ruby-cute 0.3 → 0.4

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.
@@ -36,3 +36,19 @@ class String
36
36
  end
37
37
 
38
38
  end
39
+
40
+ module Cute
41
+
42
+ class OARSSHopts < Hash
43
+
44
+ def initialize(opts={})
45
+
46
+ raise "The argument must be a Hash" unless opts.is_a?(Hash)
47
+ self.merge!({:user => "oar", :keys => ["~/my_ssh_jobkey"], :port => 6667 })
48
+ self.merge!(opts)
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
data/lib/cute/g5k_api.rb CHANGED
@@ -211,7 +211,9 @@ module Cute
211
211
 
212
212
  machine =`uname -ov`.chop
213
213
  @user_agent = "ruby-cute/#{VERSION} (#{machine}) Ruby #{RUBY_VERSION}"
214
- @api = RestClient::Resource.new(@endpoint, :timeout => 30)
214
+ @api = RestClient::Resource.new(@endpoint, :timeout => 30,:verify_ssl => false)
215
+ # some versions of restclient do not verify by default SSL certificates , :verify_ssl => true)
216
+ # SSL verify is disabled due to Grid'5000 API certificate problem
215
217
  @on_error = on_error
216
218
  test_connection
217
219
  end
@@ -280,6 +282,12 @@ module Cute
280
282
 
281
283
  # Issues a Cute::G5K exception according to the http status code
282
284
  def handle_exception(e)
285
+
286
+ unless e.respond_to? :http_code
287
+ raise e
288
+ end
289
+
290
+ # Handling G5k API errors
283
291
  case e.http_code
284
292
  when 500
285
293
  # This part deals with bug: https://intranet.grid5000.fr/bugzilla/show_bug.cgi?id=5912
@@ -484,8 +492,8 @@ module Cute
484
492
  # @option params [String] :conf_file Path for configuration file
485
493
  # @option params [String] :uri REST API URI to contact
486
494
  # @option params [String] :version Version of the REST API to use
487
- # @option params [String] :user Username to access the REST API
488
- # @option params [String] :pass Password to access the REST API
495
+ # @option params [String] :username Username to access the REST API
496
+ # @option params [String] :password Password to access the REST API
489
497
  # @option params [Symbol] :on_error Set to :ignore if you want to ignore {Cute::G5K::RequestFailed ResquestFailed} exceptions.
490
498
  def initialize(params={})
491
499
  config = {}
@@ -495,16 +503,20 @@ module Cute
495
503
  params[:conf_file] = default_file if File.exist?(default_file)
496
504
  end
497
505
 
506
+ params[:username] ||= params[:user]
507
+ params[:password] ||= params[:pass] # backward compatibility
508
+
498
509
  config = YAML.load(File.open(params[:conf_file],'r')) unless params[:conf_file].nil?
499
- @user = params[:user] || config["username"]
500
- @pass = params[:pass] || config["password"]
510
+ @user = params[:username] || config["username"]
511
+ @pass = params[:password] || config["password"]
501
512
  @uri = params[:uri] || config["uri"]
502
513
  @api_version = params[:version] || config["version"] || "sid"
503
514
  @logger = nil
504
515
 
505
516
  begin
506
517
  @g5k_connection = G5KRest.new(@uri,@api_version,@user,@pass,params[:on_error])
507
- rescue
518
+ rescue => e
519
+
508
520
  msg_create_file = ""
509
521
  if (not File.exist?(default_file)) && params[:conf_file].nil? then
510
522
  msg_create_file = "Please create the file: ~/.grid5000_api.yml and
@@ -512,7 +524,9 @@ module Cute
512
524
  :conf_file to indicate another file for the credentials"
513
525
  end
514
526
  raise "Unable to authorize against the Grid'5000 API.
515
- #{msg_create_file}"
527
+ #{e.message}
528
+ #{msg_create_file}"
529
+
516
530
 
517
531
  end
518
532
  end
@@ -656,7 +670,8 @@ module Cute
656
670
  .map { |x| "#{x}.#{site}.grid5000.fr"}
657
671
  switch['nodes'] = nodes
658
672
  }
659
- return items.select { |it| it.key?('nodes') }
673
+
674
+ return items
660
675
  end
661
676
 
662
677
  # @return [Hash] information of a specific switch available in a given Grid'5000 site.
@@ -668,6 +683,37 @@ module Cute
668
683
  return s
669
684
  end
670
685
 
686
+ # Returns information using the Metrology API.
687
+ #
688
+ # = Example
689
+ #
690
+ # You can get detailed information of available metrics in a given site:
691
+ # get_metric("rennes")
692
+ #
693
+ # If you are only interested in the names of the available metrics:
694
+ # get_metric("rennes").uids #=> ["cpu_nice", "boottime", "bytes_in", ...]
695
+ #
696
+ # Then, you can get information about the probes available for a specific metric:
697
+ # get_metric("rennes",:metric => "network_in")
698
+ #
699
+ # Finally, you can query on a specific probe:
700
+ # get_metric("rennes",:metric => "network_in",:query => {:from => 1450374553, :to => 1450374553, :only => "parasilo-11-eth0"})
701
+ #
702
+ # @return [Array] information of a specific metric in a given Grid'5000 site.
703
+ # @param site [String] a valid Grid'5000 site name
704
+ # @param [Hash] opts Options for metric query
705
+ # @option opts [String] :metric specific metric to query on
706
+ # @option opts [Hash] :query timeseries parameters (e.g. only, resolution, from, to)
707
+
708
+ def get_metric(site,opts ={})
709
+ params = opts[:metric].nil? ? "" : "/#{opts[:metric]}/timeseries"
710
+ if opts[:query]
711
+ params+="?"
712
+ opts[:query].each{ |k,v| params+="#{k}=#{v}&"}
713
+ end
714
+ @g5k_connection.get_json(api_uri("sites/#{site}/metrics#{params}")).items
715
+ end
716
+
671
717
  # Returns information of all my jobs submitted in a given site.
672
718
  # By default it only shows the jobs in state *running*.
673
719
  # You can specify another state like this:
@@ -835,6 +881,7 @@ module Cute
835
881
  # @option opts [String] :name Reservation name
836
882
  # @option opts [String] :cmd The command to execute when the job starts (e.g. ./my-script.sh).
837
883
  # @option opts [String] :cluster Valid Grid'5000 cluster
884
+ # @option opts [String] :queue A specific job queue
838
885
  # @option opts [Array] :subnets 1) prefix_size, 2) number of subnets
839
886
  # @option opts [String] :env Environment name for {http://kadeploy3.gforge.inria.fr/ Kadeploy}
840
887
  # @option opts [Symbol] :vlan Vlan type: :routed, :local, :global
@@ -847,7 +894,8 @@ module Cute
847
894
 
848
895
  # checking valid options
849
896
  valid_opts = [:site, :cluster, :switches, :cpus, :cores, :nodes, :walltime, :cmd,
850
- :type, :name, :subnets, :env, :vlan, :properties, :resources, :reservation, :wait, :keys]
897
+ :type, :name, :subnets, :env, :vlan, :properties, :resources,
898
+ :reservation, :wait, :keys, :queue, :env_user]
851
899
  unre_opts = opts.keys - valid_opts
852
900
  raise ArgumentError, "Unrecognized option #{unre_opts}" unless unre_opts.empty?
853
901
 
@@ -868,6 +916,7 @@ module Cute
868
916
  resources = opts.fetch(:resources, "")
869
917
  type = :deploy if opts[:env]
870
918
  keys = opts[:keys]
919
+ queue = opts[:queue]
871
920
 
872
921
  vlan_opts = {:routed => "kavlan",:global => "kavlan-global",:local => "kavlan-local"}
873
922
  vlan = nil
@@ -881,11 +930,11 @@ module Cute
881
930
 
882
931
  raise 'At least nodes, time and site must be given' if [nodes, walltime, site].any? { |x| x.nil? }
883
932
 
933
+ raise 'nodes should be an integer or a string containing either ALL or BEST' unless (nodes.is_a?(Fixnum) or ["ALL","BEST"].include?(nodes))
934
+
884
935
  secs = walltime.to_secs
885
936
  walltime = walltime.to_time
886
937
 
887
- raise 'Nodes must be an integer.' unless nodes.is_a?(Integer)
888
-
889
938
  command = "sleep #{secs}" if command.nil?
890
939
  type = type.to_sym unless type.nil?
891
940
 
@@ -911,6 +960,7 @@ module Cute
911
960
 
912
961
  payload['properties'] = properties unless properties.nil?
913
962
  payload['types'] = [ type.to_s ] unless type.nil?
963
+ payload['queue'] = queue if queue
914
964
 
915
965
  if not type == :deploy
916
966
  if opts[:keys]
@@ -930,8 +980,7 @@ module Cute
930
980
  # The request has to be redirected to the OAR API given that Grid'5000 API
931
981
  # does not support some OAR options.
932
982
  if payload['import-job-key-from-file'] then
933
- # Adding double quotes otherwise we have a syntax error from OAR API
934
- payload["resources"] = "\"#{payload["resources"]}\""
983
+
935
984
  temp = @g5k_connection.post_json(api_uri("sites/#{site}/internal/oarapi/jobs"),payload)
936
985
  sleep 1 # This is for being sure that our job appears on the list
937
986
  r = get_my_jobs(site,nil).select{ |j| j["uid"] == temp["id"] }.first
@@ -1035,7 +1084,8 @@ module Cute
1035
1084
 
1036
1085
  # checking valid options, same as reserve option even though some option dont make any sense
1037
1086
  valid_opts = [:site, :cluster, :switches, :cpus, :cores, :nodes, :walltime, :cmd,
1038
- :type, :name, :subnets, :env, :vlan, :properties, :resources, :reservation, :wait, :keys]
1087
+ :type, :name, :subnets, :env, :vlan, :properties, :resources,
1088
+ :reservation, :wait, :keys, :queue, :env_user]
1039
1089
 
1040
1090
  unre_opts = opts.keys - valid_opts
1041
1091
  raise ArgumentError, "Unrecognized option #{unre_opts}" unless unre_opts.empty?
@@ -1069,6 +1119,8 @@ module Cute
1069
1119
  info "Found VLAN with uid = #{vlan}"
1070
1120
  end
1071
1121
 
1122
+ payload['user'] = opts[:env_user] unless opts[:env_user].nil?
1123
+
1072
1124
  info "Creating deployment"
1073
1125
 
1074
1126
  begin
@@ -1135,9 +1187,10 @@ module Cute
1135
1187
  #
1136
1188
  # g5k = Cute::G5K::API.new()
1137
1189
  #
1138
- # job = g5k.reserve(:nodes => 1, :site => 'lyon', :env => 'wheezy-x64-base')
1190
+ # job = g5k.reserve(:nodes => 1, :site => 'lyon', :type => :deploy)
1139
1191
  #
1140
1192
  # begin
1193
+ # g5k.deploy(job,:env => 'wheezy-x64-base')
1141
1194
  # g5k.wait_for_deploy(job,:wait_time => 100)
1142
1195
  # rescue Cute::G5K::EventTimeout
1143
1196
  # puts "We waited too long let's release the job"
@@ -1171,6 +1224,20 @@ module Cute
1171
1224
 
1172
1225
  end
1173
1226
 
1227
+ # It returns an array of machines that did not deploy successfully
1228
+ # = Example
1229
+ # It can be used to try a new deploy:
1230
+ #
1231
+ # badnodes = g5k.check_deployment(job["deploy"].last)
1232
+ # g5k.deploy(job,:nodes => badnodes, :env => 'wheezy-x64-base')
1233
+ # g5k.wait_for_deploy(job)
1234
+ #
1235
+ # @return [Array] machines that did not deploy successfully
1236
+ # @param deploy_info [Hash] deployment structure information
1237
+ def check_deployment(deploy_info)
1238
+ deploy_info["result"].select{ |p,v| v["state"] == "KO"}.keys
1239
+ end
1240
+
1174
1241
  private
1175
1242
  # Handles the output of messages within the module
1176
1243
  # @param msg [String] message to show
@@ -34,7 +34,7 @@ module Cute
34
34
  def release(n = 1)
35
35
  @lock.synchronize {
36
36
  @used -= n
37
- @cond.signal
37
+ @cond.broadcast
38
38
  }
39
39
  end
40
40
  end
data/lib/cute/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cute
2
- VERSION = "0.3"
2
+ VERSION = "0.4"
3
3
  end
data/spec/g5k_api_spec.rb CHANGED
@@ -73,6 +73,10 @@ describe Cute::G5K::API do
73
73
  # expect{ subject.reserve(:site => @rand_site, :resources =>"{ib30g='YES'}/nodes=2")}.to raise_error(Cute::G5K::BadRequest)
74
74
  end
75
75
 
76
+ it "raises a bad request using OAR API" do
77
+ expect{subject.reserve(:site => @rand_site, :resources =>"nodes=1",:keys => "~/jobkey_nonexisting")}.to raise_error(Cute::G5K::BadRequest)
78
+ end
79
+
76
80
  it "raises an exception at deploying" do
77
81
  expect{ subject.reserve(:site => @rand_site, :nodes => 1, :env => "nonsense")}.to raise_error(Cute::G5K::RequestFailed)
78
82
  end
@@ -126,7 +130,7 @@ describe Cute::G5K::API do
126
130
  end
127
131
 
128
132
  it "performs an advanced reservation" do
129
- time_schedule = Time.now + 60*20
133
+ time_schedule = Time.now + 60*10
130
134
  job =subject.reserve(:site => @rand_site, :nodes => 1, :reservation => time_schedule.strftime("%Y-%m-%d %H:%M:%S"))
131
135
  subject.release(job)
132
136
  end
@@ -137,7 +141,6 @@ describe Cute::G5K::API do
137
141
  subject.release(job)
138
142
  end
139
143
 
140
-
141
144
  it "does not deploy immediately" do
142
145
  job = subject.reserve(:site => @rand_site, :type => :deploy )
143
146
  expect(job).to include("types" => ["deploy"])
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,8 @@ require 'webmock/rspec'
3
3
 
4
4
  SimpleCov.start
5
5
  # The SimpleCov.start must be issued before any of the application code is required!
6
+ # SimpleCov hacks $:, so it needs to be re-configured here, before cute is loaded.
7
+ $:.unshift File.expand_path("../../lib", __FILE__)
6
8
  require 'cute'
7
9
 
8
10
  # Disabling all external requests
@@ -57,6 +59,10 @@ RSpec.configure do |config|
57
59
  with(:body => hash_including("resources" => "/slash_22=1+{nonsense},walltime=01:00")).
58
60
  to_return(:status => 400, :body => "Oarsub failed: please verify your request syntax")
59
61
 
62
+ stub_request(:post, /^https:\/\/.*\:.*@api.grid5000.fr\/.*/).
63
+ with(:body => hash_including("import-job-key-from-file" => [ File.expand_path("~/jobkey_nonexisting") ])).
64
+ to_return(:status => 400, :body => "Oarsub failed: please verify your request syntax")
65
+
60
66
  stub_request(:post, /^https:\/\/.*\:.*@api.grid5000.fr\/.*/).
61
67
  with(:body => hash_including("environment" => "nonsense")).
62
68
  to_return(:status => 500, :body => "Invalid environment specification")
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.3'
4
+ version: '0.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Algorille team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-13 00:00:00.000000000 Z
11
+ date: 2016-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -191,6 +191,7 @@ files:
191
191
  - debian/source/format
192
192
  - debian/watch
193
193
  - examples/distem-bootstrap
194
+ - examples/g5k-tutorial.md
194
195
  - examples/g5k_exp1.rb
195
196
  - examples/g5k_exp_virt.rb
196
197
  - lib/cute.rb
@@ -231,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
232
  version: 1.3.6
232
233
  requirements: []
233
234
  rubyforge_project:
234
- rubygems_version: 2.2.2
235
+ rubygems_version: 2.4.5.1
235
236
  signing_key:
236
237
  specification_version: 4
237
238
  summary: Critically Useful Tools for Experiments