xp5k 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MTY5MDQ3MTllYzcxZjVmZGQyMjcxYzBhNzdiNmQ2MTJhNjQ0YjA5ZQ==
5
- data.tar.gz: !binary |-
6
- MWQ2ZjBkZWU3MjI0OTMxZDUwOGRjYjViNjlkYTY4NjQ2ZDUwMTk1OA==
2
+ SHA1:
3
+ metadata.gz: 64a41367917d4c9b4445f795f9d71eb1a092b901
4
+ data.tar.gz: 26ea5183d5e2e675bccdb938443d2e464efbeda6
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NDkwMDgwOTlkN2QzYWYxYjYxNzFkZTJhMWJhYjQ5M2M2Mjk3OGU1YTU3NjAz
10
- MzlmMTMzNzMxNmNlZjJlMGVkNzM3MzA0NGQyY2QxYTcwNTJmY2ZmZjQ1N2Ez
11
- YzU0NGM2Nzc2YzA5YzBjNTI0ZDg5Yzc0MDBiOWNkZGFkZGQwYmI=
12
- data.tar.gz: !binary |-
13
- OTMzOWE0N2I5MTZhMmYzNDE5YzFiMTllNWJmMzA1YWRiM2I3YjQ1ZmFiOTI3
14
- NjUwMDIzZTkzODQ4YzY0ODQwNWNkODM1MzQxY2NmMzQxMDNhZTRiMmM5NjVl
15
- NGE3MDNiZmI4MDdiNDUzNzg0Y2Q5NDFiMmQ2OWQ4MzQ2ZjY3YzI=
6
+ metadata.gz: a4e3e3c59d52bf281a1e0c8a55f328c5e7ecc4fd4791d63aff1e5a099255c46f11fbdb2267861ccde607a5ea7467d0d55de1d37d542c592ecb0822e34214903d
7
+ data.tar.gz: 84348914d0e589ef7859de46a980806b98a0067fcef293e5290aa8f8d67b6bb7c53b7b6d8f29e62235bf7c3d449c210bef4e08deda64b04a8409ef93daa4bf5b
data/Gemfile.lock CHANGED
@@ -1,38 +1,79 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- xp5k (0.0.1)
5
- json (>= 1.5.1)
6
- restfully (~> 0.6)
7
- term-ansicolor (>= 1.0.7)
4
+ xp5k (0.0.11)
5
+ json (~> 1.8)
6
+ net-ssh-multi (~> 1.2)
7
+ rest-client (~> 1.8)
8
+ restfully (~> 1.1)
9
+ term-ansicolor (~> 1.3)
8
10
 
9
11
  GEM
10
12
  remote: http://rubygems.org/
11
13
  specs:
12
- addressable (2.3.2)
13
- backports (2.6.5)
14
- json (1.7.5)
15
- mime-types (1.19)
16
- rack (1.4.1)
17
- rack-cache (1.2)
14
+ addressable (2.3.8)
15
+ backports (3.6.7)
16
+ bond (0.4.3)
17
+ domain_name (0.5.25)
18
+ unf (>= 0.0.5, < 1.0.0)
19
+ http-cookie (1.0.2)
20
+ domain_name (~> 0.5)
21
+ json (1.8.3)
22
+ mime-types (2.6.2)
23
+ net-ssh (3.0.1)
24
+ net-ssh-gateway (1.2.0)
25
+ net-ssh (>= 2.6.5)
26
+ net-ssh-multi (1.2.1)
27
+ net-ssh (>= 2.6.5)
28
+ net-ssh-gateway (>= 1.2.0)
29
+ netrc (0.11.0)
30
+ rack (1.6.4)
31
+ rack-cache (1.5.1)
18
32
  rack (>= 0.4)
19
- rest-client (1.6.7)
20
- mime-types (>= 1.16)
21
- rest-client-components (1.2.0)
33
+ rb-readline (0.5.3)
34
+ rest-client (1.8.0)
35
+ http-cookie (>= 1.0.2, < 2.0)
36
+ mime-types (>= 1.16, < 3.0)
37
+ netrc (~> 0.7)
38
+ rest-client-components (1.4.0)
22
39
  rack (>= 1.0.1)
23
- rest-client (>= 1.6.0, < 1.7.0)
24
- restfully (0.8.8)
40
+ rest-client (>= 1.6.0)
41
+ restfully (1.1.1)
25
42
  addressable
26
43
  backports
27
44
  json (~> 1.5)
28
45
  rack-cache
46
+ rb-readline
29
47
  rest-client (~> 1.6)
30
48
  rest-client-components
31
- term-ansicolor (1.0.7)
49
+ ripl (= 0.6.1)
50
+ ripl-color_streams
51
+ ripl-multi_line
52
+ ripl-play (~> 0.2.1)
53
+ ripl-short_errors
54
+ ripl (0.6.1)
55
+ bond (~> 0.4.0)
56
+ ripl-color_streams (0.1.2)
57
+ ripl (>= 0.2.8)
58
+ ripl-multi_line (0.3.1)
59
+ ripl (>= 0.3.6)
60
+ ripl-play (0.2.1)
61
+ ripl (>= 0.3.0)
62
+ ripl-short_errors (0.1.0)
63
+ ripl (>= 0.2.8)
64
+ term-ansicolor (1.3.2)
65
+ tins (~> 1.0)
66
+ tins (1.6.0)
67
+ unf (0.1.4)
68
+ unf_ext
69
+ unf_ext (0.0.7.1)
32
70
 
33
71
  PLATFORMS
34
72
  ruby
35
73
 
36
74
  DEPENDENCIES
37
- bundler (>= 1.0.0)
75
+ bundler (~> 1.10)
38
76
  xp5k!
77
+
78
+ BUNDLED WITH
79
+ 1.10.6
data/README.md CHANGED
@@ -1,18 +1,18 @@
1
1
  #### Table of Contents
2
2
 
3
- 1. [Getting started](#Getting started)
4
- * [Gemfile](#Gemfile)
5
- * [Restfully](#Restfully)
6
- * [Ssh config](#Ssh config)
7
- 2. [Samples](#Samples)
8
- * [Hello date](#Hello date)
9
- * [Xp5k Roles](#Xp5k Roles)
10
- * [Nested roels](#Nested roles)
11
- * [Patterns](#Patterns)
12
- * [Get the deployed nodes](#Get the deployed nodes)
13
- * [Automatic redeployment](#Automatic redeployment)
14
- * [Vlan support](#Vlan support)
15
- * [Non deploy jobs](#Non deploy jobs)
3
+ 1. [Getting started](#getting-started)
4
+ * [Gemfile](#gemfile)
5
+ * [Restfully](#restfully)
6
+ * [Ssh config](#ssh-config)
7
+ 2. [Samples](#samples)
8
+ * [Hello date](#hello-date)
9
+ * [Xp5k Roles](#xp5k-roles)
10
+ * [Nested roels](#nested-roles)
11
+ * [Patterns](#patterns)
12
+ * [Get the deployed nodes](#get-the-deployed-nodes)
13
+ * [Automatic redeployment](#automatic-redeployment)
14
+ * [Vlan support](#vlan-support)
15
+ * [Non deploy jobs](#non-deploy-jobs)
16
16
 
17
17
  # Getting started
18
18
 
@@ -83,9 +83,9 @@ set :g5k_user, "msimonin"
83
83
  # gateway
84
84
  set :gateway, "#{g5k_user}@access.grid5000.fr"
85
85
  # These keys will used to access the gateway and nodes
86
- ssh_options[:keys]= [File.join(ENV["HOME"], ".ssh", "id_rsa"), File.join(ENV["HOME"], ".ssh", "id_rsa_insideg5k")]
86
+ ssh_options[:keys]= [File.join(ENV["HOME"], ".ssh", "id_rsa")]
87
87
  # # This key will be installed on nodes
88
- set :ssh_public, File.join(ENV["HOME"], ".ssh", "id_rsa_insideg5k.pub")
88
+ set :ssh_public, File.join(ENV["HOME"], ".ssh", "id_rsa.pub")
89
89
 
90
90
  XP5K::Config.load
91
91
 
@@ -191,11 +191,11 @@ role :server do
191
191
  @myxp.role_with_name('server').servers
192
192
  end
193
193
 
194
- role :server do
194
+ role :frontend do
195
195
  @myxp.role_with_name('frontend').servers
196
196
  end
197
197
 
198
- role :server do
198
+ role :clients do
199
199
  @myxp.role_with_name('clients').servers
200
200
  end
201
201
  ```
@@ -223,7 +223,7 @@ You can also define nested roles (only 1 level) :
223
223
 
224
224
  You can select nodes matching a pattern (`String` or `Regexp`) :
225
225
 
226
- ```Ruby
226
+ ```ruby
227
227
  roles = []
228
228
  scenario['clusters'].each do |cluster|
229
229
  roles << XP5K::Role.new({
@@ -295,14 +295,12 @@ You can control this behaviour passing special keys in the deployment hash.
295
295
 
296
296
  ## Non deploy jobs
297
297
 
298
- Here we fill the ```types``` field with ```allow_classic_ssh```.
298
+ Here we fill the ```types``` field with ```allow_classic_ssh```.
299
299
 
300
300
  ```ruby
301
301
  @myxp.define_job({
302
302
  :resources => ["nodes=1, walltime=1"],
303
303
  :site => "rennes",
304
- :retry => true,
305
- :goal => "100%",
306
304
  :types => ["allow_classic_ssh"],
307
305
  :name => "init" ,
308
306
  :command => "sleep 86400"
@@ -0,0 +1,163 @@
1
+ require 'xp5k/role'
2
+ require 'net/ssh/multi'
3
+ require 'timeout'
4
+ require 'thread'
5
+
6
+ module XP5K
7
+ module Rake
8
+ module DSL
9
+
10
+ private
11
+
12
+ def role(*args, &block)
13
+ hosts = []
14
+ procblock = nil
15
+ if block_given?
16
+ raise 'Arguments not allowed with block' unless args[1].nil?
17
+ procblock = block
18
+ else
19
+ case args[1]
20
+ when String
21
+ hosts = [args[1]]
22
+ when Array
23
+ hosts = args[1]
24
+ else
25
+ raise "Role <#{args.first}> argument must be a String or an Array"
26
+ end
27
+ end
28
+
29
+ XP5K::Role.new(name: args.first, size: hosts.length, servers: hosts, proc: procblock).add
30
+
31
+ end
32
+
33
+
34
+ def roles(*args)
35
+ hosts = []
36
+ args.each do |rolename|
37
+ hosts << XP5K::Role.findByName(rolename).servers
38
+ end
39
+ hosts.flatten!
40
+ end
41
+
42
+ #
43
+ def on(hosts, *args, &block)
44
+
45
+ logs = Hash.new { |h,k| h[k] = '' }
46
+ errors = Hash.new { |h,k| h[k] = '' }
47
+ ssh_session = {}
48
+ current_server = ""
49
+ all_connected = false
50
+ failed_servers = []
51
+ hosts = [hosts] if hosts.class == String
52
+
53
+ XP5K::Config[:user] ||= ENV["USER"]
54
+ XP5K::Config[:gateway] ||= XP5K::Config[:user] + "@access.grid5000.fr"
55
+
56
+ commands = (args.last.class == String or args.last.class == Array) ? (args.last.class == String ? [args.pop] : args.pop ) : []
57
+ options = args.last.class == Hash ? args.pop : {}
58
+ options[:user] ||= 'root'
59
+
60
+ if block_given?
61
+ case result = yield
62
+ when String
63
+ commands << result
64
+ when Array
65
+ commands.push(result).flatten!
66
+ else
67
+ raise "<on> block must return String or Array"
68
+ end
69
+ end
70
+
71
+ until all_connected
72
+ failed = false
73
+ gateway_options = {}
74
+ gateway_options[:config] == XP5K::Config[:ssh_config] ? true : XP5K::Config[:ssh_config]
75
+ gateway_user, gateway_host = XP5K::Config[:gateway].match(/^(?:([^;,:=]+)@|)(.*?)$/)[1,2]
76
+ gateway = Net::SSH::Gateway.new(gateway_host, gateway_user)
77
+ workq = Queue.new
78
+ hosts.each{ |host| workq << host }
79
+ workers = (0...10).map do
80
+ Thread.new do
81
+ begin
82
+ while host = workq.pop(true)
83
+ begin
84
+ timeout(5) do
85
+ ssh_session[host] = gateway.ssh(host, options[:user])
86
+ puts "Connected to #{host}..."
87
+ end
88
+ rescue Timeout::Error, Net::SSH::Disconnect, Exception => e
89
+ puts "Removing #{host} (#{e.message})..."
90
+ hosts.delete host
91
+ failed_servers << host
92
+ failed = true
93
+ end
94
+ end
95
+
96
+ rescue ThreadError
97
+ end
98
+
99
+ end
100
+ end; "ok"
101
+ workers.map(&:join); "ok"
102
+
103
+ all_connected = true if !failed
104
+ end
105
+
106
+ workq = Queue.new
107
+ hosts.each{ |host| workq << host }
108
+ workers = (0...10).map do
109
+ Thread.new do
110
+ begin
111
+ while host = workq.pop(true)
112
+ begin
113
+ commands.each do |command|
114
+ puts "[command][#{host}] #{command}"
115
+ ssh_session[host].exec!(command) do |channel, stream, data|
116
+ logs[host] << data
117
+ errors[host] << data if stream == :err
118
+ puts "[#{stream}][#{host}] #{data}" if data.chomp != ""
119
+ end
120
+ end
121
+ rescue Exception => e
122
+ puts "[#{host}] " + e.message
123
+ end
124
+ end
125
+ rescue ThreadError
126
+ end
127
+ end
128
+ end; "ok"
129
+ workers.map(&:join); "ok"
130
+
131
+ # Print the result sorting by hostname
132
+ errors.sort.each do |error|
133
+ puts "---- stderr on #{error.first} #{"-" * (get_width - error.first.length - 16)} "
134
+ puts "#{error[1]}"
135
+ end
136
+ logs.sort.each do |key, value|
137
+ puts "---- #{key} #{"-" * (get_width - key.length - 6)}"
138
+ puts value
139
+ end
140
+ puts "Servers unreachable : #{failed_servers.inspect}" if !failed_servers.empty?
141
+
142
+ # Clean all ssh connections
143
+ puts "Closing ssh connections..."
144
+ hosts.each do |host|
145
+ ssh_session[host].close
146
+ gateway.close ssh_session[host].transport.port
147
+ end
148
+ gateway.shutdown!
149
+
150
+ end
151
+
152
+ def run(command)
153
+
154
+ end
155
+
156
+ def get_width
157
+ result = `tput cols`
158
+ result.to_i
159
+ end
160
+
161
+ end
162
+ end
163
+ end
data/lib/xp5k/rake.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'xp5k/rake/dsl'
2
+
3
+ self.extend XP5K::Rake::DSL
data/lib/xp5k/role.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  class XP5K::Role
2
2
 
3
- attr_accessor :name, :size, :desc, :servers, :jobid, :inner, :pattern
3
+ attr_accessor :name, :size, :desc, :servers, :jobid, :inner, :pattern, :proc
4
4
 
5
5
  @@roles = []
6
6
 
@@ -9,6 +9,7 @@ class XP5K::Role
9
9
  @inner = false
10
10
  @servers = []
11
11
  @desc = ""
12
+ @proc = nil
12
13
 
13
14
  # Required parameters
14
15
  %w{ name size }.each do |param|
@@ -20,11 +21,36 @@ class XP5K::Role
20
21
  end
21
22
 
22
23
  # Optional parameters
23
- %w{ desc servers inner pattern }.each do |param|
24
+ %w{ desc servers inner pattern proc }.each do |param|
24
25
  instance_variable_set("@#{param}", options[param.to_sym]) if options[param.to_sym]
25
26
  end
26
27
  end
27
28
 
29
+ def add
30
+ @@roles << self
31
+ end
32
+
33
+ def servers
34
+ if self.proc.class == Proc
35
+ self.callproc
36
+ end
37
+ @servers
38
+ end
39
+
40
+ def callproc
41
+ case result = self.proc.call
42
+ when String
43
+ hosts = [result]
44
+ when Array
45
+ hosts = result
46
+ else
47
+ raise "Role <#{args.first}> block must return String or Array"
48
+ end
49
+ self.size = hosts.length
50
+ self.servers = hosts
51
+ end
52
+
53
+
28
54
  def self.create_roles(job, job_definition)
29
55
  # Definition will return list of roles
30
56
  roles = []
@@ -81,6 +107,10 @@ class XP5K::Role
81
107
  @@roles
82
108
  end
83
109
 
110
+ def self.listnames()
111
+ @@roles.map { |role| role.name }
112
+ end
113
+
84
114
  def self.findByName(name)
85
115
  roles = @@roles.select { |x| x.name == name }
86
116
  roles.empty? ? nil : roles.first
data/lib/xp5k/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module XP5K
2
- VERSION='0.0.10'
2
+ VERSION='0.0.11'
3
3
  end
data/xp5k.gemspec CHANGED
@@ -10,17 +10,18 @@ Gem::Specification.new do |s|
10
10
  s.email = ['pascal.morillon@irisa.fr']
11
11
  s.license = 'MIT'
12
12
  s.homepage = 'https://github.com/pmorillon/xp5k'
13
- s.summary = %q{A small Grid'5000 helper to submit jobs and deploy environments via REST API}
13
+ s.summary = %q{A small Grid'5000 helper}
14
14
  s.description = %q{A small Grid'5000 helper to submit jobs and deploy environments via REST API}
15
15
 
16
16
  s.required_rubygems_version = '>= 1.3.6'
17
17
 
18
- s.add_dependency 'rest-client', '1.6.8' # SSL problems with newer version
19
- s.add_dependency 'restfully', '>1.0.0'
20
- s.add_dependency 'term-ansicolor', '>= 1.0.7'
21
- s.add_dependency 'json', '>= 1.5.1'
18
+ s.add_dependency 'rest-client', '~> 1.8' # SSL problems with newer version
19
+ s.add_dependency 'restfully', '~>1.1'
20
+ s.add_dependency 'term-ansicolor', '~> 1.3'
21
+ s.add_dependency 'json', '~> 1.8'
22
+ s.add_dependency 'net-ssh-multi', '~> 1.2'
22
23
 
23
- s.add_development_dependency 'bundler', '>= 1.0.0'
24
+ s.add_development_dependency 'bundler', '~> 1.10'
24
25
 
25
26
  s.files = `git ls-files`.split("\n")
26
27
  s.require_paths = ['lib']
metadata CHANGED
@@ -1,85 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xp5k
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pascal Morillon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-03 00:00:00.000000000 Z
11
+ date: 2015-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.6.8
19
+ version: '1.8'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.6.8
26
+ version: '1.8'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: restfully
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ! '>'
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.0.0
33
+ version: '1.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ! '>'
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.0.0
40
+ version: '1.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: term-ansicolor
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>='
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.0.7
47
+ version: '1.3'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ! '>='
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 1.0.7
54
+ version: '1.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: json
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ! '>='
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.5.1
61
+ version: '1.8'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ! '>='
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.5.1
68
+ version: '1.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: net-ssh-multi
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - ! '>='
87
+ - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: 1.0.0
89
+ version: '1.10'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - ! '>='
94
+ - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: 1.0.0
96
+ version: '1.10'
83
97
  description: A small Grid'5000 helper to submit jobs and deploy environments via REST
84
98
  API
85
99
  email:
@@ -88,7 +102,7 @@ executables: []
88
102
  extensions: []
89
103
  extra_rdoc_files: []
90
104
  files:
91
- - .gitignore
105
+ - ".gitignore"
92
106
  - Gemfile
93
107
  - Gemfile.lock
94
108
  - LICENCE
@@ -96,6 +110,8 @@ files:
96
110
  - lib/xp5k.rb
97
111
  - lib/xp5k/config.rb
98
112
  - lib/xp5k/exceptions.rb
113
+ - lib/xp5k/rake.rb
114
+ - lib/xp5k/rake/dsl.rb
99
115
  - lib/xp5k/role.rb
100
116
  - lib/xp5k/version.rb
101
117
  - lib/xp5k/xp.rb
@@ -110,12 +126,12 @@ require_paths:
110
126
  - lib
111
127
  required_ruby_version: !ruby/object:Gem::Requirement
112
128
  requirements:
113
- - - ! '>='
129
+ - - ">="
114
130
  - !ruby/object:Gem::Version
115
131
  version: '0'
116
132
  required_rubygems_version: !ruby/object:Gem::Requirement
117
133
  requirements:
118
- - - ! '>='
134
+ - - ">="
119
135
  - !ruby/object:Gem::Version
120
136
  version: 1.3.6
121
137
  requirements: []
@@ -123,6 +139,5 @@ rubyforge_project:
123
139
  rubygems_version: 2.2.2
124
140
  signing_key:
125
141
  specification_version: 4
126
- summary: A small Grid'5000 helper to submit jobs and deploy environments via REST
127
- API
142
+ summary: A small Grid'5000 helper
128
143
  test_files: []