ruby-cute 0.12 → 0.24
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 +5 -5
- data/.gitlab-ci.yml +55 -0
- data/README.md +12 -1
- data/bin/cute +2 -1
- data/bin/grd +701 -0
- data/debian/.gitattributes +3 -0
- data/debian/changelog +108 -0
- data/debian/control +22 -5
- data/debian/ruby-cute.docs +1 -1
- data/debian/rules +3 -11
- data/debian/watch +2 -2
- data/examples/distem-bootstrap +16 -22
- data/examples/g5k-tutorial.md +25 -18
- data/examples/g5k_exp_virt.rb +1 -1
- data/lib/cute/bash.rb +7 -7
- data/lib/cute/configparser.rb +14 -12
- data/lib/cute/execute.rb +6 -4
- data/lib/cute/extensions.rb +3 -4
- data/lib/cute/g5k_api.rb +62 -38
- data/lib/cute/net-ssh-exec3.rb +10 -7
- data/lib/cute/net-ssh.rb +2 -2
- data/lib/cute/net.rb +5 -7
- data/lib/cute/synchronization.rb +1 -3
- data/lib/cute/taktuk.rb +4 -5
- data/lib/cute/version.rb +1 -1
- data/ruby-cute.gemspec +6 -3
- data/spec/g5k_api_check_spec.rb +1 -1
- data/spec/g5k_api_spec.rb +14 -22
- data/spec/spec_helper.rb +10 -6
- data/test/test_execute.rb +0 -0
- metadata +55 -11
- data/debian/compat +0 -1
data/lib/cute/g5k_api.rb
CHANGED
@@ -24,7 +24,7 @@ module Cute
|
|
24
24
|
# - {Cute::G5K::Unauthorized} it means that there is an authentication problem.
|
25
25
|
# - {Cute::G5K::EventTimeout} this exception is triggered by the methods that wait for events such as:
|
26
26
|
# job submission and environment deployment.
|
27
|
-
class Error <
|
27
|
+
class Error < StandardError
|
28
28
|
attr_accessor :orig # Original exception
|
29
29
|
|
30
30
|
def initialize(message = nil, object = nil)
|
@@ -63,6 +63,7 @@ module Cute
|
|
63
63
|
#
|
64
64
|
# end
|
65
65
|
class BadRequest < Error
|
66
|
+
attr_accessor :inner_url, :inner_code, :inner_title, :inner_message
|
66
67
|
end
|
67
68
|
|
68
69
|
# It wraps all Restclient exceptions with http codes: 403, 405,406, 412, 415, 500, 502, 503 and 504.
|
@@ -205,7 +206,8 @@ module Cute
|
|
205
206
|
# @param user [String] user if authentication is needed
|
206
207
|
# @param pass [String] password if authentication is needed
|
207
208
|
# @param on_error [Symbol] option to deactivate the {Cute::G5K::RequestFailed RequestFailed} exceptions
|
208
|
-
|
209
|
+
# @param timeout [Integer] timeout for Rest request
|
210
|
+
def initialize(uri,api_version,user,pass,on_error,timeout)
|
209
211
|
@user = user
|
210
212
|
@pass = pass
|
211
213
|
@api_version = api_version.nil? ? "stable" : api_version
|
@@ -217,9 +219,8 @@ module Cute
|
|
217
219
|
@endpoint = "https://#{user_escaped}:#{pass_escaped}@#{uri.split("https://")[1]}"
|
218
220
|
end
|
219
221
|
|
220
|
-
machine =`uname -ov`.chop
|
221
222
|
@user_agent = "ruby-cute/#{VERSION} Ruby/#{RUBY_VERSION}"
|
222
|
-
@api = RestClient::Resource.new(@endpoint, :timeout =>
|
223
|
+
@api = RestClient::Resource.new(@endpoint, :timeout => timeout,:verify_ssl => false)
|
223
224
|
# some versions of restclient do not verify by default SSL certificates , :verify_ssl => true)
|
224
225
|
# SSL verify is disabled due to Grid'5000 API certificate problem
|
225
226
|
@on_error = on_error
|
@@ -239,6 +240,12 @@ module Cute
|
|
239
240
|
# @return [Hash] the HTTP response
|
240
241
|
# @param path [String] this complements the URI to address to a specific resource
|
241
242
|
def get_json(path)
|
243
|
+
return G5KJSON.parse(get_raw(path))
|
244
|
+
end
|
245
|
+
|
246
|
+
# @return [String] the HTTP response
|
247
|
+
# @param path [String] this complements the URI to address to a specific resource
|
248
|
+
def get_raw(path)
|
242
249
|
retries = 0
|
243
250
|
begin
|
244
251
|
r = resource(path).get(:content_type => "application/json",
|
@@ -253,7 +260,7 @@ module Cute
|
|
253
260
|
end
|
254
261
|
handle_exception(e)
|
255
262
|
end
|
256
|
-
return
|
263
|
+
return r
|
257
264
|
end
|
258
265
|
|
259
266
|
# Creates a resource on the server
|
@@ -314,7 +321,7 @@ module Cute
|
|
314
321
|
end
|
315
322
|
|
316
323
|
# Issues a Cute::G5K exception according to the http status code
|
317
|
-
def handle_exception(e,
|
324
|
+
def handle_exception(e, _req = nil)
|
318
325
|
puts("Error: #{$!}")
|
319
326
|
puts("Backtrace:\n\t"+e.backtrace.join("\n\t"))
|
320
327
|
if e.respond_to? :http_code
|
@@ -332,11 +339,24 @@ module Cute
|
|
332
339
|
case e.http_code
|
333
340
|
|
334
341
|
when 400
|
335
|
-
|
342
|
+
br = BadRequest.new("Bad request (error 400): #{e.http_body}", e)
|
343
|
+
if e.http_body =~ /^Request to ([^ ]*) failed with status 400: (.*)$/m
|
344
|
+
br.inner_url = $1
|
345
|
+
json = $2
|
346
|
+
begin
|
347
|
+
d = JSON::parse(json)
|
348
|
+
br.inner_code = d['code']
|
349
|
+
br.inner_title = d['title']
|
350
|
+
br.inner_message = d['message']
|
351
|
+
rescue JSON::ParserError
|
352
|
+
# Ignore error
|
353
|
+
end
|
354
|
+
end
|
355
|
+
raise br
|
336
356
|
when 404
|
337
|
-
raise NotFound.new("Resource not found", e)
|
357
|
+
raise NotFound.new("Resource not found (error 404): #{e.http_body}", e)
|
338
358
|
when 401
|
339
|
-
raise Unauthorized.new("Authentication problem",e)
|
359
|
+
raise Unauthorized.new("Authentication problem (error 401): #{e.http_body}",e)
|
340
360
|
else
|
341
361
|
if @on_error == :ignore
|
342
362
|
return nil
|
@@ -549,6 +569,7 @@ module Cute
|
|
549
569
|
# @option params [String] :password Password to access the REST API
|
550
570
|
# @option params [Symbol] :on_error Set to :ignore if you want to ignore {Cute::G5K::RequestFailed ResquestFailed} exceptions.
|
551
571
|
# @option params [Boolean] :debug Activate the debug mode
|
572
|
+
# @option params [Integer] :timeout Set the timeout in sec, default is 30 sec
|
552
573
|
def initialize(params={})
|
553
574
|
config = {}
|
554
575
|
default_file = "#{ENV['HOME']}/.grid5000_api.yml"
|
@@ -567,9 +588,10 @@ module Cute
|
|
567
588
|
@api_version = params[:version] || config["version"] || "stable"
|
568
589
|
@logger = nil
|
569
590
|
@debug = params[:debug] || false
|
591
|
+
@timeout = params[:timeout] || 30
|
570
592
|
|
571
593
|
begin
|
572
|
-
@g5k_connection = G5KRest.new(@uri,@api_version,@user,@pass,params[:on_error])
|
594
|
+
@g5k_connection = G5KRest.new(@uri,@api_version,@user,@pass,params[:on_error], @timeout)
|
573
595
|
rescue => e
|
574
596
|
|
575
597
|
msg_create_file = ""
|
@@ -695,7 +717,9 @@ module Cute
|
|
695
717
|
# @param site [String] a valid Grid'5000 site name
|
696
718
|
# @param uid [String] user name in Grid'5000
|
697
719
|
# @param states [Array] or [String] jobs state: running, waiting (multiple states can be specified)
|
698
|
-
|
720
|
+
# @param details [String] pass "resources=yes to the query to get the list of resources
|
721
|
+
# @param recurse [String] after fetching the list of jobs, fetch details about each job individualy
|
722
|
+
def get_jobs(site, uid = nil, states = nil, details = false, recurse = true)
|
699
723
|
|
700
724
|
parameters = []
|
701
725
|
if states then
|
@@ -703,12 +727,18 @@ module Cute
|
|
703
727
|
parameters.push("state=#{states.join(",")}")
|
704
728
|
end
|
705
729
|
parameters.push("user=#{uid}") if uid
|
706
|
-
parameters.push("limit=
|
730
|
+
parameters.push("limit=1000000")
|
731
|
+
parameters.push("resources=yes") if details
|
707
732
|
|
733
|
+
info(debug_cmd(api_uri("/sites/#{site}/jobs?#{parameters.join("&")}"),"GET"), :debug)
|
708
734
|
jobs = @g5k_connection.get_json(api_uri("/sites/#{site}/jobs?#{parameters.join("&")}")).items
|
709
|
-
|
710
|
-
|
711
|
-
|
735
|
+
if recurse
|
736
|
+
jobs.map! do |j|
|
737
|
+
info(debug_cmd(j.rel_self, "GET"), :debug)
|
738
|
+
@g5k_connection.get_json(j.rel_self)
|
739
|
+
end
|
740
|
+
end
|
741
|
+
jobs.to_a
|
712
742
|
end
|
713
743
|
|
714
744
|
# @return [Hash] the last 50 deployments performed in a Grid'5000 site
|
@@ -970,6 +1000,7 @@ module Cute
|
|
970
1000
|
# @option opts [String] :cmd The command to execute when the job starts (e.g. ./my-script.sh).
|
971
1001
|
# @option opts [String] :cluster Valid Grid'5000 cluster
|
972
1002
|
# @option opts [String] :queue A specific job queue
|
1003
|
+
# @option opts [String] :project A specific OAR project
|
973
1004
|
# @option opts [Array] :subnets 1) prefix_size, 2) number of subnets
|
974
1005
|
# @option opts [String] :env Environment name for {http://kadeploy3.gforge.inria.fr/ Kadeploy}
|
975
1006
|
# @option opts [String] :vlan VLAN type and number: kavlan-local, kavlan, kavlan-topo, etc
|
@@ -984,12 +1015,12 @@ module Cute
|
|
984
1015
|
# checking valid options
|
985
1016
|
valid_opts = [:site, :cluster, :switches, :cpus, :cores, :nodes, :walltime, :cmd,
|
986
1017
|
:type, :name, :subnets, :env, :vlan, :num_vlan,:properties, :resources,
|
987
|
-
:reservation, :wait, :keys, :queue, :env_user]
|
1018
|
+
:reservation, :wait, :keys, :queue, :project, :env_user]
|
988
1019
|
unre_opts = opts.keys - valid_opts
|
989
1020
|
raise ArgumentError, "Unrecognized option #{unre_opts}" unless unre_opts.empty?
|
990
1021
|
|
991
1022
|
nodes = opts.fetch(:nodes, 1)
|
992
|
-
walltime = opts
|
1023
|
+
walltime = opts[:walltime]
|
993
1024
|
site = opts[:site]
|
994
1025
|
type = opts.fetch(:type, [])
|
995
1026
|
name = opts.fetch(:name, 'rubyCute job')
|
@@ -1007,6 +1038,7 @@ module Cute
|
|
1007
1038
|
type = [type] if type.is_a?(Symbol)
|
1008
1039
|
keys = opts[:keys]
|
1009
1040
|
queue = opts[:queue]
|
1041
|
+
project = opts[:project]
|
1010
1042
|
vlan = opts[:vlan]
|
1011
1043
|
num_vlan = opts.fetch(:num_vlan, 1)
|
1012
1044
|
|
@@ -1021,14 +1053,11 @@ module Cute
|
|
1021
1053
|
raise ArgumentError, "VLAN type not available in site #{site}" unless available_vlans.include?(vlan)
|
1022
1054
|
end
|
1023
1055
|
|
1024
|
-
raise 'At least nodes
|
1056
|
+
raise 'At least nodes and site must be given' if [nodes, site].any? { |x| x.nil? }
|
1025
1057
|
|
1026
|
-
raise 'nodes should be an integer or a string containing either ALL or BEST' unless (nodes.is_a?(
|
1058
|
+
raise 'nodes should be an integer or a string containing either ALL or BEST' unless (nodes.is_a?(Integer) or ["ALL","BEST"].include?(nodes))
|
1027
1059
|
|
1028
|
-
|
1029
|
-
walltime = walltime.to_time
|
1030
|
-
|
1031
|
-
command = "sleep #{secs}" if command.nil?
|
1060
|
+
command = "sleep infinity" if command.nil?
|
1032
1061
|
|
1033
1062
|
if resources == ""
|
1034
1063
|
resources = "/switch=#{switches}" unless switches.nil?
|
@@ -1037,14 +1066,16 @@ module Cute
|
|
1037
1066
|
resources += "/core=#{cores}" unless cores.nil?
|
1038
1067
|
|
1039
1068
|
if cluster
|
1040
|
-
resources = (cluster.is_a?(
|
1069
|
+
resources = (cluster.is_a?(Integer) ? "/cluster=#{cluster}" : "{cluster='#{cluster}'}") + resources
|
1041
1070
|
end
|
1042
1071
|
|
1043
1072
|
resources = "{type='#{vlan}'}/vlan=#{num_vlan}+" + resources unless vlan.nil?
|
1044
1073
|
resources = "slash_#{subnets[0]}=#{subnets[1]}+" + resources unless subnets.nil?
|
1045
1074
|
end
|
1046
1075
|
|
1047
|
-
|
1076
|
+
if walltime
|
1077
|
+
resources += ",walltime=#{walltime}" unless resources.include?("walltime")
|
1078
|
+
end
|
1048
1079
|
|
1049
1080
|
payload = {
|
1050
1081
|
'resources' => resources,
|
@@ -1052,12 +1083,13 @@ module Cute
|
|
1052
1083
|
'command' => command
|
1053
1084
|
}
|
1054
1085
|
|
1055
|
-
info "Reserving resources: #{resources} (
|
1086
|
+
info "Reserving resources: #{resources} (types: #{type.join(' ')}) (in #{site})"
|
1056
1087
|
|
1057
1088
|
payload['properties'] = properties unless properties.nil?
|
1058
1089
|
payload['types'] = type.map{ |t| t.to_s} unless type.nil?
|
1059
1090
|
type.map!{|t| t.to_sym} unless type.nil?
|
1060
1091
|
payload['queue'] = queue if queue
|
1092
|
+
payload['project'] = project if project
|
1061
1093
|
|
1062
1094
|
unless type.include?(:deploy)
|
1063
1095
|
if opts[:keys]
|
@@ -1067,18 +1099,10 @@ module Cute
|
|
1067
1099
|
|
1068
1100
|
if reservation
|
1069
1101
|
payload['reservation'] = reservation
|
1070
|
-
info "Starting this reservation at #{reservation}"
|
1071
1102
|
end
|
1072
1103
|
|
1073
|
-
|
1074
|
-
|
1075
|
-
r = @g5k_connection.post_json(api_uri("sites/#{site}/jobs"),payload) # This makes reference to the same class
|
1076
|
-
rescue Error => e
|
1077
|
-
info "Fail to submit job"
|
1078
|
-
info e.message
|
1079
|
-
e.http_body.split("\\n").each{ |line| info line}
|
1080
|
-
raise
|
1081
|
-
end
|
1104
|
+
info debug_cmd(api_uri("sites/#{site}/jobs"),"POST",payload.to_json), :debug
|
1105
|
+
r = @g5k_connection.post_json(api_uri("sites/#{site}/jobs"),payload) # This makes reference to the same class
|
1082
1106
|
|
1083
1107
|
job = @g5k_connection.get_json(r.rel_self)
|
1084
1108
|
job = wait_for_job(job) if opts[:wait] == true
|
@@ -1268,7 +1292,7 @@ module Cute
|
|
1268
1292
|
|
1269
1293
|
job["deploy"].map!{ |d| d.refresh(@g5k_connection) }
|
1270
1294
|
|
1271
|
-
filter.keep_if{ |
|
1295
|
+
filter.keep_if{ |_k,v| v} # removes nil values
|
1272
1296
|
if filter.empty?
|
1273
1297
|
status = job["deploy"].map{ |d| d["status"] }
|
1274
1298
|
else
|
@@ -1346,7 +1370,7 @@ module Cute
|
|
1346
1370
|
# @return [Array] machines that did not deploy successfully
|
1347
1371
|
# @param deploy_info [Hash] deployment structure information
|
1348
1372
|
def check_deployment(deploy_info)
|
1349
|
-
deploy_info["result"].select{ |
|
1373
|
+
deploy_info["result"].select{ |_p,v| v["state"] == "KO"}.keys
|
1350
1374
|
end
|
1351
1375
|
|
1352
1376
|
# Returns a valid URI using the current G5K API version.
|
data/lib/cute/net-ssh-exec3.rb
CHANGED
@@ -14,17 +14,18 @@ class Net::SSH::Connection::Session
|
|
14
14
|
res[:stderr] = ""
|
15
15
|
res[:exit_code] = nil
|
16
16
|
res[:exit_signal] = nil
|
17
|
+
ts = Time::now
|
17
18
|
open_channel do |channel|
|
18
|
-
channel.exec(command) do |
|
19
|
+
channel.exec(command) do |_ch, success|
|
19
20
|
unless success
|
20
21
|
abort "FAILED: couldn't execute command (ssh.channel.exec)"
|
21
22
|
end
|
22
|
-
channel.on_data do |
|
23
|
+
channel.on_data do |_ch,data|
|
23
24
|
print data unless o[:no_output]
|
24
25
|
res[:stdout]+=data
|
25
26
|
end
|
26
27
|
|
27
|
-
channel.on_extended_data do |
|
28
|
+
channel.on_extended_data do |_ch,_type,data|
|
28
29
|
print data unless o[:no_output]
|
29
30
|
if o[:merge_outputs]
|
30
31
|
res[:stdout]+=data
|
@@ -33,14 +34,16 @@ class Net::SSH::Connection::Session
|
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
|
-
channel.on_request("exit-status") do |
|
37
|
+
channel.on_request("exit-status") do |_ch,data|
|
37
38
|
res[:exit_code] = data.read_long
|
38
|
-
|
39
|
+
d = sprintf("%.1f", Time::now - ts)
|
40
|
+
puts "EXITCODE: #{res[:exit_code]} (duration: #{d}s)" unless o[:no_log]
|
39
41
|
end
|
40
42
|
|
41
|
-
channel.on_request("exit-signal") do |
|
43
|
+
channel.on_request("exit-signal") do |_ch, data|
|
42
44
|
res[:exit_signal] = data.read_long
|
43
|
-
|
45
|
+
d = sprintf("%.1f", Time::now - ts)
|
46
|
+
puts "EXITSIGNAL: #{res[:exit_signal]} (duration: #{d}s)" unless o[:no_log]
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|
data/lib/cute/net-ssh.rb
CHANGED
@@ -115,7 +115,7 @@ module SessionActions
|
|
115
115
|
Multi.logger.debug("[#{c.connection.host}] #{data.strip}")
|
116
116
|
end
|
117
117
|
end
|
118
|
-
channel.on_extended_data do |c,
|
118
|
+
channel.on_extended_data do |c, _type, data|
|
119
119
|
if block
|
120
120
|
block.call(c, :stderr, data)
|
121
121
|
else
|
@@ -129,7 +129,7 @@ module SessionActions
|
|
129
129
|
results[c.connection.host][:status] = c[:exit_status]
|
130
130
|
if c[:exit_status] != 0
|
131
131
|
Multi.logger.info("execution of '#{command}' on #{c.connection.host}
|
132
|
-
failed with return status #{c[:exit_status]
|
132
|
+
failed with return status #{c[:exit_status]}")
|
133
133
|
if results[c.connection.host][:stdout]
|
134
134
|
Multi.logger.info("--- stdout dump ---")
|
135
135
|
Multi.logger.info(results[c.connection.host][:stdout])
|
data/lib/cute/net.rb
CHANGED
@@ -13,14 +13,12 @@ module Cute
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def Network::wait_open_port(host, port, timeout = 120)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
while now() < bound do
|
21
|
-
t = now()
|
16
|
+
now = -> { return Time.now.to_f }
|
17
|
+
bound = now.call + timeout
|
18
|
+
while now.call < bound do
|
19
|
+
t = now.call
|
22
20
|
return true if port_open?(host, port)
|
23
|
-
dt = now
|
21
|
+
dt = now.call - t
|
24
22
|
sleep(0.5 - dt) if dt < 0.5
|
25
23
|
end
|
26
24
|
return false
|
data/lib/cute/synchronization.rb
CHANGED
data/lib/cute/taktuk.rb
CHANGED
@@ -123,7 +123,6 @@ module Cute
|
|
123
123
|
yield taktuk_cmd
|
124
124
|
taktuk_cmd.loop unless taktuk_cmd.commands.empty?
|
125
125
|
taktuk_cmd.free! if taktuk_cmd
|
126
|
-
taktuk_cmd = nil
|
127
126
|
end
|
128
127
|
else
|
129
128
|
return taktuk_cmd
|
@@ -372,9 +371,9 @@ module Cute
|
|
372
371
|
def to_cmd
|
373
372
|
self.inject([]) do |ret,val|
|
374
373
|
if val =~ /^\[(.*)\]$/
|
375
|
-
ret
|
374
|
+
ret + ['[',Regexp.last_match(1).strip,']']
|
376
375
|
else
|
377
|
-
ret
|
376
|
+
ret + val.split(' ')
|
378
377
|
end
|
379
378
|
end
|
380
379
|
end
|
@@ -417,7 +416,7 @@ module Cute
|
|
417
416
|
|
418
417
|
@streams.types.each{ |name|
|
419
418
|
@args << '-o'
|
420
|
-
@args << "#{name
|
419
|
+
@args << "#{name}=#{@streams.to_cmd}"
|
421
420
|
}
|
422
421
|
|
423
422
|
connector = build_connector
|
@@ -563,7 +562,7 @@ module Cute
|
|
563
562
|
# tak.input(:file => "test_file.tar")
|
564
563
|
def input(opts = {})
|
565
564
|
mode = "broadcast"
|
566
|
-
@commands << "#{mode} input #{opts.keys.first
|
565
|
+
@commands << "#{mode} input #{opts.keys.first}"
|
567
566
|
@commands << "[ #{opts.values.first} ]"
|
568
567
|
@commands << ';'
|
569
568
|
end
|
data/lib/cute/version.rb
CHANGED
data/ruby-cute.gemspec
CHANGED
@@ -5,9 +5,9 @@ require 'cute/version'
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "ruby-cute"
|
7
7
|
s.version = Cute::VERSION
|
8
|
-
s.authors = ["Algorille
|
9
|
-
s.email = "
|
10
|
-
s.homepage = "http://ruby-cute.
|
8
|
+
s.authors = ["Algorille/Madynes/RESIST teams at Inria/LORIA"]
|
9
|
+
s.email = "lucas.nussbaum@inria.fr"
|
10
|
+
s.homepage = "http://ruby-cute.github.io/"
|
11
11
|
s.summary = "Critically Useful Tools for Experiments"
|
12
12
|
s.description = "Ruby library for controlling experiments"
|
13
13
|
s.required_rubygems_version = ">= 1.3.6"
|
@@ -26,7 +26,10 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_dependency 'rest-client', '>= 1.6'
|
27
27
|
s.add_dependency 'json', '>= 1.8'
|
28
28
|
s.add_dependency 'ipaddress', '>= 0.8'
|
29
|
+
s.add_dependency 'net-ssh', '>= 3.2'
|
29
30
|
s.add_dependency 'net-ssh-multi', '>= 1.2'
|
31
|
+
s.add_dependency 'net-scp', '>= 1.2'
|
32
|
+
s.add_dependency 'peach', '>= 0.5.1'
|
30
33
|
|
31
34
|
s.extra_rdoc_files = ['README.md', 'LICENSE']
|
32
35
|
s.license = 'CeCILL-B'
|
data/spec/g5k_api_check_spec.rb
CHANGED
@@ -4,7 +4,7 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe Cute::G5K::API do
|
6
6
|
|
7
|
-
subject {
|
7
|
+
subject { ENV['TEST_REAL'].nil?? Cute::G5K::API.new(:user => "test") : Cute::G5K::API.new() }
|
8
8
|
|
9
9
|
before :each do
|
10
10
|
if ENV['TEST_REAL']
|
data/spec/g5k_api_spec.rb
CHANGED
@@ -4,9 +4,9 @@ require 'spec_helper'
|
|
4
4
|
describe Cute::G5K::API do
|
5
5
|
|
6
6
|
if ENV['TEST_REAL']
|
7
|
-
subject {
|
7
|
+
subject { ENV['DEBUG'].nil?? Cute::G5K::API.new() : Cute::G5K::API.new(:debug => true) }
|
8
8
|
else
|
9
|
-
subject {
|
9
|
+
subject { ENV['DEBUG'].nil?? Cute::G5K::API.new(:user => "test") : Cute::G5K::API.new(:user => "test",:debug => true) }
|
10
10
|
end
|
11
11
|
|
12
12
|
let(:sites) { subject.site_uids}
|
@@ -69,27 +69,20 @@ describe Cute::G5K::API do
|
|
69
69
|
expect(subject.get_deployments(@rand_site)).to be_an_instance_of(Cute::G5K::G5KArray)
|
70
70
|
end
|
71
71
|
|
72
|
+
=begin
|
72
73
|
it "raises an authentication error" do
|
73
74
|
expect{Cute::G5K::API.new(:user => "fake", :pass => "fake") }.to raise_error
|
74
75
|
end
|
76
|
+
=end
|
75
77
|
|
76
|
-
it "raises a
|
77
|
-
expect{subject.get_jobs("
|
78
|
-
end
|
79
|
-
|
80
|
-
it "raises a bad request error" do
|
81
|
-
expect{ subject.reserve(:site => @rand_site, :resources =>"/slash_22=1+{nonsense}")}.to raise_error(Cute::G5K::BadRequest)
|
82
|
-
# expect{ subject.reserve(:site => @rand_site, :resources =>"{ib30g='YES'}/nodes=2")}.to raise_error(Cute::G5K::BadRequest)
|
83
|
-
end
|
84
|
-
|
85
|
-
it "raises a bad request using OAR API" do
|
86
|
-
expect{subject.reserve(:site => @rand_site, :resources =>"nodes=1",:keys => "~/jobkey_nonexisting")}.to raise_error(Cute::G5K::BadRequest)
|
87
|
-
end
|
88
|
-
|
89
|
-
it "raises an exception at deploying" do
|
90
|
-
expect{ subject.reserve(:site => @rand_site, :nodes => 1, :env => "nonsense")}.to raise_error(Cute::G5K::RequestFailed)
|
78
|
+
it "raises a not found error" do
|
79
|
+
expect{subject.get_jobs("not-found")}.to raise_error(Cute::G5K::NotFound)
|
91
80
|
end
|
92
81
|
|
82
|
+
# it "raises an exception at deploying" do
|
83
|
+
# expect{ subject.reserve(:site => @rand_site, :nodes => 1, :env => "nonsense")}.to raise_error(Cute::G5K::RequestFailed)
|
84
|
+
# end
|
85
|
+
#
|
93
86
|
it "raises argument errors" do
|
94
87
|
job = Cute::G5K::G5KJSON.new
|
95
88
|
expect {subject.deploy(:env => "env")}.to raise_error(ArgumentError)
|
@@ -185,10 +178,10 @@ describe Cute::G5K::API do
|
|
185
178
|
end
|
186
179
|
|
187
180
|
|
188
|
-
it "submits a job and then deploy" do
|
189
|
-
expect(subject.reserve(:site => @rand_site, :env => @env)).to have_key("deploy")
|
190
|
-
end
|
191
|
-
|
181
|
+
# it "submits a job and then deploy" do
|
182
|
+
# expect(subject.reserve(:site => @rand_site, :env => @env)).to have_key("deploy")
|
183
|
+
# end
|
184
|
+
#
|
192
185
|
|
193
186
|
it "returns the same information" do
|
194
187
|
#low level REST access
|
@@ -197,7 +190,6 @@ describe Cute::G5K::API do
|
|
197
190
|
end
|
198
191
|
|
199
192
|
it "submit and does not wait for the reservation" do
|
200
|
-
cluster = subject.cluster_uids(@rand_site).first
|
201
193
|
job = subject.reserve(:site => @rand_site, :wait => false)
|
202
194
|
job = subject.wait_for_job(job, :wait_time => 600)
|
203
195
|
expect(job).to include('state' => "running")
|
data/spec/spec_helper.rb
CHANGED
@@ -30,6 +30,7 @@ class FakeG5KResponse < Hash
|
|
30
30
|
'nodes' => {"node1" => {"hard"=> "alive", "soft"=>"busy"}}
|
31
31
|
}
|
32
32
|
def initialize(num_items = 2)
|
33
|
+
super
|
33
34
|
MEDIA_TYPE.each { |key,value| self[key] = value}
|
34
35
|
self['items'] = []
|
35
36
|
num_items.times.each{ self['items'].push(MEDIA_TYPE) }
|
@@ -46,33 +47,36 @@ RSpec.configure do |config|
|
|
46
47
|
# uri_sites = Addressable::Template.new "https://{user}:{password}@api.grid5000.fr/{version}/sites"
|
47
48
|
config.before(:each) do
|
48
49
|
|
50
|
+
stub_request(:any,/^https:\/\/api.grid5000.fr\/.*/).
|
51
|
+
to_return(:status => 200, :body => g5k_media_type.to_json, :headers => {})
|
52
|
+
|
49
53
|
stub_request(:any,/^https:\/\/.*\:.*@api.grid5000.fr\/.*/).
|
50
54
|
to_return(:status => 200, :body => g5k_media_type.to_json, :headers => {})
|
51
55
|
|
52
56
|
stub_request(:any,/^https:\/\/fake:fake@api.grid5000.fr\.*/).
|
53
57
|
to_return(:status => 401)
|
54
58
|
|
55
|
-
stub_request(:any,/^https
|
59
|
+
stub_request(:any,/^https:\/\/(.*\:.*@)?api.grid5000.fr\/.*\/sites\/not-found\/.*/).
|
56
60
|
to_return(:status => 404)
|
57
61
|
|
58
|
-
stub_request(:any,/^https
|
62
|
+
stub_request(:any,/^https:\/\/(.*\:.*@)?api.grid5000.fr\/.*\/sites\/tmpfail\/.*/).
|
59
63
|
to_return(:status => 503).
|
60
64
|
to_return(:status => 200, :body => g5k_media_type.to_json, :headers => {})
|
61
65
|
|
62
|
-
stub_request(:get,/^https
|
66
|
+
stub_request(:get,/^https:\/\/(.*\:.*@)?api.grid5000.fr\/.*\/sites\/.*vlans$/).
|
63
67
|
to_return(:status => 200, :body => {'total' => 3, 'items' => [{'type' => "kavlan-local"},{'type' => "kvlan"}]}.to_json)
|
64
68
|
|
65
69
|
# to_return(:status => 200, :body => {:total => 3, :items => [{:type => "kavlan-local"},{:type => "kavlan"}]})
|
66
70
|
|
67
|
-
stub_request(:post, /^https
|
71
|
+
stub_request(:post, /^https:\/\/(.*\:.*@)?api.grid5000.fr\/.*/).
|
68
72
|
with(:body => hash_including("resources" => "/slash_22=1+{nonsense},walltime=01:00")).
|
69
73
|
to_return(:status => 400, :body => "Oarsub failed: please verify your request syntax")
|
70
74
|
|
71
|
-
stub_request(:post, /^https
|
75
|
+
stub_request(:post, /^https:\/\/(.*\:.*@)?api.grid5000.fr\/.*/).
|
72
76
|
with(:body => hash_including("import-job-key-from-file" => [ File.expand_path("~/jobkey_nonexisting") ])).
|
73
77
|
to_return(:status => 400, :body => "Oarsub failed: please verify your request syntax")
|
74
78
|
|
75
|
-
stub_request(:post, /^https
|
79
|
+
stub_request(:post, /^https:\/\/(.*\:.*@)?api.grid5000.fr\/.*/).
|
76
80
|
with(:body => hash_including("environment" => "nonsense")).
|
77
81
|
to_return(:status => 500, :body => "Invalid environment specification")
|
78
82
|
|
data/test/test_execute.rb
CHANGED
File without changes
|