ruby-cute 0.5 → 0.6

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