ganeti_client 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README +6 -7
- data/lib/ganeti_client/client.rb +143 -72
- data/lib/ganeti_client.rb +0 -2
- metadata +4 -4
data/README
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
== Todo
|
2
2
|
|
3
|
-
2. Add some error handling
|
4
|
-
3. Make some code improvements
|
5
3
|
5. Improve this README with better docs
|
6
4
|
6. Write tests!
|
7
5
|
|
@@ -16,16 +14,16 @@
|
|
16
14
|
|
17
15
|
== Usage
|
18
16
|
|
19
|
-
#
|
20
|
-
|
21
|
-
client = GanetiClient::Client.new("your-host-and-port", "username", "password", boolean)
|
17
|
+
# Create a client instance
|
18
|
+
client = GanetiClient::Client.new("host:port", "username", "password")
|
22
19
|
|
23
20
|
# now you should be able to access the api resources by using the client instance.
|
24
21
|
# example:
|
25
22
|
info = client.info_get
|
26
23
|
=> #<GanetiInfo:0x10151bb78>
|
27
24
|
|
28
|
-
# most methods return an object. When you use .to_json on an object, you get
|
25
|
+
# most methods return an object. When you use .to_json on an object, you get
|
26
|
+
# the json object returned
|
29
27
|
# then you can see all the attributes available
|
30
28
|
info.name
|
31
29
|
=> "hostname"
|
@@ -35,13 +33,14 @@
|
|
35
33
|
|
36
34
|
1. Fork the project
|
37
35
|
2. Add your changes
|
38
|
-
3. Write tests
|
36
|
+
3. Write tests for your changes
|
39
37
|
4. Send a pull request
|
40
38
|
|
41
39
|
|
42
40
|
== Author
|
43
41
|
|
44
42
|
Michaël Rigart
|
43
|
+
http://www.netronix.be
|
45
44
|
|
46
45
|
|
47
46
|
== License
|
data/lib/ganeti_client/client.rb
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
#
|
3
3
|
# The Client is mainly developed for usage with the Ganeti RAPI version 2
|
4
4
|
#
|
5
|
-
# The protocol used is JSON over HTTP designed afther the REST principle. HTTP Basic authentication as per RFC2617 is
|
5
|
+
# The protocol used is JSON over HTTP designed afther the REST principle. HTTP Basic authentication as per RFC2617 is
|
6
|
+
# supported
|
6
7
|
#
|
7
8
|
# A few generic refered parameter types and the values they allow:
|
8
9
|
#
|
@@ -12,16 +13,21 @@
|
|
12
13
|
# A few parameter mean the same thing accross all resources which implement it:
|
13
14
|
#
|
14
15
|
# bulk:
|
15
|
-
# Bulk-mode means that for the resources which usually return just a list of child resources (e.g. /2/instances
|
16
|
-
#
|
16
|
+
# Bulk-mode means that for the resources which usually return just a list of child resources (e.g. /2/instances
|
17
|
+
# which returns just instance names),
|
18
|
+
# the output will instead contain detailed data for all these subresources. This is more efficient than query-ing
|
19
|
+
# the sub-resources themselves.
|
17
20
|
#
|
18
21
|
# dry-run:
|
19
|
-
# The boolean dry-run argument, if provided and set, signals to Ganeti that the job should not be executed, only
|
20
|
-
#
|
22
|
+
# The boolean dry-run argument, if provided and set, signals to Ganeti that the job should not be executed, only
|
23
|
+
# the pre-execution checks will be done.
|
24
|
+
# This is useful in trying to determine (without guarantees though, as in the meantime the cluster state could
|
25
|
+
# have changed) if the operation
|
21
26
|
# is likely to succeed or at least start executing.
|
22
27
|
#
|
23
28
|
# force:
|
24
|
-
# Force operation to continue even if it will cause the cluster to become inconsistent (e.g. because there are
|
29
|
+
# Force operation to continue even if it will cause the cluster to become inconsistent (e.g. because there are
|
30
|
+
# not enough master candidates).
|
25
31
|
#
|
26
32
|
# Author:: Michaël Rigart (mailto:michael@netronix.be)
|
27
33
|
# Copyright:: Copyright (c) 2010 Michaël Rigart
|
@@ -32,7 +38,7 @@ module Ganeti
|
|
32
38
|
# This class contains all active resources available in Ganeti RAPI
|
33
39
|
class Client
|
34
40
|
|
35
|
-
attr_accessor :host, :username, :password, :version
|
41
|
+
attr_accessor :host, :username, :password, :version
|
36
42
|
|
37
43
|
# Description:
|
38
44
|
# Create the client object
|
@@ -41,18 +47,14 @@ module Ganeti
|
|
41
47
|
# string host: hostname and port
|
42
48
|
# string username: username that has access to RAPI
|
43
49
|
# string password: password of the user provided
|
44
|
-
|
45
|
-
def initialize(host, username, password, show_response = false)
|
50
|
+
def initialize(host, username, password)
|
46
51
|
self.host = host
|
47
52
|
self.username = username
|
48
53
|
self.password = password
|
49
54
|
|
50
|
-
self.show_response = show_response
|
51
|
-
|
52
55
|
self.version = self.version_get
|
53
56
|
end
|
54
57
|
|
55
|
-
|
56
58
|
# Description:
|
57
59
|
# Get the cluster information
|
58
60
|
#
|
@@ -88,7 +90,8 @@ module Ganeti
|
|
88
90
|
# Return:
|
89
91
|
# array of all available instances. The array items contain a GanetiInstance object
|
90
92
|
def instances_get(bulk = 0)
|
91
|
-
|
93
|
+
params = {"bulk" => bulk}
|
94
|
+
url = get_url("instances", params)
|
92
95
|
response_body = send_request("GET", url)
|
93
96
|
|
94
97
|
create_class("GanetiInstance")
|
@@ -101,8 +104,10 @@ module Ganeti
|
|
101
104
|
|
102
105
|
# Description:
|
103
106
|
# Create an instance
|
104
|
-
# If the options bool dry-run argument is provided, the job will not be actually executed, only the
|
105
|
-
#
|
107
|
+
# If the options bool dry-run argument is provided, the job will not be actually executed, only the
|
108
|
+
# pre-execution checks will be done.
|
109
|
+
# Query-ing the job result will return, in boty dry-run and normal case, the list of nodes selected for
|
110
|
+
# the instance
|
106
111
|
#
|
107
112
|
# Make sure the instance_name resolves!!
|
108
113
|
#
|
@@ -112,9 +117,11 @@ module Ganeti
|
|
112
117
|
# Example:
|
113
118
|
# info = {
|
114
119
|
# 'hypervisor' => 'kvm' , 'disk_template' => 'plain',
|
115
|
-
# 'pnode' => 'node.netronix.be', 'instance_name' => 'vm1.netronix.be',
|
120
|
+
# 'pnode' => 'node.netronix.be', 'instance_name' => 'vm1.netronix.be',
|
121
|
+
# 'os' => 'debootstrap+lucid',
|
116
122
|
# 'name' => 'vm1.netronix.be',
|
117
|
-
# 'vcpus' => '4', 'memory' => '4096',
|
123
|
+
# 'vcpus' => '4', 'memory' => '4096',
|
124
|
+
# 'disks' => [25600],
|
118
125
|
# 'kernel-path' => '/boot/vmlinuz-2.6-kvmU'
|
119
126
|
# }
|
120
127
|
#
|
@@ -176,7 +183,8 @@ module Ganeti
|
|
176
183
|
# Return:
|
177
184
|
# string job id
|
178
185
|
def instance_delete(name, dry_run = 0)
|
179
|
-
|
186
|
+
params = {"dry-run" => dry_run}
|
187
|
+
url = get_url("instances/#{name}", params)
|
180
188
|
response_body = send_request("DELETE", url)
|
181
189
|
|
182
190
|
return response_body
|
@@ -193,7 +201,8 @@ module Ganeti
|
|
193
201
|
# Return:
|
194
202
|
# string job id
|
195
203
|
def instance_get_info(name, static = 0)
|
196
|
-
|
204
|
+
params = {"static" => static}
|
205
|
+
url = get_url("instances/#{name}/info", params)
|
197
206
|
response_body = send_request("GET", url)
|
198
207
|
|
199
208
|
return response_body
|
@@ -206,7 +215,8 @@ module Ganeti
|
|
206
215
|
# type defines the reboot type.
|
207
216
|
# soft is just a normal reboot, without terminating the hypervisor.
|
208
217
|
# hard means full shutdown (including terminating the hypervisor process) and startup again
|
209
|
-
# full is like hard but also recreates the configuration from ground up as if you would have
|
218
|
+
# full is like hard but also recreates the configuration from ground up as if you would have done
|
219
|
+
# a gnt-instance shutdown and gnt-instance start on it
|
210
220
|
#
|
211
221
|
#
|
212
222
|
# Parameters:
|
@@ -218,7 +228,8 @@ module Ganeti
|
|
218
228
|
# Return:
|
219
229
|
# string job id
|
220
230
|
def instance_reboot(name, type = "soft", ignore_secondaries = 0, dry_run = 0)
|
221
|
-
|
231
|
+
params = {"type" => type, "ignore_secondaries" => ignore_secondaries, "dry_run" => 0}
|
232
|
+
url = get_url("instances/#{name}/reboot", params)
|
222
233
|
response_body = send_request("POST", url)
|
223
234
|
|
224
235
|
return response_body
|
@@ -235,7 +246,8 @@ module Ganeti
|
|
235
246
|
# Return:
|
236
247
|
# string job id
|
237
248
|
def instance_shutdown(name, dry_run = 0)
|
238
|
-
|
249
|
+
params = {"dry-run" => dry_run}
|
250
|
+
url = get_url("instances/#{name}/shutdown", params)
|
239
251
|
response_body = send_request("PUT", url)
|
240
252
|
|
241
253
|
return response_body
|
@@ -253,7 +265,8 @@ module Ganeti
|
|
253
265
|
# Return:
|
254
266
|
# string job id
|
255
267
|
def instance_startup(name, force = 0, dry_run=0)
|
256
|
-
|
268
|
+
params = {"force" => force, "dry-run" => dry_run}
|
269
|
+
url = get_url("instances/#{name}/startup", params)
|
257
270
|
response_body = send_request("PUT", url)
|
258
271
|
|
259
272
|
return response_body
|
@@ -270,7 +283,8 @@ module Ganeti
|
|
270
283
|
# Return:
|
271
284
|
# string job id
|
272
285
|
def instance_reinstall(name, os_name, nostartup = 0)
|
273
|
-
|
286
|
+
params = {"os" => os_name, "nostartup" => nostartup}
|
287
|
+
url = get_url("instances/#{name}/reinstall", params)
|
274
288
|
response_body = send_request("POST", url)
|
275
289
|
|
276
290
|
return response_body
|
@@ -278,9 +292,11 @@ module Ganeti
|
|
278
292
|
|
279
293
|
# Description:
|
280
294
|
# Replaces disks on an instance
|
281
|
-
# Takes the parameters mode (one of replace_on_primary, replace_on_secondary or replace_auto), disks
|
295
|
+
# Takes the parameters mode (one of replace_on_primary, replace_on_secondary or replace_auto), disks
|
296
|
+
# (comma seperated list of disk indexes), remote_node and iallocator
|
282
297
|
# Either remote_node or iallocator needs to be defined when using mode=replace_new_secondary
|
283
|
-
# mode is a mandatory parameter. replace_auto tries to determine the broken disk(s) on its own and
|
298
|
+
# mode is a mandatory parameter. replace_auto tries to determine the broken disk(s) on its own and
|
299
|
+
# replacing it
|
284
300
|
#
|
285
301
|
# Parameters:
|
286
302
|
# string name: name of the instance
|
@@ -292,7 +308,8 @@ module Ganeti
|
|
292
308
|
# Return:
|
293
309
|
# string job id
|
294
310
|
def instance_replace_disks(name, mode = "replace_auto", iallocator = "", remote_node = "", disks = "")
|
295
|
-
|
311
|
+
params = {"mode" => mode, "iallocator" => iallocator, "remote_node" => remote_node, "disks" => disks}
|
312
|
+
url = get_url("instances/#{name}/replace-disks", params)
|
296
313
|
response_body = send_request("POST", url)
|
297
314
|
|
298
315
|
return response_body
|
@@ -300,7 +317,8 @@ module Ganeti
|
|
300
317
|
|
301
318
|
# Description:
|
302
319
|
# Activate disks on an instance
|
303
|
-
# Takes the bool parameter ignore_size. When set ignore the recorded size (useful for forcing activation
|
320
|
+
# Takes the bool parameter ignore_size. When set ignore the recorded size (useful for forcing activation
|
321
|
+
# when recoreded size is wrong)
|
304
322
|
#
|
305
323
|
# Parameters:
|
306
324
|
# string name: name of the instance
|
@@ -309,7 +327,8 @@ module Ganeti
|
|
309
327
|
# Return:
|
310
328
|
# string job id
|
311
329
|
def instance_activate_disks(name, ignore_size = 0)
|
312
|
-
|
330
|
+
params = {"ignore_size" => ignore_size}
|
331
|
+
url = get_url("instances/#{name}/activate-disks", params)
|
313
332
|
response_body = send_request("PUT", url)
|
314
333
|
|
315
334
|
return response_body
|
@@ -357,7 +376,8 @@ module Ganeti
|
|
357
376
|
# Return:
|
358
377
|
# string job id
|
359
378
|
def instance_create_tags(name, tags, dry_run = 0)
|
360
|
-
|
379
|
+
params = {'dry-run' => dry_run, 'tag' => tags}
|
380
|
+
url = get_url("instances/#{name}/tags", params)
|
361
381
|
response_body = send_request("PUT", url)
|
362
382
|
|
363
383
|
return response_body
|
@@ -374,7 +394,8 @@ module Ganeti
|
|
374
394
|
# Return:
|
375
395
|
# string job id
|
376
396
|
def instance_delete_tags(name, tags, dry_run = 0)
|
377
|
-
|
397
|
+
params = {'dry-run' => dry_run, 'tag' => tags}
|
398
|
+
url = get_url("instances/#{name}/tags", params)
|
378
399
|
response_body = send_request("DELETE", url)
|
379
400
|
|
380
401
|
return response_body
|
@@ -409,43 +430,54 @@ module Ganeti
|
|
409
430
|
# opstatus: OpCodes status as a list
|
410
431
|
# opresult: OpCodes results as a list
|
411
432
|
#
|
412
|
-
# For a successful opcode, the opresult field corresponding to it will contain the raw result from its
|
433
|
+
# For a successful opcode, the opresult field corresponding to it will contain the raw result from its
|
434
|
+
# LogicalUnit. In case an opcode has failed, its element in the opresult list will be a list of two
|
435
|
+
# elements:
|
413
436
|
# first element the error type (the Ganeti internal error name)
|
414
437
|
# second element a list of either one or two elements:
|
415
438
|
# the first element is the textual error description
|
416
439
|
# the second element, if any, will hold an error classification
|
417
440
|
#
|
418
|
-
# The error classification is most useful for the OpPrereqError error type - these errors happen before
|
441
|
+
# The error classification is most useful for the OpPrereqError error type - these errors happen before
|
442
|
+
# the OpCode has started executing, so it’s possible to retry the
|
419
443
|
# OpCode without side effects. But whether it make sense to retry depends on the error classification:
|
420
444
|
#
|
421
445
|
# resolver_error
|
422
|
-
# Resolver errors. This usually means that a name doesn’t exist in DNS, so if it’s a case of
|
446
|
+
# Resolver errors. This usually means that a name doesn’t exist in DNS, so if it’s a case of
|
447
|
+
# slow DNS propagation the operation can be retried later.
|
423
448
|
#
|
424
449
|
# insufficient_resources
|
425
|
-
# Not enough resources (iallocator failure, disk space, memory, etc.). If the resources on the
|
450
|
+
# Not enough resources (iallocator failure, disk space, memory, etc.). If the resources on the
|
451
|
+
# cluster increase, the operation might succeed.
|
426
452
|
#
|
427
453
|
# wrong_input
|
428
|
-
# Wrong arguments (at syntax level). The operation will not ever be accepted unless the arguments
|
454
|
+
# Wrong arguments (at syntax level). The operation will not ever be accepted unless the arguments
|
455
|
+
# change.
|
429
456
|
#
|
430
457
|
# wrong_state
|
431
|
-
# Wrong entity state. For example, live migration has been requested for a down instance, or
|
458
|
+
# Wrong entity state. For example, live migration has been requested for a down instance, or
|
459
|
+
# instance creation on an offline node. The operation can be retried once the resource has
|
460
|
+
# changed state.
|
432
461
|
#
|
433
462
|
# unknown_entity
|
434
463
|
# Entity not found. For example, information has been requested for an unknown instance.
|
435
464
|
#
|
436
465
|
# already_exists
|
437
|
-
# Entity already exists. For example, instance creation has been requested for an
|
466
|
+
# Entity already exists. For example, instance creation has been requested for an
|
467
|
+
# already-existing instance.
|
438
468
|
#
|
439
469
|
# resource_not_unique
|
440
470
|
# Resource not unique (e.g. MAC or IP duplication).
|
441
471
|
#
|
442
472
|
# internal_error
|
443
|
-
# Internal cluster error. For example, a node is unreachable but not set offline, or the
|
473
|
+
# Internal cluster error. For example, a node is unreachable but not set offline, or the
|
474
|
+
# ganeti node daemons are not working, etc. A gnt-cluster verify should be run.
|
444
475
|
#
|
445
476
|
# environment_error
|
446
477
|
# Environment error (e.g. node disk error). A gnt-cluster verify should be run.
|
447
478
|
#
|
448
|
-
# Note that in the above list, by entity we refer to a node or instance, while by a resource we refer
|
479
|
+
# Note that in the above list, by entity we refer to a node or instance, while by a resource we refer
|
480
|
+
# to an instance’s disk, or NIC, etc.
|
449
481
|
#
|
450
482
|
# Parameters:
|
451
483
|
# string job_id
|
@@ -486,7 +518,8 @@ module Ganeti
|
|
486
518
|
# Return:
|
487
519
|
# array of GanetiNode objects
|
488
520
|
def nodes_get(bulk = 0)
|
489
|
-
|
521
|
+
params = {"bulk", bulk}
|
522
|
+
url = get_url("nodes", params)
|
490
523
|
response_body = send_request("GET", url)
|
491
524
|
|
492
525
|
create_class("GanetiNode")
|
@@ -526,8 +559,9 @@ module Ganeti
|
|
526
559
|
# Return:
|
527
560
|
# string job id
|
528
561
|
def node_evaluate(name, iallocator = "", remote_node = "")
|
529
|
-
|
530
|
-
|
562
|
+
params = {"iallocator" => iallocator, "remote_node" => remote_node}
|
563
|
+
url = get_url("nodes/#{name}/evacuate", params)
|
564
|
+
response_body = send_request("POST", url)
|
531
565
|
|
532
566
|
return response_body
|
533
567
|
end
|
@@ -543,7 +577,8 @@ module Ganeti
|
|
543
577
|
# Return:
|
544
578
|
# string job id
|
545
579
|
def node_migrate(name, live = 0)
|
546
|
-
|
580
|
+
params = {"live" => live}
|
581
|
+
url = get_url("nodes/#{name}/migrate", params)
|
547
582
|
response_body = send_request("POST", url)
|
548
583
|
|
549
584
|
return response_body
|
@@ -592,7 +627,8 @@ module Ganeti
|
|
592
627
|
# Return:
|
593
628
|
# string job id
|
594
629
|
def node_change_role(name, role, force = 0)
|
595
|
-
|
630
|
+
params = {"role" => role, "force" => force}
|
631
|
+
url = get_url("nodes/#{name}/role", params)
|
596
632
|
# This is again quirck in the RAPI. The string needs to have escaped
|
597
633
|
# quotes becouse of pythons "non-stric" JSON handling
|
598
634
|
# http://code.google.com/p/ganeti/issues/detail?id=118
|
@@ -604,7 +640,8 @@ module Ganeti
|
|
604
640
|
|
605
641
|
# Description:
|
606
642
|
# Manages storage units on the node
|
607
|
-
# Requests a list of storage units on a node. Requires the parameters storage_type (one of file, lvm-pv
|
643
|
+
# Requests a list of storage units on a node. Requires the parameters storage_type (one of file, lvm-pv
|
644
|
+
# or lvm-vg) and output_fields.
|
608
645
|
# The result will be a job id, using which the result can be retrieved
|
609
646
|
#
|
610
647
|
# Parameters:
|
@@ -615,7 +652,8 @@ module Ganeti
|
|
615
652
|
# Return:
|
616
653
|
# string job id
|
617
654
|
def node_get_storage(name, storage_type = "", output_fields = "")
|
618
|
-
|
655
|
+
params = {"storage_type" => storage_type, "output_fields" => output_fields}
|
656
|
+
url = get_url("nodes/#{name}/storage", params)
|
619
657
|
response_body = send_request("GET", url)
|
620
658
|
|
621
659
|
return response_body
|
@@ -623,7 +661,8 @@ module Ganeti
|
|
623
661
|
|
624
662
|
# Description:
|
625
663
|
# Modify storage units on the node
|
626
|
-
# Mofifies parameters of storage units on the node. Requires the parameters storage_type (one of file,
|
664
|
+
# Mofifies parameters of storage units on the node. Requires the parameters storage_type (one of file,
|
665
|
+
# lvm-pv or lvm-vg) and name (name of the storage unit).
|
627
666
|
# Parameters can be passed additionally. Currently only allocatable (bool) is supported.
|
628
667
|
#
|
629
668
|
# Parameters:
|
@@ -633,7 +672,8 @@ module Ganeti
|
|
633
672
|
# Return:
|
634
673
|
# string job id
|
635
674
|
def node_modify_storage(name, storage_unit_name, storage_type, allocatable = 0)
|
636
|
-
|
675
|
+
params = {"name" => storage_unit_name, "storage_type" => storage_type, "allocatable" => allocatable}
|
676
|
+
url = get_url("nodes/#{name}/storage/modify", params)
|
637
677
|
response_body = send_request("PUT", url)
|
638
678
|
|
639
679
|
return response_body
|
@@ -641,7 +681,8 @@ module Ganeti
|
|
641
681
|
|
642
682
|
|
643
683
|
# Description:
|
644
|
-
# Repairs a storage unit on the node. Requires the parameters storage_type (currently only lvm-vg can
|
684
|
+
# Repairs a storage unit on the node. Requires the parameters storage_type (currently only lvm-vg can
|
685
|
+
# be repaired) and name (name of the storage unit).
|
645
686
|
#
|
646
687
|
# Parameters:
|
647
688
|
# string name: name of the node
|
@@ -651,7 +692,8 @@ module Ganeti
|
|
651
692
|
# Return:
|
652
693
|
# string job id
|
653
694
|
def node_repair_storage(name, storage_name, storage_type = "lvm-vg")
|
654
|
-
|
695
|
+
params = {"storage_type" => storage_type, "name" => storage_name}
|
696
|
+
url = get_url("nodes/#{name}/storage/repair", params)
|
655
697
|
response_body = send_request("PUT", url)
|
656
698
|
|
657
699
|
return response_body
|
@@ -688,7 +730,8 @@ module Ganeti
|
|
688
730
|
# Return:
|
689
731
|
# string job id
|
690
732
|
def node_create_tags(name, tags, dry_run = 0)
|
691
|
-
|
733
|
+
params = {"tag" => tags, "dry-run" => dry_run}
|
734
|
+
url = get_url("nodes/#{name}/tags", params)
|
692
735
|
response_body = send_request("PUT", url)
|
693
736
|
|
694
737
|
return response_body
|
@@ -707,7 +750,8 @@ module Ganeti
|
|
707
750
|
# Return:
|
708
751
|
# string job id
|
709
752
|
def node_delete_tags(name, tags, dry_run = 0)
|
710
|
-
|
753
|
+
params = {"tag" => tags, "dry-run" => dry_run}
|
754
|
+
url = get_url("nodes/#{name}/tags", params)
|
711
755
|
response_body = send_request("DELETE", url)
|
712
756
|
|
713
757
|
return response_body
|
@@ -715,7 +759,8 @@ module Ganeti
|
|
715
759
|
|
716
760
|
# Description:
|
717
761
|
# Returns a list of all OSes
|
718
|
-
# Can return error 500 in case of a problem. Since this is a costly operation for Ganeti 2.0, it is
|
762
|
+
# Can return error 500 in case of a problem. Since this is a costly operation for Ganeti 2.0, it is
|
763
|
+
# not recommented to execute it too often
|
719
764
|
#
|
720
765
|
# Example:
|
721
766
|
# ["debian-etch"]
|
@@ -757,7 +802,8 @@ module Ganeti
|
|
757
802
|
# Return:
|
758
803
|
# string job id
|
759
804
|
def tags_create(tags, dry_run = 0)
|
760
|
-
|
805
|
+
params = {"tag" => tags, "dry-run" => dry_run}
|
806
|
+
url = get_url("tags", params)
|
761
807
|
response_body = send_request("PUT", url)
|
762
808
|
|
763
809
|
return response_body
|
@@ -776,7 +822,8 @@ module Ganeti
|
|
776
822
|
# Return:
|
777
823
|
# string job id
|
778
824
|
def tags_delete(tags, dry_run = 0)
|
779
|
-
|
825
|
+
params = {"tag" => tags, "dry-run" => dry_run}
|
826
|
+
url = get_url("tags", params)
|
780
827
|
response_body = send_request("DELETE", url)
|
781
828
|
|
782
829
|
return response_body
|
@@ -811,9 +858,7 @@ module Ganeti
|
|
811
858
|
# hash headers
|
812
859
|
def authenticate(username, password)
|
813
860
|
basic = Base64.encode64("#{username}:#{password}").strip
|
814
|
-
|
815
|
-
|
816
|
-
return headers
|
861
|
+
return {'Authorization' => "Basic #{basic}"}
|
817
862
|
end
|
818
863
|
|
819
864
|
# Descriptions:
|
@@ -853,28 +898,54 @@ module Ganeti
|
|
853
898
|
# string method: action method (get, post, put, delete)
|
854
899
|
# string url: the path to the resource
|
855
900
|
# string body: extra body information that needs to be send to the resource
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
901
|
+
def send_request(method, url, body = nil, headers = {})
|
902
|
+
raise ArgumentError, 'only GET, POST, PUT and DELETE methods are supported' unless %w[GET POST PUT DELETE].include?(method.to_s)
|
903
|
+
raise ArgumentError, 'headers must be a hash' unless headers.is_a?(Hash)
|
904
|
+
|
860
905
|
uri = URI.parse(host)
|
861
906
|
|
862
907
|
http = Net::HTTP.new(uri.host, uri.port)
|
863
908
|
http.use_ssl = (uri.scheme == "http")? false : true
|
909
|
+
|
910
|
+
headers.merge!({'User-Agent' => 'Ruby Ganeti RAPI Client'})
|
911
|
+
headers.merge!(authenticate(self.username, self.password))
|
912
|
+
|
913
|
+
begin
|
914
|
+
response = http.send_request(method, url, body, headers)
|
915
|
+
rescue => e
|
916
|
+
puts "Error sending request"
|
917
|
+
puts e.message
|
918
|
+
else
|
919
|
+
case response
|
920
|
+
when Net::HTTPSuccess
|
921
|
+
parse_response(response.body.strip)
|
922
|
+
else
|
923
|
+
response.instance_eval { class << self; attr_accessor :body_parsed; end }
|
924
|
+
begin; response.body_parsed = parse_response(response.body); rescue; end
|
925
|
+
response.error! # raises exception corresponding to http error Net::XXX
|
926
|
+
end
|
927
|
+
end
|
928
|
+
end
|
864
929
|
|
865
|
-
headers = {}
|
866
|
-
headers = authenticate(self.username, self.password)
|
867
|
-
|
868
|
-
response = http.send_request(method, url, body, headers)
|
869
|
-
|
870
|
-
|
871
|
-
puts "Response #{response.code} #{response.message}: #{response.body}" if self.show_response
|
872
930
|
|
931
|
+
# Description:
|
932
|
+
# TEST
|
933
|
+
#
|
934
|
+
# Parameters:
|
935
|
+
# string response_body
|
936
|
+
#
|
937
|
+
# Return:
|
938
|
+
# json response: the reponse from the resource
|
939
|
+
def parse_response(response_body)
|
873
940
|
# adding workaround becouse Google seems to operate on 'non-strict' JSON format
|
874
941
|
# http://code.google.com/p/ganeti/issues/detail?id=117
|
875
|
-
|
942
|
+
begin
|
943
|
+
response_body = JSON.parse(response_body)
|
944
|
+
rescue
|
945
|
+
response_body = JSON.parse('['+response_body+']').first
|
946
|
+
end
|
876
947
|
|
877
|
-
return
|
948
|
+
return response_body
|
878
949
|
end
|
879
950
|
|
880
951
|
# Description:
|
data/lib/ganeti_client.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ganeti_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 8
|
10
|
+
version: 0.0.8
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Micha\xC3\xABl Rigart"
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-20 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|