ruby-cute 0.12 → 0.24
Sign up to get free protection for your applications and to get access to all the features.
- 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
|