ganeti_client 0.0.7 → 0.0.8
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.
- 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
|
|