ruby-cute 0.6 → 0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4bee03262cac39274dd43426589fce86de6962eb
4
- data.tar.gz: b0262a03d84c76f2557550f4a0c05bcefc7c2a09
3
+ metadata.gz: c25c70220c9af96769ac92522d76cb09ee237846
4
+ data.tar.gz: 98596abba4e8569122cf00369fafc0b7ea8eefb1
5
5
  SHA512:
6
- metadata.gz: 2241ac02410656a7dbf16006d2f28ea9d02767e1b4e395fc0861798e6891eb60d60ede93b7899d87f86fc3dbe355da0071a8e591760f828b5a6e14737f8011b2
7
- data.tar.gz: ab9c2570faf491c33759ecd1317cf574b3e4779b86df251986b2456d50ba3b22eac475bc9af04e2017d278044f83bf0497f58ac6fb602ecc0be72f8f643f5a4e
6
+ metadata.gz: 305140e82df29d420897496719de4a71554a10ea7c9f32c90dd8c956576c7c374c6b2e57cac4daa685775631e85a6e6c23954d9686d83d4ccb3a5aa48cac459e
7
+ data.tar.gz: ae3e6bdb53792be17caeb8ee67824d4c61cb7f64ad15b29e74c099bc60a5ede6993d4051d1854e4b5826d356b1c16bf60d3679baa9ba5cee005afc18b23cb39f
data/README.md CHANGED
@@ -36,7 +36,6 @@ $ cat > ~/.grid5000_api.yml << EOF
36
36
  uri: https://api.grid5000.fr/
37
37
  username: user
38
38
  password: **********
39
- version: sid
40
39
  EOF
41
40
 
42
41
  ```
@@ -106,9 +105,86 @@ Within this shell you have preloaded [G5K Module](http://www.rubydoc.info/github
106
105
  [Net::SSH::Multi](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Net/SSH/Multi),
107
106
  you can go directly to their respective documentation to know how to take advantage of them.
108
107
 
109
- ### Experiment example
108
+ ### Examples
109
+
110
+ The following examples show how to use the [G5K Module](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/G5K/API) in an experiment.
111
+
112
+ #### Example 1: automatic experiment bootstrap
113
+
114
+ This example (also available as
115
+ [examples/xp-bootstrap](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/file/examples/xp-bootstrap)
116
+ is simple script automating the initial bootstrap of an experiment.
117
+
118
+ ```ruby
119
+ #!/usr/bin/ruby -w
120
+
121
+ # This script, to be executed on a frontend, automates the initial setup
122
+ # of an experiment, and then sleeps to let the user take over.
123
+ # The same script, run with --reserve, will handle resources reservation
124
+
125
+ # To make this work:
126
+ # - connect to a frontend
127
+ # - install ruby-cute: gem install --user-install ruby-cute
128
+ # - get this script, make it executable (chmod a+rx xp-bootstrap)
129
+ # - run it: ./xp-bootstrap --reserve
130
+
131
+ gem 'ruby-cute', ">=0.6"
132
+ require 'cute'
133
+ require 'pp'
134
+
135
+ g5k = Cute::G5K::API.new
136
+ G5K_SITE = `hostname --fqdn`.split('.')[-3] # get the site name from the `hostname` command
137
+ G5K_ENV = 'jessie-x64-base' # environment to deploy
138
+ NODES = 2
139
+ WALLTIME = '0:30'
140
+
141
+ # When the script is run with --reserve, use Ruby-Cute to reserve resources and run the script again inside the reservation, when it starts
142
+ if ARGV[0] == '--reserve'
143
+ # reserve two nodes for 30 mins
144
+ job = g5k.reserve(:site => G5K_SITE, :nodes => NODES, :walltime => WALLTIME, :type => :deploy, :wait => false,
145
+ :name => 'xp-bootstrap',
146
+ :cmd => File::realpath(__FILE__)
147
+ )
148
+ puts "Job #{job['uid']} created. Monitor its status with e.g.: oarstat -fj #{job['uid']}"
149
+ exit(0)
150
+ end
151
+
152
+ ###########################################################################
153
+ #### What follows is what gets executed inside the resources reservation
154
+
155
+ # for better output, redirect stderr to stdout, make stdout a synchronized output stream
156
+ STDERR.reopen(STDOUT)
157
+ STDOUT.sync = true
158
+
159
+ jobid = ENV['OAR_JOB_ID']
160
+ raise "OAR_JOB_ID not set. Are you running inside a OAR reservation? Maybe you should use #{__FILE__} --reserve?" if not jobid
161
+
162
+ # get job details
163
+ job = g5k.get_job(G5K_SITE, jobid)
164
+ nodes = job['assigned_nodes']
165
+ puts "Running on: #{nodes.join(' ')}"
166
+
167
+ # deploying all nodes, waiting for the end of deployment
168
+ g5k.deploy(job, :env => G5K_ENV, :wait => true)
169
+
170
+ raise "Deployment ended with error" if ((job['deploy'].last['status'] == 'error') or (not job['deploy'].last['result'].to_a.all? { |e| e[1]['state'] == 'OK' }))
171
+
172
+ cmd = 'apt-get update && apt-get -y install nuttcp'
173
+ puts "Running command: #{cmd}"
174
+ # Run a command on each node and analyze result
175
+ ssh = Net::SSH::Multi::Session::new
176
+ nodes.each { |n| ssh.use "root@#{n}" }
177
+ r = ssh.exec!(cmd)
178
+ raise "Command failed on at least one node\n#{r}" if not r.to_a.all? { |e| e[1][:status] == 0 }
179
+
180
+ # Sleep for a very long time to avoid reservation termination
181
+ puts "Experiment preparation finished."
182
+ puts "Nodes: #{nodes.join(' ')}"
183
+ sleep 86400*365
184
+ ```
185
+
186
+ #### Example 2: running MPI
110
187
 
111
- The following example shows how to use the [G5K Module](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/G5K/API) in an experiment.
112
188
  This example implements the experiment described in
113
189
  [MPI on Grid5000](https://www.grid5000.fr/mediawiki/index.php/Run_MPI_On_Grid%275000#Setting_up_and_starting_Open_MPI_to_use_high_performance_interconnect).
114
190
 
@@ -155,16 +231,16 @@ g5k.release(job) # Frees resources.
155
231
 
156
232
  ## Contact information
157
233
 
158
- Ruby-Cute is maintained by the Algorille team at LORIA/Inria Nancy - Grand Est, and specifically by:
234
+ Ruby-Cute is maintained by the Madynes team at LORIA/Inria Nancy - Grand Est, and specifically by:
159
235
 
160
- * Cristian Ruiz <cristian.ruiz@inria.fr>
161
- * Emmanuel Jeanvoine <emmanuel.jeanvoine@inria.fr>
162
236
  * Lucas Nussbaum <lucas.nussbaum@loria.fr>
163
237
 
164
238
  Past contributors include:
165
239
 
166
240
  * Sébastien Badia <sebastien.badia@inria.fr>
167
241
  * Tomasz Buchert <tomasz.buchert@inria.fr>
242
+ * Emmanuel Jeanvoine <emmanuel.jeanvoine@inria.fr>
243
+ * Cristian Ruiz <cristian.ruiz@inria.fr>
168
244
  * Luc Sarzyniec <luc.sarzyniec@inria.fr>
169
245
 
170
- Questions/comments should be directed to Lucas Nussbaum and Emmanuel Jeanvoine.
246
+ Questions/comments should be directed to Lucas Nussbaum.
@@ -1,16 +1,16 @@
1
- ruby-cute (0.6) UNRELEASED; urgency=medium
1
+ ruby-cute (0.6) unstable; urgency=medium
2
2
 
3
3
  * New release.
4
4
 
5
- -- Cristian Ruiz <cristian.ruiz@inria.fr> Thu, 20 Oct 2016 10:57:07 +0100
5
+ -- Lucas Nussbaum <lucas@debian.org> Fri, 17 Mar 2017 23:38:19 +0100
6
6
 
7
- ruby-cute (0.5) UNRELEASED; urgency=medium
7
+ ruby-cute (0.5) unstable; urgency=medium
8
8
 
9
9
  * New release.
10
10
 
11
11
  -- Cristian Ruiz <cristian.ruiz@inria.fr> Tue, 3 May 2016 08:54:42 +0100
12
12
 
13
- ruby-cute (0.4) UNRELEASED; urgency=medium
13
+ ruby-cute (0.4) unstable; urgency=medium
14
14
 
15
15
  * Initial release.
16
16
 
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ # This script, to be executed on a frontend, automates the initial setup
4
+ # of an experiment, and then sleeps to let the user take over.
5
+ # The same script, run with --reserve, will handle resources reservation
6
+
7
+ # To make this work:
8
+ # - connect to a frontend
9
+ # - install ruby-cute: gem install --user-install ruby-cute
10
+ # - get this script, make it executable (chmod a+rx xp-bootstrap)
11
+ # - run it: ./xp-bootstrap --reserve
12
+
13
+ gem 'ruby-cute', ">=0.6"
14
+ require 'cute'
15
+ require 'pp'
16
+
17
+ g5k = Cute::G5K::API.new
18
+ G5K_SITE = `hostname --fqdn`.split('.')[-3] # get the site name from the `hostname` command
19
+ G5K_ENV = 'jessie-x64-base' # environment to deploy
20
+ NODES = 2
21
+ WALLTIME = '0:30'
22
+
23
+ # When the script is run with --reserve, use Ruby-Cute to reserve resources and run the script again inside the reservation, when it starts
24
+ if ARGV[0] == '--reserve'
25
+ # reserve two nodes for 30 mins
26
+ job = g5k.reserve(:site => G5K_SITE, :nodes => NODES, :walltime => WALLTIME, :type => :deploy, :wait => false,
27
+ :name => 'xp-bootstrap',
28
+ :cmd => File::realpath(__FILE__)
29
+ )
30
+ puts "Job #{job['uid']} created. Monitor its status with e.g.: oarstat -fj #{job['uid']}"
31
+ exit(0)
32
+ end
33
+
34
+ ###########################################################################
35
+ #### What follows is what gets executed inside the resources reservation
36
+
37
+ # for better output, redirect stderr to stdout, make stdout a synchronized output stream
38
+ STDERR.reopen(STDOUT)
39
+ STDOUT.sync = true
40
+
41
+ jobid = ENV['OAR_JOB_ID']
42
+ raise "OAR_JOB_ID not set. Are you running inside a OAR reservation? Maybe you should use #{__FILE__} --reserve?" if not jobid
43
+
44
+ # get job details
45
+ job = g5k.get_job(G5K_SITE, jobid)
46
+ nodes = job['assigned_nodes']
47
+ puts "Running on: #{nodes.join(' ')}"
48
+
49
+ # deploying all nodes, waiting for the end of deployment
50
+ g5k.deploy(job, :env => G5K_ENV, :wait => true)
51
+
52
+ raise "Deployment ended with error" if ((job['deploy'].last['status'] == 'error') or (not job['deploy'].last['result'].to_a.all? { |e| e[1]['state'] == 'OK' }))
53
+
54
+ cmd = 'apt-get update && apt-get -y install nuttcp'
55
+ puts "Running command: #{cmd}"
56
+ # Run a command on each node and analyze result
57
+ ssh = Net::SSH::Multi::Session::new
58
+ nodes.each { |n| ssh.use "root@#{n}" }
59
+ r = ssh.exec!(cmd)
60
+ raise "Command failed on at least one node\n#{r}" if not r.to_a.all? { |e| e[1][:status] == 0 }
61
+
62
+ # Sleep for a very long time to avoid reservation termination
63
+ puts "Experiment preparation finished."
64
+ puts "Nodes: #{nodes.join(' ')}"
65
+ sleep 86400*365
@@ -1,5 +1,4 @@
1
1
  require 'cute/version'
2
- require 'cute/bash'
3
2
  require 'cute/execute'
4
3
  require 'cute/taktuk'
5
4
  require 'cute/g5k_api'
@@ -1,7 +1,13 @@
1
1
  require 'restclient'
2
2
  require 'yaml'
3
3
  require 'json'
4
- require 'ipaddress'
4
+ begin
5
+ old_verbose, $VERBOSE = $VERBOSE, false
6
+ require 'ipaddress'
7
+ ensure
8
+ $VERBOSE = old_verbose
9
+ end
10
+
5
11
  require 'uri'
6
12
 
7
13
  module Cute
@@ -225,14 +231,24 @@ module Cute
225
231
  return @api[path]
226
232
  end
227
233
 
234
+ RETRY_503_MAX = 10
235
+ RETRY_503_SLEEP = 1
236
+
228
237
  # @return [Hash] the HTTP response
229
238
  # @param path [String] this complements the URI to address to a specific resource
230
239
  def get_json(path)
231
-
240
+ retries = 0
232
241
  begin
233
242
  r = resource(path).get(:content_type => "application/json",
234
243
  :user_agent => @user_agent)
235
244
  rescue => e
245
+ if e.kind_of?(RestClient::Exception) and e.http_code == 503 and retries < RETRY_503_MAX
246
+ # the G5K REST API sometimes fail with error 503. In that case we should just wait and retry
247
+ puts("G5KRest: GET #{path} failed with error 503, retrying after #{RETRY_503_SLEEP} seconds")
248
+ retries += 1
249
+ sleep RETRY_503_SLEEP
250
+ retry
251
+ end
236
252
  handle_exception(e)
237
253
  end
238
254
  return G5KJSON.parse(r)
@@ -242,13 +258,20 @@ module Cute
242
258
  # @param path [String] this complements the URI to address to a specific resource
243
259
  # @param json [Hash] contains the characteristics of the resources to be created.
244
260
  def post_json(path, json)
245
-
261
+ retries = 0
246
262
  begin
247
263
  r = resource(path).post(json.to_json,
248
264
  :content_type => "application/json",
249
265
  :accept => "application/json",
250
266
  :user_agent => @user_agent)
251
267
  rescue => e
268
+ if e.kind_of?(RestClient::Exception) and e.http_code == 503 and retries < RETRY_503_MAX
269
+ # the G5K REST API sometimes fail with error 503. In that case we should just wait and retry
270
+ puts("G5KRest: POST #{path} failed with error 503, retrying after #{RETRY_503_SLEEP} seconds")
271
+ retries += 1
272
+ sleep RETRY_503_SLEEP
273
+ retry
274
+ end
252
275
  handle_exception(e)
253
276
  end
254
277
  return G5KJSON.parse(r)
@@ -257,9 +280,17 @@ module Cute
257
280
  # Deletes a resource on the server
258
281
  # @param path [String] this complements the URI to address to a specific resource
259
282
  def delete_json(path)
283
+ retries = 0
260
284
  begin
261
285
  return resource(path).delete()
262
286
  rescue => e
287
+ if e.kind_of?(RestClient::Exception) and e.http_code == 503 and retries < RETRY_503_MAX
288
+ # the G5K REST API sometimes fail with error 503. In that case we should just wait and retry
289
+ puts("G5KRest: DELETE #{path} failed with error 503, retrying after #{RETRY_503_SLEEP} seconds")
290
+ retries += 1
291
+ sleep RETRY_503_SLEEP
292
+ retry
293
+ end
263
294
  handle_exception(e)
264
295
  end
265
296
  end
@@ -616,6 +647,7 @@ module Cute
616
647
  environment_uids = environments(site).uids.map{ |e|
617
648
  e_match = /(.*)-(.*)/.match(e)
618
649
  new_name = e_match.nil? ? "" : e_match[1]
650
+ new_name
619
651
  }
620
652
 
621
653
  return environment_uids.uniq
@@ -1160,7 +1192,7 @@ module Cute
1160
1192
  # @param [Hash] opts Deploy options
1161
1193
  # @option opts [String] :env {http://kadeploy3.gforge.inria.fr/ Kadeploy} environment to deploy
1162
1194
  # @option opts [Array] :nodes Specifies the nodes to deploy on
1163
- # @option opts [String] :keys Specifies the SSH keys to copy for the deployment
1195
+ # @option opts [String] :keys Specifies the SSH keys to copy for the deployment. By default, the content of ~/.ssh/id_rsa.pub is used.
1164
1196
  # @option opts [Boolean] :wait Whether or not to wait until the deployment is done (default is false)
1165
1197
  # @return [G5KJSON] a job with deploy information as described in {Cute::G5K::G5KJSON job}
1166
1198
  def deploy(job, opts = {})
@@ -1,4 +1,9 @@
1
- require 'net/ssh/multi'
1
+ begin # load it without warnings
2
+ old_verbose, $VERBOSE = $VERBOSE, false
3
+ require 'net/ssh/multi'
4
+ ensure
5
+ $VERBOSE = old_verbose
6
+ end
2
7
  require 'logger'
3
8
 
4
9
  module Net; module SSH
@@ -91,6 +96,7 @@ module SessionActions
91
96
  #
92
97
  def exec!(command, &block)
93
98
 
99
+ Multi.logger.debug "SSH execution: #{command}"
94
100
  results = {}
95
101
 
96
102
  main =open_channel do |channel|
@@ -100,36 +106,38 @@ module SessionActions
100
106
 
101
107
  results[ch.connection.host] ||= {}
102
108
 
103
- channel.on_data do |ch, data|
109
+ channel.on_data do |c, data|
104
110
  if block
105
- block.call(ch, :stdout, data)
111
+ block.call(c, :stdout, data)
106
112
  else
107
- results[ch.connection.host][:stdout] = data.strip
108
- Multi.logger.debug("[#{ch.connection.host}] #{data.strip}")
113
+ results[c.connection.host][:stdout] ||= ""
114
+ results[c.connection.host][:stdout] += data.strip
115
+ Multi.logger.debug("[#{c.connection.host}] #{data.strip}")
109
116
  end
110
117
  end
111
- channel.on_extended_data do |ch, type, data|
118
+ channel.on_extended_data do |c, type, data|
112
119
  if block
113
- block.call(ch, :stderr, data)
120
+ block.call(c, :stderr, data)
114
121
  else
115
- results[ch.connection.host][:stderr] = data.strip
116
- Multi.logger.debug("[#{ch.connection.host}] #{data.strip}")
122
+ results[c.connection.host][:stderr] ||= ""
123
+ results[c.connection.host][:stderr] += data.strip
124
+ Multi.logger.debug("[#{c.connection.host}] #{data.strip}")
117
125
  end
118
126
  end
119
- channel.on_request("exit-status") do |ch, data|
120
- ch[:exit_status] = data.read_long
121
- results[ch.connection.host][:status] = ch[:exit_status]
122
- if ch[:exit_status] != 0
123
- Multi.logger.info("execution of '#{command}' on #{ch.connection.host}
124
- failed with return status #{ch[:exit_status].to_s}")
125
- if results[ch.connection.host][:stdout]
127
+ channel.on_request("exit-status") do |c, data|
128
+ c[:exit_status] = data.read_long
129
+ results[c.connection.host][:status] = c[:exit_status]
130
+ if c[:exit_status] != 0
131
+ Multi.logger.info("execution of '#{command}' on #{c.connection.host}
132
+ failed with return status #{c[:exit_status].to_s}")
133
+ if results[c.connection.host][:stdout]
126
134
  Multi.logger.info("--- stdout dump ---")
127
- Multi.logger.info(results[ch.connection.host][:stdout])
135
+ Multi.logger.info(results[c.connection.host][:stdout])
128
136
  end
129
137
 
130
- if results[ch.connection.host][:stderr]
138
+ if results[c.connection.host][:stderr]
131
139
  Multi.logger.info("--stderr dump ---")
132
- Multi.logger.info(results[ch.connection.host][:stderr])
140
+ Multi.logger.info(results[c.connection.host][:stderr])
133
141
  end
134
142
  end
135
143
  end
@@ -184,7 +184,7 @@ module Cute
184
184
  # Return just the value 0:(.*)
185
185
  def treat_value(string)
186
186
  tmp = string.split(":",2)
187
- value = tmp[1].nil? ? "" : tmp[1]
187
+ return tmp[1].nil? ? "" : tmp[1]
188
188
  end
189
189
 
190
190
  def to_cmd
@@ -1,3 +1,3 @@
1
1
  module Cute
2
- VERSION = "0.6"
2
+ VERSION = "0.7"
3
3
  end
@@ -23,10 +23,10 @@ Gem::Specification.new do |s|
23
23
  s.add_development_dependency "yard", "~> 0.8"
24
24
  s.add_development_dependency "simplecov", "~> 0.7"
25
25
 
26
- s.add_dependency 'rest-client', '1.6.7'
27
- s.add_dependency 'json', '~> 1.8'
28
- s.add_dependency 'ipaddress', '~>0.8'
29
- s.add_dependency 'net-ssh-multi', '~>1.2'
26
+ s.add_dependency 'rest-client', '>= 1.6'
27
+ s.add_dependency 'json', '>= 1.8'
28
+ s.add_dependency 'ipaddress', '>= 0.8'
29
+ s.add_dependency 'net-ssh-multi', '>= 1.2'
30
30
 
31
31
  s.extra_rdoc_files = ['README.md', 'LICENSE']
32
32
  s.license = 'CeCILL-B'
@@ -220,4 +220,17 @@ describe Cute::G5K::API do
220
220
  expect(subject.release_all(@rand_site)).to be true
221
221
  end
222
222
 
223
+ it "retries GET automatically when there is an error" do
224
+ expect(subject.get_jobs("tmpfail")).to be_truthy
225
+ end
226
+
227
+ it "retries POST automatically when there is an error" do
228
+ job = subject.reserve(:site => 'tmpfail', :wait => false)
229
+ expect(job).to be_truthy
230
+ end
231
+
232
+ it "retries DELETE automatically when there is an error" do
233
+ job = subject.rest.delete_json("3.0/sites/tmpfail/aa")
234
+ expect(job).to be_truthy
235
+ end
223
236
  end
@@ -55,6 +55,10 @@ RSpec.configure do |config|
55
55
  stub_request(:any,/^https:\/\/.*\:.*@api.grid5000.fr\/...\/sites\/non-found\/.*/).
56
56
  to_return(:status => 404)
57
57
 
58
+ stub_request(:any,/^https:\/\/.*\:.*@api.grid5000.fr\/...\/sites\/tmpfail\/.*/).
59
+ to_return(:status => 503).
60
+ to_return(:status => 200, :body => g5k_media_type.to_json, :headers => {})
61
+
58
62
  stub_request(:get,/^https:\/\/.*\:.*@api.grid5000.fr\/...\/sites\/.*vlans$/).
59
63
  to_return(:status => 200, :body => {'total' => 3, 'items' => [{'type' => "kavlan-local"},{'type' => "kvlan"}]}.to_json)
60
64
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-cute
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.6'
4
+ version: '0.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Algorille team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-20 00:00:00.000000000 Z
11
+ date: 2017-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -112,56 +112,56 @@ dependencies:
112
112
  name: rest-client
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '='
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: 1.6.7
117
+ version: '1.6'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '='
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: 1.6.7
124
+ version: '1.6'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: json
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - "~>"
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
131
  version: '1.8'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - "~>"
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '1.8'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: ipaddress
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - "~>"
143
+ - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0.8'
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - "~>"
150
+ - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0.8'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: net-ssh-multi
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - "~>"
157
+ - - ">="
158
158
  - !ruby/object:Gem::Version
159
159
  version: '1.2'
160
160
  type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - "~>"
164
+ - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '1.2'
167
167
  description: Ruby library for controlling experiments
@@ -194,6 +194,7 @@ files:
194
194
  - examples/g5k-tutorial.md
195
195
  - examples/g5k_exp1.rb
196
196
  - examples/g5k_exp_virt.rb
197
+ - examples/xp-bootstrap
197
198
  - lib/cute.rb
198
199
  - lib/cute/bash.rb
199
200
  - lib/cute/configparser.rb
@@ -233,7 +234,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
233
234
  version: 1.3.6
234
235
  requirements: []
235
236
  rubyforge_project:
236
- rubygems_version: 2.2.2
237
+ rubygems_version: 2.5.2
237
238
  signing_key:
238
239
  specification_version: 4
239
240
  summary: Critically Useful Tools for Experiments
@@ -245,4 +246,3 @@ test_files:
245
246
  - spec/taktuk_spec.rb
246
247
  - test/test_bash.rb
247
248
  - test/test_execute.rb
248
- has_rdoc: