ood_appkit 0.2.8 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +102 -80
- data/lib/ood_appkit/cluster_decorator.rb +53 -0
- data/lib/ood_appkit/clusters.rb +24 -0
- data/lib/ood_appkit/config_parser.rb +42 -0
- data/lib/ood_appkit/configuration.rb +4 -15
- data/lib/ood_appkit/validator.rb +25 -0
- data/lib/ood_appkit/validators/groups.rb +27 -8
- data/lib/ood_appkit/version.rb +1 -1
- data/lib/ood_appkit.rb +4 -11
- metadata +41 -9
- data/config/clusters.yml +0 -112
- data/lib/ood_appkit/cluster.rb +0 -102
- data/lib/ood_appkit/server.rb +0 -15
- data/lib/ood_appkit/servers/ganglia.rb +0 -83
- data/lib/ood_appkit/servers/moab.rb +0 -54
- data/lib/ood_appkit/servers/torque.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6fbe94cce7c92a5b9ccf234d59a65c42a25af6d
|
4
|
+
data.tar.gz: 48b20a943231ce1ddcd150d482a9c84ede36a22d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2b6601dbd55a03f526802e8c88e9104dbf43939b49fc10c09b649e5d23143d858c5b2520e6b3993f743fe33fdc394f55f0b6582304ce3d28fd45bee0e3355a0
|
7
|
+
data.tar.gz: f4052ec287e187c7c7469309c60aa7a40193538cf1b0306bedb0ac9efc7caf23fc42f1a8a1cd0824470d4a596946587f8d70682f7ad9829d4ae72ec18cc32dde
|
data/README.md
CHANGED
@@ -448,119 +448,141 @@ breadcrumbs style will resemble the `navbar-brand` style.
|
|
448
448
|
|
449
449
|
### Cluster Information
|
450
450
|
|
451
|
-
|
451
|
+
Access to a list of clusters defined by the system administrator on a given
|
452
|
+
host is done through:
|
452
453
|
|
453
454
|
```ruby
|
454
|
-
#
|
455
|
-
OodAppkit.clusters
|
456
|
-
#=>
|
457
|
-
# cluster1: <OodAppkit::Cluster ...>,
|
458
|
-
# cluster2: <OodAppkit::Cluster ...>,
|
459
|
-
# ...
|
460
|
-
# }
|
461
|
-
|
462
|
-
# Hash of all available High Performance Computing (hpc) clusters
|
463
|
-
OodAppkit.clusters.hpc
|
464
|
-
#=> {
|
465
|
-
# cluster1: <OodAppkit::Cluster ...>,
|
466
|
-
# cluster2: <OodAppkit::Cluster ...>,
|
467
|
-
# ...
|
468
|
-
# }
|
469
|
-
|
470
|
-
# Hash of all available Low Performance Computing (hpc) clusters
|
471
|
-
# NB: A low performance computing cluster expects jobs that request a single
|
472
|
-
# core and use minimal resources (e.g., a desktop for file browsing/editing,
|
473
|
-
# a web server that submits jobs to an HPC cluster, visualization software)
|
474
|
-
OodAppkit.clusters.lpc
|
475
|
-
#=> {
|
476
|
-
# cluster3: <OodAppkit::Cluster ...>,
|
477
|
-
# cluster4: <OodAppkit::Cluster ...>,
|
478
|
-
# ...
|
479
|
-
# }
|
480
|
-
```
|
455
|
+
# An enumerable list of clusters
|
456
|
+
OodAppkit.clusters
|
457
|
+
#=> #<OodAppkit::Clusters>
|
481
458
|
|
482
|
-
|
483
|
-
|
459
|
+
# Create list of cluster titles
|
460
|
+
OodAppkit.clusters.map(&:title)
|
461
|
+
#=> ["My Cluster", "Tiny Cluster", "Big Cluster"]
|
484
462
|
|
485
|
-
|
486
|
-
|
487
|
-
|
463
|
+
# Count number of clusters available
|
464
|
+
OodAppkit.clusters.count
|
465
|
+
#=> 3
|
488
466
|
|
489
|
-
# Check if
|
490
|
-
|
467
|
+
# Check if cluster called "tiny_cluster" exists
|
468
|
+
OodAppkit.clusters.include? :tiny_cluster
|
491
469
|
#=> true
|
470
|
+
```
|
492
471
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
#
|
497
|
-
|
498
|
-
|
499
|
-
# ...
|
500
|
-
# }
|
472
|
+
You can access a given cluster with id `my_cluster` by:
|
473
|
+
|
474
|
+
```ruby
|
475
|
+
# Get object describing my HPC center's `my_cluster`
|
476
|
+
OodAppkit.clusters[:my_cluster]
|
477
|
+
#=> #<OodAppkit::ClusterDecorator>
|
501
478
|
|
502
|
-
#
|
503
|
-
|
479
|
+
# or...
|
480
|
+
OodAppkit.clusters["my_cluster"]
|
481
|
+
#=> #<OodAppkit::ClusterDecorator>
|
482
|
+
|
483
|
+
# Trying to access a non-existant cluster
|
484
|
+
OodAppkit.clusters[:invalid_cluster]
|
485
|
+
#=> nil
|
504
486
|
```
|
505
487
|
|
506
|
-
|
507
|
-
|
488
|
+
A cluster object comes with some pre-defined helper methods to help you find
|
489
|
+
the cluster that meets your needs:
|
508
490
|
|
509
491
|
```ruby
|
510
|
-
#
|
511
|
-
|
492
|
+
# Get the cluster of our choosing
|
493
|
+
my_cluster = OodAppkit.clusters[:my_cluster]
|
494
|
+
|
495
|
+
# Is this cluster valid (can I the user access the servers provided by it?)
|
496
|
+
my_cluster.valid?
|
497
|
+
#=> true
|
498
|
+
|
499
|
+
# Is this cluster considered a High Performance Computing (hpc) cluster?
|
500
|
+
# NB: A low performance computing cluster expects jobs that request a single
|
501
|
+
# core and use minimal resources (e.g., a desktop for file browsing/editing,
|
502
|
+
# a web server that submits jobs to an HPC cluster, visualization software)
|
503
|
+
my_cluster.hpc_cluster?
|
504
|
+
#=> false
|
512
505
|
|
513
|
-
#
|
514
|
-
|
515
|
-
|
506
|
+
# ID of cluster object to find again in OodAppkit.clusters
|
507
|
+
my_cluster.id #=> :my_cluster
|
508
|
+
|
509
|
+
# URL of cluster
|
510
|
+
my_cluster.url #=> "https://hpc.center.edu/clusters/my_cluster"
|
511
|
+
|
512
|
+
# Check if it has a login server
|
513
|
+
my_cluster.login_server? #=> true
|
514
|
+
|
515
|
+
# Access login server object
|
516
|
+
my_cluster.login_server
|
517
|
+
#=> #<OodCluster::Servers::Ssh>
|
516
518
|
```
|
517
519
|
|
518
|
-
|
519
|
-
|
520
|
+
As this object is an `Enumerable` you can create subsets of clusters that your
|
521
|
+
app only cares for in an initializer:
|
520
522
|
|
521
523
|
```ruby
|
522
|
-
#
|
523
|
-
|
524
|
+
# I only want clusters that are valid for the currently running user
|
525
|
+
valid_clusters = OodAppkit::Clusters.new(
|
526
|
+
OodAppkit.clusters.select(&:valid?)
|
527
|
+
)
|
528
|
+
#=> #<OodAppkit::Clusters>
|
524
529
|
|
525
|
-
#
|
526
|
-
|
527
|
-
#=> "
|
530
|
+
# Create list of cluster titles from these valid clusters
|
531
|
+
valid_clusters.map(&:title)
|
532
|
+
#=> ["My Cluster"]
|
528
533
|
|
529
|
-
#
|
530
|
-
|
531
|
-
|
534
|
+
# I only want HPC clusters that I can submit solver jobs to
|
535
|
+
hpc_clusters = OodAppkit::Clusters.new(
|
536
|
+
OodAppkit.clusters.select(&:hpc_cluster?)
|
537
|
+
)
|
532
538
|
```
|
533
539
|
|
534
|
-
|
540
|
+
Depending on the type of server chosen, different helper methods will be
|
541
|
+
available to the developer. You can find more details on this at
|
542
|
+
https://github.com/OSC/ood_cluster.
|
543
|
+
|
544
|
+
#### Reservations
|
545
|
+
|
546
|
+
If reservations are supported for the chosen cluster, then a cluster object can
|
547
|
+
be used to query reservation information for the current user:
|
535
548
|
|
536
549
|
```ruby
|
537
|
-
#
|
538
|
-
|
550
|
+
# Check if reservation query object is valid (am I allowed to use it)
|
551
|
+
# NB: Definitely use this as some users may be privileged and have access to
|
552
|
+
# view ALL reservations. This can cause the app to hang.
|
553
|
+
my_cluster.valid?(:rsv_query) #=> true
|
554
|
+
|
555
|
+
# Get reservation query object
|
556
|
+
my_rsv_query = my_cluster.rsv_query
|
557
|
+
#=> #<OodReservations::Queries::TorqueMoab>
|
539
558
|
|
540
|
-
#
|
541
|
-
|
542
|
-
|
559
|
+
# Try to get reservation query object from cluster that doesn't support
|
560
|
+
# reservations
|
561
|
+
cluster_with_no_rsvs.rsv_query
|
562
|
+
#=> nil
|
543
563
|
|
544
|
-
#
|
545
|
-
|
546
|
-
#=>
|
564
|
+
# Get all reservations I have on this cluster
|
565
|
+
my_rsv_query.reservations
|
566
|
+
#=> [ #<OodReservations::Reservation>, ... ]
|
547
567
|
```
|
548
568
|
|
549
|
-
|
569
|
+
You can learn more about the reservation query object by visiting
|
570
|
+
https://github.com/OSC/ood_reservations.
|
571
|
+
|
572
|
+
#### Configuration
|
573
|
+
|
574
|
+
The list of clusters generated by OodAppkit can be modified by supplying a
|
550
575
|
different config file through the environment variable `OOD_CLUSTERS`
|
551
576
|
|
552
|
-
```
|
577
|
+
```sh
|
553
578
|
OOD_CLUSTERS="/path/to/my/config.yml"
|
554
579
|
```
|
555
580
|
|
556
|
-
|
557
|
-
|
558
|
-
```ruby
|
559
|
-
# config/initializers/ood_appkit.rb
|
581
|
+
Or a directory with aptly named configuration files (name of file is id of
|
582
|
+
cluster):
|
560
583
|
|
561
|
-
|
562
|
-
|
563
|
-
end
|
584
|
+
```sh
|
585
|
+
OOD_CLUSTERS="/path/to/configs.d"
|
564
586
|
```
|
565
587
|
|
566
588
|
## Develop
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'ood_cluster'
|
2
|
+
require 'ood_reservations'
|
3
|
+
|
4
|
+
module OodAppkit
|
5
|
+
# A decorator that adds a presentation layer to the {OodCluster::Cluster} object
|
6
|
+
class ClusterDecorator < SimpleDelegator
|
7
|
+
# The identifier used as the key in the OodAppkit clusters hash (used for
|
8
|
+
# reverse searching)
|
9
|
+
# @return [Symbol] the clusters hash key for this object
|
10
|
+
attr_reader :id
|
11
|
+
|
12
|
+
# The title used to describe this cluster to users
|
13
|
+
# @return [String] the cluster title
|
14
|
+
attr_reader :title
|
15
|
+
|
16
|
+
# The URL for this cluster that users can use to view more information
|
17
|
+
# @return [String] the cluster url
|
18
|
+
attr_reader :url
|
19
|
+
|
20
|
+
# @param cluster [OodCluster::Cluster] cluster object
|
21
|
+
# @param id [#to_sym] id used in clusters hash of OodAppkit
|
22
|
+
# @param title [#to_s] title of cluster
|
23
|
+
# @param url [#to_s] url of cluster
|
24
|
+
# @param validators [Hash{#to_sym=>Array<Validator>}] hash of validators
|
25
|
+
def initialize(cluster:, id:, title: "", url: "", validators: {}, **_)
|
26
|
+
super(cluster)
|
27
|
+
@id = id.to_sym
|
28
|
+
@title = title.to_s
|
29
|
+
@url = url.to_s
|
30
|
+
@validators = validators.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Whether the given method is valid (i.e., passes all supplied validators)
|
34
|
+
# @param method [#to_sym] method to check if valid
|
35
|
+
# @return [Boolean] whether this method is valid
|
36
|
+
def valid?(method = :cluster)
|
37
|
+
@validators.fetch(method.to_sym, []).all? { |v| v.success? }
|
38
|
+
end
|
39
|
+
|
40
|
+
# A reservation query object used to query reservations for current user
|
41
|
+
# @return [OodReservations::Query,nil] reservation query object
|
42
|
+
def rsv_query
|
43
|
+
OodReservations::Query.build(cluster: self)
|
44
|
+
end
|
45
|
+
|
46
|
+
# The comparison operator
|
47
|
+
# @param other [#to_sym] object to compare against
|
48
|
+
# @return [Boolean] whether objects are equivalent
|
49
|
+
def ==(other)
|
50
|
+
id == other.to_sym
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module OodAppkit
|
2
|
+
# An enumerable that holds a list of {ClusterDecorator} objects
|
3
|
+
class Clusters
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
# @param clusters [Array<ClusterDecorator>] list of cluster decorator objects
|
7
|
+
def initialize(clusters = [])
|
8
|
+
@clusters = clusters
|
9
|
+
end
|
10
|
+
|
11
|
+
# Find object in list from object's id
|
12
|
+
# @param id [Object] id of cluster decorator object
|
13
|
+
# @return [ClusterDecorator, nil] object if found
|
14
|
+
def [](id)
|
15
|
+
@clusters.detect { |v| v == id }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Iterate over each of the clusters
|
19
|
+
# @yield [obj] cluster decorator objects
|
20
|
+
def each(&block)
|
21
|
+
@clusters.each(&block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module OodAppkit
|
5
|
+
# Helper methods for parsing/deserializing yml configuration files
|
6
|
+
module ConfigParser
|
7
|
+
# Specific version hash in the yaml file to parse
|
8
|
+
YAML_VERSION = 'v1'
|
9
|
+
|
10
|
+
# Identifier used to distinguish class names when deserializing
|
11
|
+
CLASS_ID = 'type'
|
12
|
+
|
13
|
+
# Exception raise when unable to access config file or directory
|
14
|
+
class InvalidConfigPath < StandardError; end
|
15
|
+
|
16
|
+
# Parse/deserialize a configuration file or a set of configuration files
|
17
|
+
# @param config [#to_s] configuration file or directory
|
18
|
+
# @raise [InvalidConfigPath] if config path is inaccessible
|
19
|
+
# @return [Hash] hash of deserialized config file
|
20
|
+
def self.parse(config:)
|
21
|
+
# use 'type' to distinguish class name in yaml file
|
22
|
+
JSON.create_id = CLASS_ID
|
23
|
+
|
24
|
+
config = Pathname.new(config.to_s).expand_path
|
25
|
+
if config.file?
|
26
|
+
parse_file config
|
27
|
+
elsif config.directory?
|
28
|
+
config.children.each_with_object({}) do |f, h|
|
29
|
+
/^(.+)\.yml$/.match(f.basename.to_s) { h[$1.to_sym] = parse_file(f) }
|
30
|
+
end
|
31
|
+
else
|
32
|
+
raise InvalidConfigPath, "invalid config path: #{config}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
# Parse a single yaml file
|
38
|
+
def self.parse_file(file)
|
39
|
+
JSON.load(JSON.dump(YAML.load(File.read(file.to_s))[YAML_VERSION])).deep_symbolize_keys
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -65,22 +65,11 @@ module OodAppkit
|
|
65
65
|
self.dataroot = ENV['OOD_DATAROOT'] || ENV['RAILS_DATAROOT']
|
66
66
|
|
67
67
|
# Initialize list of available clusters
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
file: ENV['OOD_CLUSTERS'] || File.expand_path('../../../config/clusters.yml', __FILE__)
|
73
|
-
)
|
68
|
+
self.clusters = Clusters.new(
|
69
|
+
ConfigParser.parse(
|
70
|
+
config: ENV['OOD_CLUSTERS'] || Pathname.new('/etc/ood/config/clusters.d')
|
71
|
+
).map { |k, v| ClusterDecorator.new(id: k.to_sym, **v) }
|
74
72
|
)
|
75
|
-
def clusters.all
|
76
|
-
cache
|
77
|
-
end
|
78
|
-
def clusters.hpc
|
79
|
-
all.select {|k,v| v.hpc_cluster?}
|
80
|
-
end
|
81
|
-
def clusters.lpc
|
82
|
-
all.reject {|k,v| v.hpc_cluster?}
|
83
|
-
end
|
84
73
|
|
85
74
|
# Add markdown template support
|
86
75
|
self.markdown = Redcarpet::Markdown.new(
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module OodAppkit
|
2
|
+
class Validator
|
3
|
+
# Deserialize a validator object from JSON
|
4
|
+
# @param object [Hash{#to_sym=>Object}] hash used defining context
|
5
|
+
# @return [self] deserialized object
|
6
|
+
def self.json_create(object)
|
7
|
+
new object["data"].each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(**_)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Whether this validation was successful
|
14
|
+
# @return [Boolean] whether successful
|
15
|
+
def success?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
# Whether this validation was a failure
|
20
|
+
# @return [Boolean] whether failure
|
21
|
+
def failure?
|
22
|
+
!success?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -3,17 +3,36 @@ require 'ood_support'
|
|
3
3
|
module OodAppkit
|
4
4
|
module Validators
|
5
5
|
# Class used to determine if user is in valid list of groups
|
6
|
-
class Groups
|
7
|
-
# @param groups [Array
|
8
|
-
|
9
|
-
|
6
|
+
class Groups < Validator
|
7
|
+
# @param groups [Array<#to_s>] list of groups
|
8
|
+
# @param allow [Boolean] whether these groups are allowed access
|
9
|
+
def initialize(groups: [], allow: true, **kwargs)
|
10
|
+
super(kwargs)
|
11
|
+
@groups = groups.map(&:to_s)
|
12
|
+
@allow = allow
|
10
13
|
end
|
11
14
|
|
12
|
-
# Whether
|
13
|
-
# @return [Boolean] whether
|
14
|
-
def
|
15
|
-
|
15
|
+
# Whether this validation was successful
|
16
|
+
# @return [Boolean] whether successful
|
17
|
+
def success?
|
18
|
+
@allow ? in_user_groups?(@groups) : not_in_user_groups?(@groups)
|
16
19
|
end
|
20
|
+
|
21
|
+
private
|
22
|
+
# List of groups user is in
|
23
|
+
def user_groups
|
24
|
+
OodSupport::User.new.groups.map(&:to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Whether any groups match user's groups
|
28
|
+
def in_user_groups?(groups)
|
29
|
+
!(groups & user_groups).empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
# Whether groups don't correspond with any user group
|
33
|
+
def not_in_user_groups?(groups)
|
34
|
+
!in_user_groups?(groups)
|
35
|
+
end
|
17
36
|
end
|
18
37
|
end
|
19
38
|
end
|
data/lib/ood_appkit/version.rb
CHANGED
data/lib/ood_appkit.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
require 'addressable'
|
2
|
-
|
3
1
|
require 'ood_appkit/version'
|
4
2
|
require 'ood_appkit/configuration'
|
5
3
|
require 'ood_appkit/url'
|
6
4
|
require 'ood_appkit/files_rack_app'
|
7
5
|
require 'ood_appkit/markdown_template_handler'
|
8
6
|
require 'ood_appkit/log_formatter'
|
9
|
-
require 'ood_appkit/
|
10
|
-
require 'ood_appkit/
|
7
|
+
require 'ood_appkit/config_parser'
|
8
|
+
require 'ood_appkit/cluster_decorator'
|
9
|
+
require 'ood_appkit/clusters'
|
10
|
+
require 'ood_appkit/validator'
|
11
11
|
|
12
12
|
# The main namespace for OodAppkit. Provides a global configuration.
|
13
13
|
module OodAppkit
|
@@ -23,13 +23,6 @@ module OodAppkit
|
|
23
23
|
require 'ood_appkit/urls/editor'
|
24
24
|
end
|
25
25
|
|
26
|
-
# A namespace to hold all subclasses of {Server}
|
27
|
-
module Servers
|
28
|
-
require 'ood_appkit/servers/torque'
|
29
|
-
require 'ood_appkit/servers/moab'
|
30
|
-
require 'ood_appkit/servers/ganglia'
|
31
|
-
end
|
32
|
-
|
33
26
|
# A namespace for validators used to validate a cluster
|
34
27
|
module Validators
|
35
28
|
require 'ood_appkit/validators/groups'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ood_appkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Franz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -17,6 +17,9 @@ dependencies:
|
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '4.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 4.0.7
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
- - "~>"
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '4.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 4.0.7
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: ood_support
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +44,34 @@ dependencies:
|
|
38
44
|
- - "~>"
|
39
45
|
- !ruby/object:Gem::Version
|
40
46
|
version: '0.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: ood_cluster
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0.0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: ood_reservations
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0.0'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0.0'
|
41
75
|
- !ruby/object:Gem::Dependency
|
42
76
|
name: addressable
|
43
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,25 +148,23 @@ files:
|
|
114
148
|
- app/controllers/concerns/ood_appkit/wiki_page.rb
|
115
149
|
- app/controllers/ood_appkit/wiki_controller.rb
|
116
150
|
- app/views/ood_appkit/wiki/show.html.erb
|
117
|
-
- config/clusters.yml
|
118
151
|
- config/routes.rb
|
119
152
|
- lib/ood_appkit.rb
|
120
|
-
- lib/ood_appkit/
|
153
|
+
- lib/ood_appkit/cluster_decorator.rb
|
154
|
+
- lib/ood_appkit/clusters.rb
|
155
|
+
- lib/ood_appkit/config_parser.rb
|
121
156
|
- lib/ood_appkit/configuration.rb
|
122
157
|
- lib/ood_appkit/engine.rb
|
123
158
|
- lib/ood_appkit/files_rack_app.rb
|
124
159
|
- lib/ood_appkit/log_formatter.rb
|
125
160
|
- lib/ood_appkit/markdown_template_handler.rb
|
126
|
-
- lib/ood_appkit/server.rb
|
127
|
-
- lib/ood_appkit/servers/ganglia.rb
|
128
|
-
- lib/ood_appkit/servers/moab.rb
|
129
|
-
- lib/ood_appkit/servers/torque.rb
|
130
161
|
- lib/ood_appkit/url.rb
|
131
162
|
- lib/ood_appkit/urls/dashboard.rb
|
132
163
|
- lib/ood_appkit/urls/editor.rb
|
133
164
|
- lib/ood_appkit/urls/files.rb
|
134
165
|
- lib/ood_appkit/urls/public.rb
|
135
166
|
- lib/ood_appkit/urls/shell.rb
|
167
|
+
- lib/ood_appkit/validator.rb
|
136
168
|
- lib/ood_appkit/validators/groups.rb
|
137
169
|
- lib/ood_appkit/version.rb
|
138
170
|
- lib/tasks/ood_appkit_tasks.rake
|
@@ -184,7 +216,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
184
216
|
requirements:
|
185
217
|
- - ">="
|
186
218
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
219
|
+
version: 2.2.0
|
188
220
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
221
|
requirements:
|
190
222
|
- - ">="
|
data/config/clusters.yml
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
v1:
|
2
|
-
oakley:
|
3
|
-
title: 'Oakley'
|
4
|
-
servers:
|
5
|
-
login:
|
6
|
-
type: 'OodAppkit::Server'
|
7
|
-
host: 'oakley.osc.edu'
|
8
|
-
resource_mgr:
|
9
|
-
type: 'OodAppkit::Servers::Torque'
|
10
|
-
host: 'oak-batch.osc.edu'
|
11
|
-
prefix: '/usr/local/torque/5.1.1-1_fba25d92'
|
12
|
-
version: '5.1.1'
|
13
|
-
scheduler:
|
14
|
-
type: 'OodAppkit::Servers::Moab'
|
15
|
-
host: 'oak-batch.osc.edu'
|
16
|
-
prefix: '/usr/local/moab/8.1.1.2-2015080516-eb28ad0-el6'
|
17
|
-
version: '8.1.1'
|
18
|
-
moabhomedir: '/var/spool/batch/moab'
|
19
|
-
ganglia:
|
20
|
-
type: 'OodAppkit::Servers::Ganglia'
|
21
|
-
host: 'cts05.osc.edu'
|
22
|
-
scheme: 'https://'
|
23
|
-
segments:
|
24
|
-
- 'gweb'
|
25
|
-
- 'graph.php'
|
26
|
-
req_query:
|
27
|
-
c: 'Oakley nodes'
|
28
|
-
opt_query:
|
29
|
-
h: '%{h}.ten.osc.edu'
|
30
|
-
version: '3'
|
31
|
-
ruby:
|
32
|
-
title: 'Ruby'
|
33
|
-
validators:
|
34
|
-
in_valid_groups:
|
35
|
-
type: 'OodAppkit::Validators::Groups'
|
36
|
-
groups:
|
37
|
-
- 'ruby'
|
38
|
-
servers:
|
39
|
-
login:
|
40
|
-
type: 'OodAppkit::Server'
|
41
|
-
host: 'ruby.osc.edu'
|
42
|
-
resource_mgr:
|
43
|
-
type: 'OodAppkit::Servers::Torque'
|
44
|
-
host: 'ruby-batch.osc.edu'
|
45
|
-
prefix: '/usr/local/torque/5.1.1-1_fba25d92'
|
46
|
-
version: '5.1.1'
|
47
|
-
scheduler:
|
48
|
-
type: 'OodAppkit::Servers::Moab'
|
49
|
-
host: 'ruby-batch.osc.edu'
|
50
|
-
prefix: '/usr/local/moab/8.1.1.2-2015080516-eb28ad0-el6'
|
51
|
-
version: '8.1.1'
|
52
|
-
moabhomedir: '/var/spool/batch/moab'
|
53
|
-
ganglia:
|
54
|
-
type: 'OodAppkit::Servers::Ganglia'
|
55
|
-
host: 'cts05.osc.edu'
|
56
|
-
scheme: 'https://'
|
57
|
-
segments:
|
58
|
-
- 'gweb'
|
59
|
-
- 'graph.php'
|
60
|
-
req_query:
|
61
|
-
c: 'Ruby'
|
62
|
-
opt_query:
|
63
|
-
h: '%{h}.ten.osc.edu'
|
64
|
-
version: '3'
|
65
|
-
owens:
|
66
|
-
title: 'Owens'
|
67
|
-
validators:
|
68
|
-
in_valid_groups:
|
69
|
-
type: 'OodAppkit::Validators::Groups'
|
70
|
-
groups:
|
71
|
-
- 'owens'
|
72
|
-
- 'oscsys'
|
73
|
-
- 'hpcsys'
|
74
|
-
- 'sysp'
|
75
|
-
- 'appl'
|
76
|
-
- 'oscgen'
|
77
|
-
- 'hpcsoft'
|
78
|
-
- 'oscadm'
|
79
|
-
servers:
|
80
|
-
login:
|
81
|
-
type: 'OodAppkit::Server'
|
82
|
-
host: 'owens.hpc.osc.edu'
|
83
|
-
ganglia:
|
84
|
-
type: 'OodAppkit::Servers::Ganglia'
|
85
|
-
host: 'cts05.osc.edu'
|
86
|
-
scheme: 'https://'
|
87
|
-
segments:
|
88
|
-
- 'gweb'
|
89
|
-
- 'graph.php'
|
90
|
-
req_query:
|
91
|
-
c: 'Owens'
|
92
|
-
opt_query:
|
93
|
-
h: '%{h}.ten.osc.edu'
|
94
|
-
version: '3'
|
95
|
-
quick:
|
96
|
-
title: 'Quick'
|
97
|
-
hpc_cluster: false
|
98
|
-
servers:
|
99
|
-
resource_mgr:
|
100
|
-
type: 'OodAppkit::Servers::Torque'
|
101
|
-
host: 'quick-batch.osc.edu'
|
102
|
-
prefix: '/usr/local/torque/5.1.1-1_fba25d92'
|
103
|
-
version: '5.1.1'
|
104
|
-
sub_cluster:
|
105
|
-
- 'ruby'
|
106
|
-
- 'oakley'
|
107
|
-
scheduler:
|
108
|
-
type: 'OodAppkit::Servers::Moab'
|
109
|
-
host: 'quick-batch.osc.edu'
|
110
|
-
prefix: '/usr/local/moab/8.1.1.2-2015080516-eb28ad0-el6'
|
111
|
-
version: '8.1.1'
|
112
|
-
moabhomedir: '/var/spool/batch/moab'
|
data/lib/ood_appkit/cluster.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module OodAppkit
|
4
|
-
# An object that describes a given cluster of nodes used by an HPC center
|
5
|
-
class Cluster
|
6
|
-
# YAML configuration version
|
7
|
-
VERSION = :v1
|
8
|
-
|
9
|
-
# Unique ID of the cluster
|
10
|
-
# @return [Symbol] id of cluster
|
11
|
-
attr_reader :id
|
12
|
-
|
13
|
-
# Title of the cluster
|
14
|
-
# @return [String] title of cluster
|
15
|
-
attr_reader :title
|
16
|
-
|
17
|
-
# Hash of validators this cluster validates against
|
18
|
-
# @return [Hash<#valid?>] hash of validators
|
19
|
-
attr_reader :validators
|
20
|
-
|
21
|
-
# Hash of servers this cluster supports
|
22
|
-
# @return [Hash<Server>] hash of servers
|
23
|
-
attr_reader :servers
|
24
|
-
|
25
|
-
# A list of accessible clusters for the currently running user
|
26
|
-
# @param file [String] yaml file with cluster configurations
|
27
|
-
# @param force [Boolean] whether we force invalid clusters to be included as well
|
28
|
-
# @return [Hash<Cluster>] list of clusters user has access to
|
29
|
-
def self.all(file: File.expand_path('../../../config/clusters.yml', __FILE__), force: false)
|
30
|
-
parse_config(file).each_with_object({}) do |(k, v), h|
|
31
|
-
c = Cluster.new v.merge(id: k)
|
32
|
-
h[k] = c if c.valid? || force
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# @param id [Symbol] id of cluster
|
37
|
-
# @param title [String] title of cluster
|
38
|
-
# @param validators [Hash] hash of validations that describe the validators
|
39
|
-
# @param servers [Hash] hash of servers with corresponding server info
|
40
|
-
# @param hpc_cluster [Boolean] whether this is an hpc-style cluster
|
41
|
-
def initialize(id:, title:, validators: {}, servers: {}, hpc_cluster: true)
|
42
|
-
# Set id & title of cluster
|
43
|
-
@id = id
|
44
|
-
@title = title
|
45
|
-
|
46
|
-
# Generate hash of validations
|
47
|
-
@validators = validators.each_with_object({}) do |(k, v), h|
|
48
|
-
h[k] = v[:type].constantize.new(v)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Generate hash of servers
|
52
|
-
@servers = servers.each_with_object({}) do |(k, v), h|
|
53
|
-
h[k] = v[:type].constantize.new(v)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Is this an hpc-style cluster?
|
57
|
-
@hpc_cluster = hpc_cluster
|
58
|
-
end
|
59
|
-
|
60
|
-
# Whether this is a valid cluster
|
61
|
-
# @example Whether I have access to this cluster
|
62
|
-
# my_cluster.valid?
|
63
|
-
# #=> true
|
64
|
-
# @return [Boolean] whether user has access to this cluster
|
65
|
-
def valid?
|
66
|
-
!@validators.any? {|name, validator| !validator.valid?}
|
67
|
-
end
|
68
|
-
|
69
|
-
# Whether this is an hpc-style cluster (i.e., meant for heavy computation)
|
70
|
-
# @return [Boolean] whether this an hpc-style cluster
|
71
|
-
def hpc_cluster?
|
72
|
-
@hpc_cluster
|
73
|
-
end
|
74
|
-
|
75
|
-
# Grab object from {@servers} hash or check if it exists
|
76
|
-
# @param method_name the method name called
|
77
|
-
# @param arguments the arguments to the call
|
78
|
-
# @param block an optional block for the call
|
79
|
-
def method_missing(method_name, *arguments, &block)
|
80
|
-
if /^(.+)_server$/ =~ method_name.to_s
|
81
|
-
@servers.fetch($1.to_sym, nil)
|
82
|
-
elsif /^(.+)_server\?$/ =~ method_name.to_s
|
83
|
-
@servers.has_key? $1.to_sym
|
84
|
-
else
|
85
|
-
super
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# Check if method ends with custom *_server or *_server?
|
90
|
-
# @param method_name the method name to check
|
91
|
-
# @return [Boolean]
|
92
|
-
def respond_to_missing?(method_name, include_private = false)
|
93
|
-
method_name.to_s.end_with?('_server', '_server?') || super
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
# Parse the config file
|
98
|
-
def self.parse_config(file)
|
99
|
-
YAML.load(File.read(file)).deep_symbolize_keys.fetch(VERSION, {})
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
data/lib/ood_appkit/server.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
module OodAppkit
|
2
|
-
# An object that describes a server hosted by a given cluster
|
3
|
-
class Server
|
4
|
-
# The host information for this server object
|
5
|
-
# @example Host information for login node
|
6
|
-
# "my_server.host" #=> "oakley.osc.edu"
|
7
|
-
# @return [String] the host for this server
|
8
|
-
attr_reader :host
|
9
|
-
|
10
|
-
# @param host [String] host info
|
11
|
-
def initialize(host:, **_)
|
12
|
-
@host = host
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
module OodAppkit
|
2
|
-
module Servers
|
3
|
-
# This defines a Ganglia server and defining parameters
|
4
|
-
class Ganglia < Server
|
5
|
-
# Template used to describe URI
|
6
|
-
# @see https://www.rfc-editor.org/rfc/rfc6570.txt RFC describing template format
|
7
|
-
TEMPLATE = '{+scheme}{host}{/segments*}{?query*}'
|
8
|
-
|
9
|
-
# The scheme of the URI
|
10
|
-
# @example Scheme of SSL protocol
|
11
|
-
# "my_ganglia.scheme" #=> "https://"
|
12
|
-
# @return [String] scheme of uri
|
13
|
-
attr_reader :scheme
|
14
|
-
|
15
|
-
# The segments used to describe the path of the URI
|
16
|
-
# @example Segments for URI with path "/ganglia/gweb.php"
|
17
|
-
# "my_ganglia.segments"
|
18
|
-
# #=> ["ganglia", "gweb.php"]
|
19
|
-
# @return [Array<String>] segments of uri
|
20
|
-
attr_reader :segments
|
21
|
-
|
22
|
-
# The required query values of the URI
|
23
|
-
# @example Required cluster query value
|
24
|
-
# "my_ganglia.req_query"
|
25
|
-
# #=> {c: "MyCluster"}
|
26
|
-
# @return [Hash] required query values of uri
|
27
|
-
attr_reader :req_query
|
28
|
-
|
29
|
-
# Optional query values of the URI, these query values are
|
30
|
-
# only defined if specified
|
31
|
-
# NB: All optional values will be evaluated for string interpolations
|
32
|
-
# @example Optional host query value
|
33
|
-
# "my_ganglia.opt_query"
|
34
|
-
# #=> {h: "%{h}.ten.osc.edu"}
|
35
|
-
# @return [Hash] optional query values of uri
|
36
|
-
attr_reader :opt_query
|
37
|
-
|
38
|
-
# The version of this software
|
39
|
-
# @return [String] version of software
|
40
|
-
attr_reader :version
|
41
|
-
|
42
|
-
# @param scheme [String] the scheme used for URI
|
43
|
-
# @param segments [Array<String>] the segments used to construct path of URI
|
44
|
-
# @param req_query [Hash] hash of required query values used for URI
|
45
|
-
# @param opt_query [Hash] hash of optional query values if they exist
|
46
|
-
# @param version [String] version of server software
|
47
|
-
def initialize(scheme:, segments: [], req_query: {}, opt_query: {}, version:, **kwargs)
|
48
|
-
super(kwargs)
|
49
|
-
|
50
|
-
# uri
|
51
|
-
@scheme = scheme
|
52
|
-
@segments = segments
|
53
|
-
@req_query = req_query
|
54
|
-
@opt_query = opt_query
|
55
|
-
|
56
|
-
# version
|
57
|
-
@version = version
|
58
|
-
end
|
59
|
-
|
60
|
-
# The URI used to access information about given cluster
|
61
|
-
# @param query [Hash] user specified query hash
|
62
|
-
# @return [Addressable] the uri for ganglia server
|
63
|
-
def uri(query: {})
|
64
|
-
Addressable::Template.new(TEMPLATE).expand({
|
65
|
-
scheme: scheme,
|
66
|
-
host: host,
|
67
|
-
segments: segments,
|
68
|
-
query: query_hash(query)
|
69
|
-
})
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
# The full hash of query values used to construct URI
|
74
|
-
def query_hash(query)
|
75
|
-
req_query.merge(
|
76
|
-
query.each_with_object({}) do |(k, v), h|
|
77
|
-
h[k] = opt_query.has_key?(k) ? (opt_query[k] % req_query.merge(query)) : v
|
78
|
-
end
|
79
|
-
)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
module OodAppkit
|
2
|
-
module Servers
|
3
|
-
# This defines a Moab server / client software installation
|
4
|
-
class Moab < Server
|
5
|
-
# The path to the installation location for this software
|
6
|
-
# @return [Pathname] the path to software installation location
|
7
|
-
attr_reader :prefix
|
8
|
-
|
9
|
-
# The version of this software
|
10
|
-
# @return [String] version of software
|
11
|
-
attr_reader :version
|
12
|
-
|
13
|
-
# The required Moab environment variable
|
14
|
-
# @return [Pathname] require moab env var
|
15
|
-
attr_reader :moabhomedir
|
16
|
-
|
17
|
-
# @param prefix [String] installation path of client software
|
18
|
-
# @param version [String] version of client software
|
19
|
-
# @param moabhomedir [String] required moab env var
|
20
|
-
def initialize(prefix:, version:, moabhomedir:, **kwargs)
|
21
|
-
super(kwargs)
|
22
|
-
|
23
|
-
# installation path
|
24
|
-
@prefix = Pathname.new prefix
|
25
|
-
raise ArgumentError, "prefix path doesn't exist (#{@prefix})" unless @prefix.exist?
|
26
|
-
raise ArgumentError, "prefix not valid directory (#{@prefix})" unless @prefix.directory?
|
27
|
-
|
28
|
-
# version number
|
29
|
-
@version = version
|
30
|
-
|
31
|
-
# required moab env var
|
32
|
-
@moabhomedir = Pathname.new moabhomedir
|
33
|
-
raise ArgumentError, "moabhomedir path doesn't exist (#{@moabhomedir})" unless @moabhomedir.exist?
|
34
|
-
raise ArgumentError, "moabhomedir not valid directory (#{@moabhomedir})" unless @moabhomedir.directory?
|
35
|
-
end
|
36
|
-
|
37
|
-
# The path to Torque software library
|
38
|
-
# @example Locally installed Torque v5.1.1
|
39
|
-
# "my_software.lib" #=> "/usr/local/torque/5.1.1/lib"
|
40
|
-
# @return [Pathname] path to libraries
|
41
|
-
def lib
|
42
|
-
prefix.join('lib')
|
43
|
-
end
|
44
|
-
|
45
|
-
# The path to Torque software binaries
|
46
|
-
# @example Locally installed Torque v5.1.1
|
47
|
-
# "my_software.lib" #=> "/usr/local/torque/5.1.1/bin"
|
48
|
-
# @return [Pathname] path to binaries
|
49
|
-
def bin
|
50
|
-
prefix.join('bin')
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module OodAppkit
|
2
|
-
module Servers
|
3
|
-
# This defines a Torque server / client software installation
|
4
|
-
class Torque < Server
|
5
|
-
# The path to the installation location for this software
|
6
|
-
# @return [Pathname] the path to software installation location
|
7
|
-
attr_reader :prefix
|
8
|
-
|
9
|
-
# The version of this software
|
10
|
-
# @return [String] version of software
|
11
|
-
attr_reader :version
|
12
|
-
|
13
|
-
# @param prefix [String] installation path of client software
|
14
|
-
# @param version [String] version of client software
|
15
|
-
def initialize(prefix:, version:, **kwargs)
|
16
|
-
super(kwargs)
|
17
|
-
|
18
|
-
# installation path
|
19
|
-
@prefix = Pathname.new prefix
|
20
|
-
raise ArgumentError, "prefix path doesn't exist (#{@prefix})" unless @prefix.exist?
|
21
|
-
raise ArgumentError, "prefix not valid directory (#{@prefix})" unless @prefix.directory?
|
22
|
-
|
23
|
-
# version number
|
24
|
-
@version = version
|
25
|
-
end
|
26
|
-
|
27
|
-
# The path to Torque software library
|
28
|
-
# @example Locally installed Torque v5.1.1
|
29
|
-
# "my_software.lib" #=> "/usr/local/torque/5.1.1/lib"
|
30
|
-
# @return [Pathname] path to libraries
|
31
|
-
def lib
|
32
|
-
prefix.join('lib')
|
33
|
-
end
|
34
|
-
|
35
|
-
# The path to Torque software binaries
|
36
|
-
# @example Locally installed Torque v5.1.1
|
37
|
-
# "my_software.lib" #=> "/usr/local/torque/5.1.1/bin"
|
38
|
-
# @return [Pathname] path to binaries
|
39
|
-
def bin
|
40
|
-
prefix.join('bin')
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|