ruby-cute 0.5 → 0.6

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: 1bcde24cec062bee7628aff6089b9a146c46be33
4
- data.tar.gz: 4398bc96b38dca6b342118828649b766dcb1550b
3
+ metadata.gz: 4bee03262cac39274dd43426589fce86de6962eb
4
+ data.tar.gz: b0262a03d84c76f2557550f4a0c05bcefc7c2a09
5
5
  SHA512:
6
- metadata.gz: 97d07be46381ca5ccca6c531eba4f8bbef52038ea0cce3d0acba250cd8d7505c5ef8f8ff7311b19d979cff04bf7c9f4f96b9c2c4175ad0852ae8454dcfaf2639
7
- data.tar.gz: 960f749e351f01142c235620df0c7cef5d210dfbf620ac2900939c3a04f7e997c639315f9941d5b6e7a79e0b4427474f37839a0aefa3d5f85976dc78df6b5052
6
+ metadata.gz: 2241ac02410656a7dbf16006d2f28ea9d02767e1b4e395fc0861798e6891eb60d60ede93b7899d87f86fc3dbe355da0071a8e591760f828b5a6e14737f8011b2
7
+ data.tar.gz: ab9c2570faf491c33759ecd1317cf574b3e4779b86df251986b2456d50ba3b22eac475bc9af04e2017d278044f83bf0497f58ac6fb602ecc0be72f8f643f5a4e
data/README.md CHANGED
@@ -27,6 +27,21 @@ Then, type the following for having ruby cute in your path (this is only necessa
27
27
  ```bash
28
28
  $ export PATH=$PATH:$(ruby -e 'puts "#{Gem.user_dir}/bin"')
29
29
  ```
30
+ If you want to use Ruby-Cute outside Grid'5000 you need to create a configuration file with your credentials.
31
+ By default you need to create a file called *.grid5000_api.yml* located in your home directory:
32
+
33
+ ```bash
34
+
35
+ $ cat > ~/.grid5000_api.yml << EOF
36
+ uri: https://api.grid5000.fr/
37
+ username: user
38
+ password: **********
39
+ version: sid
40
+ EOF
41
+
42
+ ```
43
+
44
+ For more details have a look at [G5K Module](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/G5K/API).
30
45
 
31
46
  ## Overview
32
47
 
data/debian/changelog CHANGED
@@ -1,3 +1,9 @@
1
+ ruby-cute (0.6) UNRELEASED; urgency=medium
2
+
3
+ * New release.
4
+
5
+ -- Cristian Ruiz <cristian.ruiz@inria.fr> Thu, 20 Oct 2016 10:57:07 +0100
6
+
1
7
  ruby-cute (0.5) UNRELEASED; urgency=medium
2
8
 
3
9
  * New release.
@@ -199,8 +199,8 @@ A hash is returned containing all the information about the job that we have jus
199
199
  "directory"=>"/home/cruizsanabria",
200
200
  "events"=>[],
201
201
  "links"=>
202
- [{"rel"=>"self", "href"=>"/sid/sites/nancy/jobs/692665", "type"=>"application/vnd.grid5000.item+json"},
203
- {"rel"=>"parent", "href"=>"/sid/sites/nancy", "type"=>"application/vnd.grid5000.item+json"}],
202
+ [{"rel"=>"self", "href"=>"/3.0/sites/nancy/jobs/692665", "type"=>"application/vnd.grid5000.item+json"},
203
+ {"rel"=>"parent", "href"=>"/3.0/sites/nancy", "type"=>"application/vnd.grid5000.item+json"}],
204
204
  "resources_by_type"=>{"cores"=>["graphene-67.nancy.grid5000.fr", "graphene-45.nancy.grid5000.fr"]},
205
205
  "assigned_nodes"=>["graphene-67.nancy.grid5000.fr", "graphene-45.nancy.grid5000.fr"]}
206
206
 
@@ -751,7 +751,7 @@ In this variable, we can find information related with the deployment.
751
751
  [44] pry(main)> jobs["nancy"]["deploy"]
752
752
  => [{"created_at"=>1450439620,
753
753
  "environment"=>"jessie-x64-min",
754
- "key"=>"https://api.grid5000.fr/sid/sites/nancy/files/cruizsanabria-key-84f3f1dbb1279bc1bddcd618e26c960307d653c5",
754
+ "key"=>"https://api.grid5000.fr/3.0/sites/nancy/files/cruizsanabria-key-84f3f1dbb1279bc1bddcd618e26c960307d653c5",
755
755
  "nodes"=>["graphite-4.nancy.grid5000.fr"],
756
756
  "result"=>{"graphite-4.nancy.grid5000.fr"=>{"macro"=>nil, "micro"=>nil, "state"=>"OK"}},
757
757
  "site_uid"=>"nancy",
@@ -761,8 +761,8 @@ In this variable, we can find information related with the deployment.
761
761
  "user_uid"=>"cruizsanabria",
762
762
  "vlan"=>14,
763
763
  "links"=>
764
- [{"rel"=>"self", "href"=>"/sid/sites/nancy/deployments/D-b026879e-b185-4e20-8bc5-ea0842a6954b", "type"=>"application/vnd.grid5000.item+json"},
765
- {"rel"=>"parent", "href"=>"/sid/sites/nancy", "type"=>"application/vnd.grid5000.item+json"}]}]
764
+ [{"rel"=>"self", "href"=>"/3.0/sites/nancy/deployments/D-b026879e-b185-4e20-8bc5-ea0842a6954b", "type"=>"application/vnd.grid5000.item+json"},
765
+ {"rel"=>"parent", "href"=>"/3.0/sites/nancy", "type"=>"application/vnd.grid5000.item+json"}]}]
766
766
 
767
767
  Some important information are: the status of the whole process and the state per node.
768
768
  We can use this information to check if the deployment have finished successfully in all nodes.
data/lib/cute/g5k_api.rb CHANGED
@@ -116,8 +116,8 @@ module Cute
116
116
  # "properties"=>"(deploy = 'YES') AND maintenance = 'NO'",
117
117
  # "directory"=>"/home/name",
118
118
  # "events"=>[],
119
- # "links"=>[{"rel"=>"self", "href"=>"/sid/sites/nancy/jobs/604692", "type"=>"application/vnd.grid5000.item+json"},
120
- # {"rel"=>"parent", "href"=>"/sid/sites/nancy", "type"=>"application/vnd.grid5000.item+json"}],
119
+ # "links"=>[{"rel"=>"self", "href"=>"/3.0/sites/nancy/jobs/604692", "type"=>"application/vnd.grid5000.item+json"},
120
+ # {"rel"=>"parent", "href"=>"/3.0/sites/nancy", "type"=>"application/vnd.grid5000.item+json"}],
121
121
  # "resources_by_type"=>
122
122
  # {"cores"=>
123
123
  # ["griffon-8.nancy.grid5000.fr",
@@ -137,7 +137,7 @@ module Cute
137
137
  # "deploy"=>
138
138
  # {"created_at"=>1423575401,
139
139
  # "environment"=>"http://public.sophia.grid5000.fr/~nniclausse/openmx.dsc",
140
- # "key"=>"https://api.grid5000.fr/sid/sites/nancy/files/cruizsanabria-key-84f3f1dbb1279bc1bddcd618e26c960307d653c5",
140
+ # "key"=>"https://api.grid5000.fr/3.0/sites/nancy/files/cruizsanabria-key-84f3f1dbb1279bc1bddcd618e26c960307d653c5",
141
141
  # "nodes"=>["griffon-8.nancy.grid5000.fr", "griffon-9.nancy.grid5000.fr", "griffon-77.nancy.grid5000.fr"],
142
142
  # "site_uid"=>"nancy",
143
143
  # "status"=>"processing",
@@ -146,7 +146,7 @@ module Cute
146
146
  # "user_uid"=>"cruizsanabria",
147
147
  # "vlan"=>5,
148
148
  # "links"=>
149
- # [{"rel"=>"self", "href"=>"/sid/sites/nancy/deployments/D-751096de-0c33-461a-9d27-56be1b2dd980", "type"=>"application/vnd.grid5000.item+json"},
149
+ # [{"rel"=>"self", "href"=>"/3.0/sites/nancy/deployments/D-751096de-0c33-461a-9d27-56be1b2dd980", "type"=>"application/vnd.grid5000.item+json"},
150
150
  class G5KJSON < Hash
151
151
 
152
152
  def items
@@ -259,8 +259,8 @@ module Cute
259
259
  def delete_json(path)
260
260
  begin
261
261
  return resource(path).delete()
262
- rescue RestClient::InternalServerError => e
263
- raise RequestFailed.new("Service internal error", e)
262
+ rescue => e
263
+ handle_exception(e)
264
264
  end
265
265
  end
266
266
 
@@ -281,7 +281,15 @@ module Cute
281
281
  end
282
282
 
283
283
  # Issues a Cute::G5K exception according to the http status code
284
- def handle_exception(e)
284
+ def handle_exception(e, req = nil)
285
+ puts("Error: #{$!}")
286
+ puts("Backtrace:\n\t"+e.backtrace.join("\n\t"))
287
+ if e.respond_to? :http_code
288
+ puts("HTTP Code: #{e.http_code}")
289
+ end
290
+ if e.respond_to? :response and e.response != ''
291
+ puts("Response: #{e.response}")
292
+ end
285
293
 
286
294
  unless e.respond_to? :http_code
287
295
  raise e
@@ -309,18 +317,17 @@ module Cute
309
317
 
310
318
  # This class helps you to access Grid'5000 REST API.
311
319
  # Thus, the most common actions such as reservation of nodes and deployment can be easily scripted.
312
- # To simplify the use of the module, it is better to create a file with the following information:
320
+ # If you are using this module outside Grid'5000 you should created a configuration file with
321
+ # the following contents:
313
322
  #
314
323
  # $ cat > ~/.grid5000_api.yml << EOF
315
324
  # uri: https://api.grid5000.fr/
316
325
  # username: user
317
326
  # password: **********
318
- # version: sid
327
+ # version: stable
319
328
  # EOF
320
329
  #
321
- # The *username* and *password* are not necessary if you are using the module from inside Grid'5000.
322
- # You can take a look at the {Cute::G5K::API#initialize G5K::API constructor} to see more details of
323
- # this configuration.
330
+ # You can take a look at the {Cute::G5K::API#initialize G5K::API constructor} to see more details of this configuration.
324
331
  #
325
332
  # = Getting started
326
333
  #
@@ -368,9 +375,11 @@ module Cute
368
375
  # you can specify another path for your keys with the option *:keys*.
369
376
  # In order to deploy your own environment, you have to put the tar file that contains the operating system you want to deploy and
370
377
  # the environment description file, under the public directory of a given site.
371
- # *VLANS* are supported by adding the parameter :vlan => type where type can be: *:routed*, *:local*, *:global*.
378
+ # *VLANS* are supported by adding the parameter :vlan => type where type can be: *kavlan*, *kavlan-global*, *kavlan-local*.
372
379
  # The following example, reserves 10 nodes in the Lille site, starts the deployment of a custom environment over the nodes
373
- # and puts the nodes under a routed VLAN. We used the method {Cute::G5K::API#get_vlan_nodes get_vlan_nodes} to get the
380
+ # and puts the nodes under a routed VLAN. The different types of VLANs are described
381
+ # in {https://www.grid5000.fr/mediawiki/index.php/KaVLAN KaVLAN}
382
+ # We used the method {Cute::G5K::API#get_vlan_nodes get_vlan_nodes} to get the
374
383
  # new hostnames assigned to your nodes.
375
384
  #
376
385
  # require 'cute'
@@ -378,12 +387,14 @@ module Cute
378
387
  # g5k = Cute::G5K::API.new()
379
388
  #
380
389
  # job = g5k.reserve(:site => "lille", :nodes => 10,
381
- # :env => 'https://public.lyon.grid5000.fr/~user/debian_custom_img.yaml',
382
- # :vlan => :routed, :keys => "~/my_ssh_key")
390
+ # :env => 'http://public.lyon.grid5000.fr/~user/debian_custom_img.yaml',
391
+ # :vlan => "kavlan", :keys => "~/my_ssh_key")
383
392
  #
384
393
  #
385
394
  # puts "Log in into the nodes using the following hostnames: #{g5k.get_vlan_nodes(job)}"
386
395
  #
396
+ # You should make sure when using custom environments that in the Kadeploy description file, you use an URL to specify the path to the tarball.
397
+ # Otherwise, you will get the error 'Invalid client's export'.
387
398
  # If you do not want that the method {Cute::G5K::API#reserve reserve} perform the deployment for you, you have to use the option :type => :deploy.
388
399
  # This can be useful when deploying different environments in your reserved nodes, for example: deploying the environments for a small HPC cluster.
389
400
  # You have to use the method {Cute::G5K::API#deploy deploy} for performing the deploy.
@@ -401,8 +412,8 @@ module Cute
401
412
  # slaves = nodes[1..4]
402
413
  # master = nodes-slaves
403
414
  #
404
- # g5k.deploy(job,:nodes => master, :env => 'https://public.lyon.grid5000.fr/~user/debian_master_img.yaml')
405
- # g5k.deploy(job,:nodes => slaves, :env => 'https://public.lyon.grid5000.fr/~user/debian_slaves_img.yaml')
415
+ # g5k.deploy(job,:nodes => master, :env => 'http://public.lyon.grid5000.fr/~user/debian_master_img.yaml')
416
+ # g5k.deploy(job,:nodes => slaves, :env => 'http://public.lyon.grid5000.fr/~user/debian_slaves_img.yaml')
406
417
  #
407
418
  # g5k.wait_for_deploy(job)
408
419
  #
@@ -450,6 +461,14 @@ module Cute
450
461
  #
451
462
  # [12] pry(main)> $g5k.release(job)
452
463
  # [13] pry(main)> $g5k.release_all("grenoble")
464
+ # == How to debug
465
+ #
466
+ # There are two ways for debugging: (1) by using the option *:debug* when initializing the {Cute::G5K::API#initialize G5K::API} object or
467
+ # (2) by enabling the RestClient's logging:
468
+ #
469
+ # RESTCLIENT_LOG=stdout cute
470
+ # RESTCLIENT_LOG=stdout path/to/my/script
471
+ #
453
472
  class API
454
473
 
455
474
  # Assigns a logger
@@ -480,6 +499,15 @@ module Cute
480
499
  #
481
500
  # g5k = Cute::G5K::API.new(:on_error => :ignore)
482
501
  #
502
+ # To activate debugging mode you can use the option *:debug*:
503
+ #
504
+ # g5k = Cute::G5K::API.new(:debug => true)
505
+ #
506
+ # This will provide you with a *curl* command to try by hand the same request the library is trying to perform.
507
+ # For example:
508
+ #
509
+ # 2016-09-27 11:25:34.039 => CMD debug: curl -kn https://api.grid5000.fr/3.0/sites/nancy/deployments/?user=cruizsanabria
510
+ #
483
511
  # @param [Hash] params Contains initialization parameters.
484
512
  # @option params [String] :conf_file Path for configuration file
485
513
  # @option params [String] :uri REST API URI to contact
@@ -487,6 +515,7 @@ module Cute
487
515
  # @option params [String] :username Username to access the REST API
488
516
  # @option params [String] :password Password to access the REST API
489
517
  # @option params [Symbol] :on_error Set to :ignore if you want to ignore {Cute::G5K::RequestFailed ResquestFailed} exceptions.
518
+ # @option params [Boolean] :debug Activate the debug mode
490
519
  def initialize(params={})
491
520
  config = {}
492
521
  default_file = "#{ENV['HOME']}/.grid5000_api.yml"
@@ -504,6 +533,7 @@ module Cute
504
533
  @uri = params[:uri] || config["uri"] || "https://api.grid5000.fr/"
505
534
  @api_version = params[:version] || config["version"] || "stable"
506
535
  @logger = nil
536
+ @debug = params[:debug] || false
507
537
 
508
538
  begin
509
539
  @g5k_connection = G5KRest.new(@uri,@api_version,@user,@pass,params[:on_error])
@@ -524,7 +554,7 @@ module Cute
524
554
  end
525
555
 
526
556
  # It returns the site name. Example:
527
- # site #=> "rennes"
557
+ # site #=> "rennes"
528
558
  # This will only work when {Cute::G5K::API G5K::API} is used within Grid'5000.
529
559
  # In the other cases it will return *nil*
530
560
  # @return [String] the site name where the method is called on
@@ -534,7 +564,15 @@ module Cute
534
564
  res[1] unless res.nil?
535
565
  end
536
566
 
537
- # @api private
567
+ # It returns the RestClient::Resource object which provides you the *get_json* and *post_json* methods. This enables to perform low level REST requests.
568
+ # This method is intended to be used along with the {G5K::API#api_uri api_uri} method for generating valid URI.
569
+ #
570
+ # = Example:
571
+ # require 'cute'
572
+ #
573
+ # g5k = Cute::G5K::API.new()
574
+ # g5k.rest.get_json(g5k.api_uri("/sites/grenoble/clusters")
575
+ #
538
576
  # @return the rest point for performing low level REST requests
539
577
  def rest
540
578
  @g5k_connection
@@ -586,6 +624,7 @@ module Cute
586
624
  # @return [Hash] all the status information of a given Grid'5000 site
587
625
  # @param site [String] a valid Grid'5000 site name
588
626
  def site_status(site)
627
+ info(debug_cmd(api_uri("sites/#{site}/status"),"GET"), :debug)
589
628
  @g5k_connection.get_json(api_uri("sites/#{site}/status"))
590
629
  end
591
630
 
@@ -642,6 +681,7 @@ module Cute
642
681
  # @param site [String] a valid Grid'5000 site name
643
682
  # @param uid [String] user name in Grid'5000
644
683
  def get_deployments(site, uid = nil)
684
+ info(debug_cmd(api_uri("sites/#{site}/deployments/?user=#{uid}"),"GET"), :debug)
645
685
  @g5k_connection.get_json(api_uri("sites/#{site}/deployments/?user=#{uid}")).items
646
686
  end
647
687
 
@@ -649,12 +689,14 @@ module Cute
649
689
  # @param site [String] a valid Grid'5000 site name
650
690
  # @param jid [Fixnum] a valid job identifier
651
691
  def get_job(site, jid)
692
+ info(debug_cmd(api_uri("/sites/#{site}/jobs/#{jid}"),"GET"), :debug)
652
693
  @g5k_connection.get_json(api_uri("/sites/#{site}/jobs/#{jid}"))
653
694
  end
654
695
 
655
696
  # @return [Hash] switches information available in a given Grid'5000 site.
656
697
  # @param site [String] a valid Grid'5000 site name
657
698
  def get_switches(site)
699
+ info(debug_cmd(api_uri("/sites/#{site}/network_equipments"),"GET"), :debug)
658
700
  items = @g5k_connection.get_json(api_uri("/sites/#{site}/network_equipments")).items
659
701
  items = items.select { |x| x['kind'] == 'switch' }
660
702
  # extract nodes connected to those switches
@@ -688,7 +730,7 @@ module Cute
688
730
  # get_metric("rennes")
689
731
  #
690
732
  # If you are only interested in the names of the available metrics:
691
- # get_metric("rennes").uids #=> ["cpu_nice", "boottime", "bytes_in", ...]
733
+ # get_metric("rennes").uids #=> ["cpu_nice", "boottime", "bytes_in", ...]
692
734
  #
693
735
  # Then, you can get information about the probes available for a specific metric:
694
736
  # get_metric("rennes",:metric => "network_in")
@@ -708,6 +750,7 @@ module Cute
708
750
  params+="?"
709
751
  opts[:query].each{ |k,v| params+="#{k}=#{v}&"}
710
752
  end
753
+ info debug_cmd(api_uri("sites/#{site}/metrics#{params}"),"GET"), :debug
711
754
  @g5k_connection.get_json(api_uri("sites/#{site}/metrics#{params}")).items
712
755
  end
713
756
 
@@ -718,7 +761,7 @@ module Cute
718
761
  # = Examples
719
762
  # get_my_jobs("nancy", "waiting")
720
763
  # Getting several states:
721
- # get_my_jobs("nancy", ["waiting","running"])
764
+ # get_my_jobs("nancy", ["waiting","running"])
722
765
  # Valid states are specified in {https://api.grid5000.fr/doc/4.0/reference/spec.html Grid'5000 API spec}
723
766
  # @return [Array] all my submitted jobs to a given site and their associated deployments.
724
767
  # @param site [String] a valid Grid'5000 site name
@@ -828,15 +871,23 @@ module Cute
828
871
  # If walltime is not specified, 1 hour walltime will be assigned to the reservation.
829
872
  #
830
873
  # job = g5k.reserve(:site => 'lille', :cluster => 'chirloute', :nodes => 2,
831
- # :env => 'wheezy-x64-xen', :keys => "~/my_ssh_jobkey",
874
+ # :env => 'wheezy-x64-xen', :keys => "path/to/my_ssh_jobkey",
832
875
  # :subnets => [22,2])
833
876
  #
877
+ # == Multiple types
878
+ #
879
+ # The option *:type* accepts an array for specifying multiple types.
880
+ # For example, if we want to submit a job deploy and destructive, we will type:
881
+ #
882
+ # job = g5k.reserve(:site => "nancy", :nodes => 1, :walltime => "2:00:00", :type => [:deploy,:destructive])
883
+ #
834
884
  # == Before using OAR hierarchy
835
885
  # All non-deploy reservations are submitted by default with the OAR option "-allow_classic_ssh"
836
886
  # which does not take advantage of the CPU/core management level.
837
887
  # Therefore, in order to take advantage of this capability, SSH keys have to be specified at the moment of reserving resources.
838
888
  # This has to be used whenever we perform a reservation with cpu and core hierarchy.
839
- # Users are encouraged to create a pair of SSH keys for managing jobs, for instance the following command can be used:
889
+ # Given that OAR needs access to both keys private and public users are encouraged
890
+ # to create a pair of SSH keys for managing jobs, for instance the following command can be used:
840
891
  #
841
892
  # ssh-keygen -N "" -t rsa -f ~/my_ssh_jobkey
842
893
  #
@@ -844,8 +895,11 @@ module Cute
844
895
  # You have to specify different keys per reservation if you want several jobs running at the same time in the same site.
845
896
  # Example using the OAR hierarchy:
846
897
  #
847
- # job = g5k.reserve(:site => "grenoble", :switches => 3, :nodes => 1, :cpus => 1, :cores => 1, :keys => "~/my_ssh_jobkey")
898
+ # job = g5k.reserve(:site => "grenoble", :switches => 3, :nodes => 1, :cpus => 1, :cores => 1, :keys => "path/to/my_ssh_jobkey")
848
899
  #
900
+ # Remember that the path passed in the *:keys* parameter corresponds to the path in the Grid'5000 site frontend where you are submitting the job.
901
+ # This is because OAR needs to access to both keys (private and public) locally.
902
+ # For deployments the path corresponds to the local path from where the script is being executed (See {Cute::G5K::API#deploy deploy} method).
849
903
  # == Using OAR syntax
850
904
  #
851
905
  # The parameter *:resources* can be used instead of parameters such as: *:cluster*, *:nodes*, *:cpus*, *:walltime*, *:vlan*, *:subnets*, *:properties*, etc,
@@ -879,14 +933,15 @@ module Cute
879
933
  # @option opts [Numeric] :nodes Number of nodes to reserve
880
934
  # @option opts [String] :walltime Walltime of the reservation
881
935
  # @option opts [String] :site Grid'5000 site
882
- # @option opts [Symbol] :type Type of reservation: :deploy, :allow_classic_ssh
936
+ # @option opts [Array or Symbol] :type Type of reservation: :deploy, :allow_classic_ssh, [:deploy,:destructive]
883
937
  # @option opts [String] :name Reservation name
884
938
  # @option opts [String] :cmd The command to execute when the job starts (e.g. ./my-script.sh).
885
939
  # @option opts [String] :cluster Valid Grid'5000 cluster
886
940
  # @option opts [String] :queue A specific job queue
887
941
  # @option opts [Array] :subnets 1) prefix_size, 2) number of subnets
888
942
  # @option opts [String] :env Environment name for {http://kadeploy3.gforge.inria.fr/ Kadeploy}
889
- # @option opts [Symbol] :vlan Vlan type: :routed, :local, :global
943
+ # @option opts [String] :vlan VLAN type and number: kavlan-local, kavlan, kavlan-topo, etc
944
+ # @option opts [Numeric] :num_vlan Number of VLANs
890
945
  # @option opts [String] :properties OAR properties defined in the cluster
891
946
  # @option opts [String] :resources OAR syntax for complex submissions
892
947
  # @option opts [String] :reservation Request a job to be scheduled a specific date.
@@ -896,7 +951,7 @@ module Cute
896
951
 
897
952
  # checking valid options
898
953
  valid_opts = [:site, :cluster, :switches, :cpus, :cores, :nodes, :walltime, :cmd,
899
- :type, :name, :subnets, :env, :vlan, :properties, :resources,
954
+ :type, :name, :subnets, :env, :vlan, :num_vlan,:properties, :resources,
900
955
  :reservation, :wait, :keys, :queue, :env_user]
901
956
  unre_opts = opts.keys - valid_opts
902
957
  raise ArgumentError, "Unrecognized option #{unre_opts}" unless unre_opts.empty?
@@ -920,15 +975,18 @@ module Cute
920
975
  type = [type] if type.is_a?(Symbol)
921
976
  keys = opts[:keys]
922
977
  queue = opts[:queue]
978
+ vlan = opts[:vlan]
979
+ num_vlan = opts.fetch(:num_vlan, 1)
980
+
981
+
982
+ available_vlans = nil
983
+ if opts[:vlan]
984
+ available_vlans = @g5k_connection.get_json(api_uri("sites/#{site}/vlans")).items.map{ |item| item["type"]}.uniq
985
+ available_vlans.delete("NULL")
986
+ end
923
987
 
924
- vlan_opts = {:routed => "kavlan",:global => "kavlan-global",:local => "kavlan-local"}
925
- vlan = nil
926
988
  unless opts[:vlan].nil?
927
- if vlan_opts.include?(opts[:vlan]) then
928
- vlan = vlan_opts.fetch(opts[:vlan])
929
- else
930
- raise ArgumentError, 'Option for vlan not recognized'
931
- end
989
+ raise ArgumentError, "VLAN type not available in site #{site}" unless available_vlans.include?(vlan)
932
990
  end
933
991
 
934
992
  raise 'At least nodes, time and site must be given' if [nodes, walltime, site].any? { |x| x.nil? }
@@ -950,7 +1008,7 @@ module Cute
950
1008
  resources = (cluster.is_a?(Fixnum) ? "/cluster=#{cluster}" : "{cluster='#{cluster}'}") + resources
951
1009
  end
952
1010
 
953
- resources = "{type='#{vlan}'}/vlan=1+" + resources unless vlan.nil?
1011
+ resources = "{type='#{vlan}'}/vlan=#{num_vlan}+" + resources unless vlan.nil?
954
1012
  resources = "slash_#{subnets[0]}=#{subnets[1]}+" + resources unless subnets.nil?
955
1013
  end
956
1014
 
@@ -985,13 +1043,15 @@ module Cute
985
1043
  begin
986
1044
  # Support for the option "import-job-key-from-file"
987
1045
  # The request has to be redirected to the OAR API given that Grid'5000 API
988
- # does not support some OAR options.
1046
+ # does not support some OAR options. Bug #7360: https://intranet.grid5000.fr/bugzilla/show_bug.cgi?id=7360
989
1047
  if payload['import-job-key-from-file'] then
990
1048
 
991
1049
  temp = @g5k_connection.post_json(api_uri("sites/#{site}/internal/oarapi/jobs"),payload)
1050
+ info debug_cmd(api_uri("sites/#{site}/internal/oarapi/jobs"),"POST",payload.to_json), :debug
992
1051
  sleep 1 # This is for being sure that our job appears on the list
993
1052
  r = get_my_jobs(site,nil).select{ |j| j["uid"] == temp["id"] }.first
994
1053
  else
1054
+ info debug_cmd(api_uri("sites/#{site}/jobs"),"POST",payload.to_json), :debug
995
1055
  r = @g5k_connection.post_json(api_uri("sites/#{site}/jobs"),payload) # This makes reference to the same class
996
1056
  end
997
1057
  rescue Error => e
@@ -1004,7 +1064,17 @@ module Cute
1004
1064
  job = @g5k_connection.get_json(r.rel_self)
1005
1065
  job = wait_for_job(job) if opts[:wait] == true
1006
1066
  opts.delete(:nodes) # to not collapse with deploy options
1007
- deploy(job,opts) unless opts[:env].nil? #type == :deploy
1067
+ opts.delete(:vlan)
1068
+ opts.delete(:num_vlan)
1069
+ if opts[:env]
1070
+ if opts[:vlan]
1071
+ vlan_id = job.resources["vlans"].first
1072
+ deploy(job,opts.merge!({:vlan_id => vlan_id}))
1073
+ else
1074
+ deploy(job,opts) #type == :deploy
1075
+ end
1076
+ end
1077
+
1008
1078
  return job
1009
1079
 
1010
1080
  end
@@ -1020,21 +1090,21 @@ module Cute
1020
1090
  #
1021
1091
  # require 'cute'
1022
1092
  #
1023
- # g5k = Cute::G5K::API.new()
1093
+ # g5k = Cute::G5K::API.new()
1024
1094
  #
1025
- # sites = g5k.site_uids
1095
+ # sites = g5k.site_uids
1026
1096
  #
1027
- # sites.each{ |site|
1028
- # job = g5k.reserve(:site => site, :nodes => 5, :wait => false, :walltime => "03:00:00")
1029
- # begin
1030
- # job = g5k.wait_for_job(job, :wait_time => 60)
1031
- # puts "Nodes assigned #{job['assigned_nodes']}"
1032
- # break
1033
- # rescue Cute::G5K::EventTimeout
1034
- # puts "We waited too long in site #{site} let's release the job and try in another site"
1035
- # g5k.release(job)
1036
- # end
1037
- # }
1097
+ # sites.each{ |site|
1098
+ # job = g5k.reserve(:site => site, :nodes => 5, :wait => false, :walltime => "03:00:00")
1099
+ # begin
1100
+ # job = g5k.wait_for_job(job, :wait_time => 60)
1101
+ # puts "Nodes assigned #{job['assigned_nodes']}"
1102
+ # break
1103
+ # rescue Cute::G5K::EventTimeout
1104
+ # puts "We waited too long in site #{site} let's release the job and try in another site"
1105
+ # g5k.release(job)
1106
+ # end
1107
+ # }
1038
1108
  #
1039
1109
  # @param job [G5KJSON] as described in {Cute::G5K::G5KJSON job}
1040
1110
  # @param [Hash] opts Options
@@ -1097,7 +1167,7 @@ module Cute
1097
1167
 
1098
1168
  # checking valid options, same as reserve option even though some option dont make any sense
1099
1169
  valid_opts = [:site, :cluster, :switches, :cpus, :cores, :nodes, :walltime, :cmd,
1100
- :type, :name, :subnets, :env, :vlan, :properties, :resources,
1170
+ :type, :name, :subnets, :env, :vlan_id, :properties, :resources,
1101
1171
  :reservation, :wait, :keys, :queue, :env_user]
1102
1172
 
1103
1173
  unre_opts = opts.keys - valid_opts
@@ -1136,17 +1206,14 @@ module Cute
1136
1206
  'key' => public_key_file,
1137
1207
  }
1138
1208
 
1139
- if !job.resources["vlans"].nil?
1140
- vlan = job.resources["vlans"].first
1141
- payload['vlan'] = vlan
1142
- info "Found VLAN with uid = #{vlan}"
1143
- end
1209
+ payload['vlan'] = opts[:vlan_id] if opts[:vlan_id]
1144
1210
 
1145
1211
  payload['user'] = opts[:env_user] unless opts[:env_user].nil?
1146
1212
 
1147
1213
  info "Creating deployment"
1148
1214
 
1149
1215
  begin
1216
+ info debug_cmd(api_uri("sites/#{site}/deployments"),"POST",payload.to_json), :debug
1150
1217
  r = @g5k_connection.post_json(api_uri("sites/#{site}/deployments"), payload)
1151
1218
  rescue Error => e
1152
1219
  info "Fail to deploy"
@@ -1171,7 +1238,7 @@ module Cute
1171
1238
  #
1172
1239
  # = Example
1173
1240
  #
1174
- # deploy_status(job, :nodes => ["adonis-10.grenoble.grid5000.fr"], :status => "terminated")
1241
+ # deploy_status(job, :nodes => ["adonis-10.grenoble.grid5000.fr"], :status => "terminated")
1175
1242
  #
1176
1243
  # @return [Array] status of deploys within a job
1177
1244
  # @param job [G5KJSON] as described in {Cute::G5K::G5KJSON job}
@@ -1261,24 +1328,41 @@ module Cute
1261
1328
  deploy_info["result"].select{ |p,v| v["state"] == "KO"}.keys
1262
1329
  end
1263
1330
 
1331
+ # Returns a valid URI using the current G5K API version.
1332
+ # @return [String] valid URI
1333
+ def api_uri(path)
1334
+ path = path[1..-1] if path.start_with?('/')
1335
+ return "#{@api_version}/#{path}"
1336
+ end
1337
+
1264
1338
  private
1265
1339
  # Handles the output of messages within the module
1266
1340
  # @param msg [String] message to show
1267
- def info(msg)
1341
+ def info(msg,mode =nil)
1342
+
1343
+ return if mode == :debug and not @debug
1344
+
1268
1345
  if @logger.nil? then
1269
1346
  t = Time.now
1270
1347
  s = t.strftime('%Y-%m-%d %H:%M:%S.%L')
1271
1348
  puts "#{s} => #{msg}"
1272
1349
  else
1273
- @logger.info(msg)
1350
+ if mode == :debug
1351
+ @logger.debug(msg)
1352
+ else
1353
+ @logger.info(msg)
1354
+ end
1274
1355
  end
1356
+
1275
1357
  end
1276
1358
 
1277
- # @return a valid Grid'5000 resource
1278
- # it avoids "//"
1279
- def api_uri(path)
1280
- path = path[1..-1] if path.start_with?('/')
1281
- return "#{@api_version}/#{path}"
1359
+ # @return a string containing the command line equivalent for debugging purposes
1360
+ def debug_cmd(path,method,payload=nil)
1361
+ if method == "GET"
1362
+ return "CMD debug: curl -kn #{@uri}#{path}"
1363
+ else
1364
+ return "CMD debug: curl -kni #{@uri}#{path} -X POST -H'Content-Type: application/json' -d '#{payload}'"
1365
+ end
1282
1366
  end
1283
1367
 
1284
1368
  end
data/lib/cute/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cute
2
- VERSION = "0.5"
2
+ VERSION = "0.6"
3
3
  end
data/spec/g5k_api_spec.rb CHANGED
@@ -3,7 +3,11 @@ require 'spec_helper'
3
3
  # Real tests can be activated by setting the shell variable TEST_REAL
4
4
  describe Cute::G5K::API do
5
5
 
6
- subject { g5k = ENV['TEST_REAL'].nil?? Cute::G5K::API.new(:user => "test") : Cute::G5K::API.new() }
6
+ if ENV['TEST_REAL']
7
+ subject { g5k = ENV['DEBUG'].nil?? Cute::G5K::API.new() : Cute::G5K::API.new(:debug => true) }
8
+ else
9
+ subject { g5k = ENV['DEBUG'].nil?? Cute::G5K::API.new(:user => "test") : Cute::G5K::API.new(:user => "test",:debug => true) }
10
+ end
7
11
 
8
12
  let(:sites) { subject.site_uids}
9
13
 
@@ -99,7 +103,7 @@ describe Cute::G5K::API do
99
103
  end
100
104
 
101
105
  it "raises error vlan" do
102
- expect {subject.reserve(:site => @rand_site, :vlan => :nonsense)}.to raise_error(ArgumentError,'Option for vlan not recognized')
106
+ expect {subject.reserve(:site => @rand_site, :vlan => :nonsense)}.to raise_error(ArgumentError,"VLAN type not available in site #{@rand_site}")
103
107
  end
104
108
 
105
109
 
@@ -117,7 +121,7 @@ describe Cute::G5K::API do
117
121
 
118
122
 
119
123
  it "reserves with vlan and get vlan hostnames" do
120
- job = subject.reserve(:site => @rand_site, :nodes => 1, :type => :deploy, :vlan => :routed)
124
+ job = subject.reserve(:site => @rand_site, :nodes => 1, :type => :deploy, :vlan => "kvlan")
121
125
  expect(subject.get_vlan_nodes(job)).to be_an_instance_of(Array)
122
126
  subject.release(job)
123
127
  end
data/spec/spec_helper.rb CHANGED
@@ -55,6 +55,11 @@ 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(:get,/^https:\/\/.*\:.*@api.grid5000.fr\/...\/sites\/.*vlans$/).
59
+ to_return(:status => 200, :body => {'total' => 3, 'items' => [{'type' => "kavlan-local"},{'type' => "kvlan"}]}.to_json)
60
+
61
+ # to_return(:status => 200, :body => {:total => 3, :items => [{:type => "kavlan-local"},{:type => "kavlan"}]})
62
+
58
63
  stub_request(:post, /^https:\/\/.*\:.*@api.grid5000.fr\/.*/).
59
64
  with(:body => hash_including("resources" => "/slash_22=1+{nonsense},walltime=01:00")).
60
65
  to_return(:status => 400, :body => "Oarsub failed: please verify your request syntax")
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.5'
4
+ version: '0.6'
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-05-03 00:00:00.000000000 Z
11
+ date: 2016-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler