ganeti_client 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +13 -6
- data/lib/ganeti_client/client.rb +242 -79
- data/lib/ganeti_client.rb +24 -0
- metadata +3 -3
data/README
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
== License
|
2
|
-
|
3
|
-
This Ruby Ganeti Client is release under AGPL licence (http://www.gnu.org/licenses/agpl-3.0.html)
|
4
|
-
|
5
|
-
|
6
1
|
== Todo
|
7
2
|
|
8
3
|
1. Manually test the following methods + fix when bugs found
|
@@ -17,7 +12,6 @@
|
|
17
12
|
1.9. instance_activate_disks
|
18
13
|
1.10. instance_create_tags
|
19
14
|
1.11. instance_delete_tags
|
20
|
-
1.12. job_get
|
21
15
|
1.13. job_delete
|
22
16
|
1.14. node_evaluate
|
23
17
|
1.15. node_migrate
|
@@ -61,6 +55,7 @@
|
|
61
55
|
info.name
|
62
56
|
=> "hostname"
|
63
57
|
|
58
|
+
|
64
59
|
== Contributing
|
65
60
|
|
66
61
|
1. Fork the project
|
@@ -69,6 +64,18 @@
|
|
69
64
|
4. Send a pull request
|
70
65
|
|
71
66
|
|
67
|
+
== Author
|
68
|
+
|
69
|
+
Michaël Rigart
|
70
|
+
|
71
|
+
|
72
|
+
== License
|
73
|
+
|
74
|
+
This Ruby Ganeti Client is release under AGPL licence (http://www.gnu.org/licenses/agpl-3.0.html)
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
72
79
|
|
73
80
|
|
74
81
|
|
data/lib/ganeti_client/client.rb
CHANGED
@@ -1,23 +1,61 @@
|
|
1
|
+
# The program makes use of the Google Ganeti RAPI to access diffrent resources.
|
2
|
+
#
|
3
|
+
# The Client is mainly developed for usage with the Ganeti RAPI version 2
|
4
|
+
#
|
5
|
+
# The protocol used is JSON over HTTP designed afther the REST principle. HTTP Basic authentication as per RFC2617 is supported
|
6
|
+
#
|
7
|
+
# A few generic refered parameter types and the values they allow:
|
8
|
+
#
|
9
|
+
# bool:
|
10
|
+
# A boolean option will accept 1 or 0 as numbers but not i.e. True or False
|
11
|
+
#
|
12
|
+
# A few parameter mean the same thing accross all resources which implement it:
|
13
|
+
#
|
14
|
+
# bulk:
|
15
|
+
# Bulk-mode means that for the resources which usually return just a list of child resources (e.g. /2/instances which returns just instance names),
|
16
|
+
# the output will instead contain detailed data for all these subresources. This is more efficient than query-ing the sub-resources themselves.
|
17
|
+
#
|
18
|
+
# dry-run:
|
19
|
+
# The boolean dry-run argument, if provided and set, signals to Ganeti that the job should not be executed, only the pre-execution checks will be done.
|
20
|
+
# This is useful in trying to determine (without guarantees though, as in the meantime the cluster state could have changed) if the operation
|
21
|
+
# is likely to succeed or at least start executing.
|
22
|
+
#
|
23
|
+
# force:
|
24
|
+
# Force operation to continue even if it will cause the cluster to become inconsistent (e.g. because there are not enough master candidates).
|
25
|
+
#
|
26
|
+
# Author:: Michaël Rigart (mailto:michael@netronix.be)
|
27
|
+
# Copyright:: Copyright (c) 2010 Michaël Rigart
|
28
|
+
# License:: Distributes under AGPL Licence
|
29
|
+
|
1
30
|
module GanetiClient
|
31
|
+
|
32
|
+
# This class contains all active resources available in Ganeti RAPI
|
2
33
|
class Client
|
3
34
|
|
4
|
-
attr_accessor :
|
35
|
+
attr_accessor :host, :username, :password, :version, :show_response
|
5
36
|
|
37
|
+
# Create the client object
|
38
|
+
#
|
39
|
+
# Parameters:
|
40
|
+
# host: hostname and port
|
41
|
+
# username: username that has access to RAPI
|
42
|
+
# password: password of the user provided
|
43
|
+
# show_response: show response data (optional)
|
6
44
|
def initialize(host, username, password, show_response = false)
|
7
|
-
self.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
self.
|
12
|
-
|
13
|
-
self.headers = authenticate(username, password)
|
45
|
+
self.host = host
|
46
|
+
self.username = username
|
47
|
+
self.password = password
|
48
|
+
|
49
|
+
self.show_response = show_response
|
14
50
|
|
15
|
-
self.version = self.
|
51
|
+
self.version = self.version_get
|
16
52
|
end
|
17
53
|
|
18
54
|
|
19
|
-
#
|
20
|
-
#
|
55
|
+
# Get the cluster information
|
56
|
+
#
|
57
|
+
# Return:
|
58
|
+
# GanetiInfo object
|
21
59
|
def info_get
|
22
60
|
url = get_url("info")
|
23
61
|
response_body = JSON.parse(send_request("GET", url))
|
@@ -28,7 +66,9 @@ module GanetiClient
|
|
28
66
|
end
|
29
67
|
|
30
68
|
# Redistrite configuration to all nodes
|
31
|
-
#
|
69
|
+
#
|
70
|
+
# Return:
|
71
|
+
# job id.
|
32
72
|
def redistribute_config
|
33
73
|
url = get_url("redistribute-config")
|
34
74
|
response_body = send_request("PUT", url)
|
@@ -36,9 +76,13 @@ module GanetiClient
|
|
36
76
|
return response_body
|
37
77
|
end
|
38
78
|
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
79
|
+
# Get all instances on the cluster
|
80
|
+
#
|
81
|
+
# Parameters:
|
82
|
+
# bulk: 0|1 (optional)
|
83
|
+
#
|
84
|
+
# Return:
|
85
|
+
# Array of all available instances. The array items contain a GanetiInstance object
|
42
86
|
def instances_get(bulk = 0)
|
43
87
|
url = get_url("instances", {"bulk" => bulk})
|
44
88
|
response_body = JSON.parse(send_request("GET", url))
|
@@ -51,23 +95,57 @@ module GanetiClient
|
|
51
95
|
return list
|
52
96
|
end
|
53
97
|
|
54
|
-
#
|
98
|
+
# Create an instance
|
55
99
|
# If the options bool dry-run argument is provided, the job will not be actually executed, only the pre-execution checks will be done.
|
56
100
|
# Query-ing the job result will return, in boty dry-run and normal case, the list of nodes selected for the instance
|
57
|
-
# Returns: a job ID that can be used later for polling
|
58
101
|
#
|
59
|
-
#
|
60
|
-
#
|
102
|
+
# Build parameters dict, optional parameters need to be
|
103
|
+
# excluded to not cause issues with rapi.
|
104
|
+
#
|
105
|
+
# Example:
|
106
|
+
# info = {
|
107
|
+
# 'hypervisor' => 'kvm' , 'disk_template' => 'plain',
|
108
|
+
# 'pnode' => 'node.netronix.be', 'name' => 'vm1.netronix.be', 'os' => 'debootstrap+lucid',
|
109
|
+
# 'vcpus' => '4', 'memory' => '4096', 'disks' => ['25600'],
|
110
|
+
# 'kernel-path' => '/boot/vmlinuz-2.6-kvmU'
|
111
|
+
# }
|
112
|
+
#
|
113
|
+
# Parameters:
|
114
|
+
# info: hash of data needed for the instance creation
|
115
|
+
# dry_run: 0|1 (optional)
|
116
|
+
#
|
117
|
+
# Return:
|
118
|
+
# job_id
|
61
119
|
def instance_create(info, dry_run = 0)
|
120
|
+
params = {
|
121
|
+
'hypervisor' => info['hypervisor'], 'disk_template' => info['disk_template'],
|
122
|
+
'pnode' => info['pnode'], 'name' => info['iname'], 'os' => info['os'],
|
123
|
+
'vcpus' => info['vcpus'], 'memory' => info['memory'], 'disks' => [info['size']]
|
124
|
+
}
|
125
|
+
|
126
|
+
# Add secondary node
|
127
|
+
params['snode'] = info['snode'] if info['disk_template'] == 'drbd' && info['snode']
|
128
|
+
|
129
|
+
# Add PVM parameters
|
130
|
+
if info['hypervisor']
|
131
|
+
params['kernel_path'] = info['kernel_path'] if info['kernel_path']
|
132
|
+
params['initrd_path'] = info['initrd_path'] if info['initrd_path']
|
133
|
+
end
|
134
|
+
|
62
135
|
url = get_url("instances", {"dry-run" => dry_run})
|
63
|
-
body = JSON.generate(
|
136
|
+
body = JSON.generate(params)
|
64
137
|
response_body = send_request("POST", url, body)
|
65
138
|
|
66
139
|
return response_body
|
67
140
|
end
|
68
141
|
|
69
|
-
#
|
70
|
-
#
|
142
|
+
# Get instance specific information, similar to the bulk output from the instance list
|
143
|
+
#
|
144
|
+
# Parameters:
|
145
|
+
# name: name of the instance
|
146
|
+
#
|
147
|
+
# Return
|
148
|
+
# GanetiInstance object
|
71
149
|
def instance_get(name)
|
72
150
|
url = get_url("instances/#{name}")
|
73
151
|
response_body = JSON.parse(send_request("GET", url))
|
@@ -77,19 +155,29 @@ module GanetiClient
|
|
77
155
|
return GanetiInstance.new(response_body)
|
78
156
|
end
|
79
157
|
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
|
158
|
+
# Delete a specific instance
|
159
|
+
#
|
160
|
+
# Parameters:
|
161
|
+
# name: name of the instance
|
162
|
+
# dry_run: 0|1 (optional)
|
163
|
+
#
|
164
|
+
# Return:
|
165
|
+
# ?
|
166
|
+
def instance_delete(name, dry_run = 0)
|
84
167
|
url = get_url("instances/#{name}", {"dry-run" => dry_run})
|
85
168
|
response_body = send_request("DELETE", url)
|
86
169
|
|
87
170
|
return response_body
|
88
171
|
end
|
89
172
|
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
173
|
+
# Get detailed information about an instance. Static parameter can be set to return only static information from the configuration without querying the instance's nodes
|
174
|
+
#
|
175
|
+
# Parameters:
|
176
|
+
# name: name of the instance
|
177
|
+
# static: 0|1 (optional)
|
178
|
+
#
|
179
|
+
# Return:
|
180
|
+
# job id
|
93
181
|
def instance_get_info(name, static = 0)
|
94
182
|
url = get_url("instances/#{name}/info", {"static" => static})
|
95
183
|
response_body = send_request("GET", url)
|
@@ -97,8 +185,7 @@ module GanetiClient
|
|
97
185
|
return response_body
|
98
186
|
end
|
99
187
|
|
100
|
-
#
|
101
|
-
# Reboots the instance
|
188
|
+
# Reboot a specific instance
|
102
189
|
# The URI takes optional type=soft|hard|full and ignore_secondaries=0|1 parameters
|
103
190
|
#
|
104
191
|
# type defines the reboot type.
|
@@ -107,86 +194,130 @@ module GanetiClient
|
|
107
194
|
# full is like hard but also recreates the configuration from ground up as if you would have don a gnt-instance shutdown and gnt-instance start on it
|
108
195
|
#
|
109
196
|
# it supports the dry-run argument
|
197
|
+
#
|
198
|
+
# Parameters:
|
199
|
+
# name: name of the instance
|
200
|
+
# type: soft|hard|full (optional)
|
201
|
+
# ignore_secondaries: 0|1 (optional)
|
202
|
+
# dry_run: 0|1 (optional)
|
203
|
+
#
|
204
|
+
# Return:
|
205
|
+
# ?
|
110
206
|
def instance_reboot(name, type = "soft", ignore_secondaries = 0, dry_run = 0)
|
111
207
|
url = get_url("instances/#{name}/reboot", {"type" => type, "ignore_secondaries" => ignore_secondaries, "dry_run" => 0})
|
112
|
-
response_body =
|
113
|
-
|
114
|
-
create_class("GanetiInstanceReboot")
|
208
|
+
response_body = send_request("POST", url)
|
115
209
|
|
116
|
-
return
|
210
|
+
return response_body
|
117
211
|
end
|
118
212
|
|
119
213
|
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
214
|
+
# Shutdown an instance
|
215
|
+
#
|
216
|
+
# Parameters:
|
217
|
+
# name: name of the instance
|
218
|
+
# dry_run: 0|1 (optional)
|
219
|
+
#
|
220
|
+
# Return:
|
221
|
+
# ?
|
123
222
|
def instance_shutdown(name, dry_run = 0)
|
124
223
|
url = get_url("instances/#{name}/shutdown", {"dry-run" => dry_run})
|
125
|
-
response_body =
|
126
|
-
|
127
|
-
create_class("GanetiInstanceShutdown")
|
224
|
+
response_body = send_request("PUT", url)
|
128
225
|
|
129
|
-
return
|
226
|
+
return response_body
|
130
227
|
end
|
131
228
|
|
132
|
-
# Instance startup URI
|
133
229
|
# Startup an instance
|
134
230
|
# The URI takes an optional force=1|0 parameter to start the instance even if secondary disks are failing
|
135
|
-
#
|
231
|
+
#
|
232
|
+
# Parameters:
|
233
|
+
# name: name of the instance
|
234
|
+
# force: 0|1 (optional)
|
235
|
+
# dry_run: 0|1 (optional)
|
236
|
+
#
|
237
|
+
# Return:
|
238
|
+
# ?
|
136
239
|
def instance_startup(name, force = 0, dry_run=0)
|
137
240
|
url = get_url("instances/#{name}/startup", {"force" => force, "dry-run" => dry_run})
|
138
241
|
body = "" # force parameter
|
139
242
|
response_body = send_request("PUT", url, body)
|
140
243
|
|
141
|
-
|
142
|
-
|
143
|
-
return GanetiInstanceStartup.new(response_body)
|
244
|
+
return response_body
|
144
245
|
end
|
145
246
|
|
146
247
|
# Install the operating system again
|
147
|
-
#
|
148
|
-
|
248
|
+
#
|
249
|
+
# Parameters:
|
250
|
+
# name: name of the instance
|
251
|
+
# os_name: name of the os
|
252
|
+
# nostartup: 0|1 (optional)
|
253
|
+
#
|
254
|
+
# Return:
|
255
|
+
# ?
|
256
|
+
def instance_reinstall(name, os_name, nostartup = 0)
|
149
257
|
url = get_url("instances/#{name}/reinstall", {"os" => os_name, "nostartup" => nostartup})
|
150
258
|
response_body = send_request("POST", url)
|
151
259
|
|
152
|
-
|
153
|
-
|
154
|
-
return GanetiInstanceReinstall.new(response_body)
|
260
|
+
return response_body
|
155
261
|
end
|
156
262
|
|
157
263
|
# Replaces disks on an instance
|
158
264
|
# Takes the parameters mode (one of replace_on_primary, replace_on_secondary or replace_auto), disks (comma seperated list of disk indexes), remote_node and iallocator
|
159
265
|
# Either remote_node or iallocator needs to be defined when using mode=replace_new_secondary
|
160
266
|
# mode is a mandatory parameter. replace_auto tries to determine the broken disk(s) on its own and replacing it
|
267
|
+
#
|
268
|
+
# Parameters:
|
269
|
+
# name: name of the instance
|
270
|
+
# mode replace_on_primary|replace_on_secondary|replace_auto (optional)
|
271
|
+
# ialllocator:
|
272
|
+
# remote_node:
|
273
|
+
# disks: comma seperated list of disk indexes
|
274
|
+
#
|
275
|
+
# Return:
|
276
|
+
# ?
|
161
277
|
def instance_replace_disks(name, mode = "replace_auto", iallocator = "", remote_node = "", disks = "")
|
162
278
|
url = get_url("instances/#{name}/replace-disks", {"mode" => mode, "iallocator" => iallocator, "remote_node" => remote_node, "disks" => disks})
|
163
279
|
response_body = send_request("POST", url)
|
164
280
|
|
165
|
-
return
|
281
|
+
return response_body
|
166
282
|
end
|
167
283
|
|
168
284
|
# Activate disks on an instance
|
169
285
|
# Takes the bool parameter ignore_size. When set ignore the recorded size (useful for forcing activation when recoreded size is wrong)
|
286
|
+
#
|
287
|
+
# Parameters:
|
288
|
+
# name: name of the instance
|
289
|
+
# ignore_size: 0|1 (optional)
|
290
|
+
#
|
291
|
+
# Return:
|
292
|
+
# ?
|
170
293
|
def intance_activate_disks(name, ignore_size = 0)
|
171
294
|
url = get_url("instances/#{name}/activate-disks", {"ignore_size" => ignore_size})
|
172
295
|
response_body = send_request("PUT", url)
|
173
296
|
|
174
|
-
return
|
297
|
+
return response_body
|
175
298
|
end
|
176
299
|
|
177
300
|
# Deactivate disks on an instance
|
178
|
-
#
|
301
|
+
#
|
302
|
+
# Parameters:
|
303
|
+
# name: name of the instance
|
304
|
+
#
|
305
|
+
# Return:
|
306
|
+
# ?
|
179
307
|
def instance_deactivate_disks(name)
|
180
308
|
url = get_url("instances/#{name}/deactivate-disks")
|
181
309
|
response_body = send_request("PUT", url)
|
182
310
|
|
183
|
-
return
|
311
|
+
return response_body
|
184
312
|
end
|
185
313
|
|
186
314
|
# Returns a list of tags
|
187
315
|
#
|
188
|
-
#
|
189
|
-
#
|
316
|
+
# Parameters:
|
317
|
+
# name: name of the instance
|
318
|
+
#
|
319
|
+
# Return:
|
320
|
+
# Array of tags
|
190
321
|
def instance_get_tags(name)
|
191
322
|
url = get_url("instances/#{name}/tags")
|
192
323
|
response_body = JSON.parse(send_request("GET", url))
|
@@ -195,28 +326,41 @@ module GanetiClient
|
|
195
326
|
end
|
196
327
|
|
197
328
|
# Add a set of tags
|
198
|
-
#
|
199
|
-
#
|
200
|
-
|
201
|
-
|
329
|
+
#
|
330
|
+
# Parameters:
|
331
|
+
# name: name of the instance
|
332
|
+
# tags: Array of tags
|
333
|
+
# dry_run: 0|1 (optional)
|
334
|
+
#
|
335
|
+
# Return:
|
336
|
+
# ?
|
337
|
+
def instance_create_tags(name, tags, dry_run = 0)
|
338
|
+
url = get_url("instances/#{name}/tags", {"tags" => tags, "dry-run" => dry_run})
|
202
339
|
response_body = send_request("PUT", url)
|
203
340
|
|
204
341
|
return response_body
|
205
342
|
end
|
206
343
|
|
207
|
-
# Delete a tag
|
208
|
-
#
|
209
|
-
#
|
210
|
-
#
|
211
|
-
|
212
|
-
|
344
|
+
# Delete (a) tag(s) on an instance
|
345
|
+
#
|
346
|
+
# Parameters:
|
347
|
+
# name: name of the instance
|
348
|
+
# tags: Array of tags
|
349
|
+
# dry_run: 0|1 (optional)
|
350
|
+
#
|
351
|
+
# Return:
|
352
|
+
# ?
|
353
|
+
def instance_delete_tags(name, tags, dry_run = 0)
|
354
|
+
url = get_url("instances/#{name}/tags", {"tags" => tags, "dry-run" => dry_run})
|
213
355
|
response_body = send_request("DELETE", url)
|
214
356
|
|
215
|
-
return
|
357
|
+
return response_body
|
216
358
|
end
|
217
359
|
|
218
360
|
# Returns a dictionary of jobs
|
219
|
-
#
|
361
|
+
#
|
362
|
+
# Return:
|
363
|
+
# Array of GanetiJob objects
|
220
364
|
def jobs_get
|
221
365
|
url = get_url("jobs")
|
222
366
|
response_body = JSON.parse(send_request("GET", url))
|
@@ -287,11 +431,17 @@ module GanetiClient
|
|
287
431
|
end
|
288
432
|
|
289
433
|
# Cancel a not-yet-started job
|
434
|
+
#
|
435
|
+
# Parameters:
|
436
|
+
# job_id: id of a job
|
437
|
+
#
|
438
|
+
# Return:
|
439
|
+
# ?
|
290
440
|
def job_delete(job_id)
|
291
441
|
url = get_url("jobs/#{job_id}")
|
292
442
|
response = send_request("DELETE", url)
|
293
443
|
|
294
|
-
return
|
444
|
+
return response_body
|
295
445
|
end
|
296
446
|
|
297
447
|
# Nodes resource
|
@@ -331,7 +481,7 @@ module GanetiClient
|
|
331
481
|
url = get_url("nodes/#{name}/evacuate", {"iallocator" => iallocator, "remote_node" => remote_node})
|
332
482
|
response_body = send_request("POST", url)
|
333
483
|
|
334
|
-
return
|
484
|
+
return response_body
|
335
485
|
end
|
336
486
|
|
337
487
|
# Migrates all primary instances of a node
|
@@ -343,7 +493,7 @@ module GanetiClient
|
|
343
493
|
url = get_url("nodes/#{name}/migrate", {"live" => live})
|
344
494
|
response_body = send_request("POST", url)
|
345
495
|
|
346
|
-
return
|
496
|
+
return response_body
|
347
497
|
end
|
348
498
|
|
349
499
|
# Get the node role
|
@@ -515,9 +665,9 @@ module GanetiClient
|
|
515
665
|
private
|
516
666
|
|
517
667
|
def authenticate(username, password)
|
518
|
-
basic = Base64.
|
668
|
+
basic = Base64.encode64("#{username}:#{password}").strip
|
519
669
|
headers = {'Authorization' => "Basic #{basic}"}
|
520
|
-
|
670
|
+
|
521
671
|
return headers
|
522
672
|
end
|
523
673
|
|
@@ -528,20 +678,33 @@ module GanetiClient
|
|
528
678
|
params.each do |key, value|
|
529
679
|
if value.kind_of?(Array)
|
530
680
|
value.each do |svalue|
|
531
|
-
param_string += "#{key}=#{svalue}"
|
681
|
+
param_string += "#{key}=#{svalue}&"
|
532
682
|
end
|
533
683
|
else
|
534
684
|
param_string += "#{key}=#{value}&"
|
535
685
|
end
|
536
686
|
end
|
537
687
|
end
|
538
|
-
|
688
|
+
|
689
|
+
url = (self.version)? "/#{self.version}/#{path}?#{param_string}" : "/#{path}?#{param_string}"
|
690
|
+
|
691
|
+
return url.chop
|
539
692
|
end
|
540
693
|
|
541
694
|
def send_request(method, url, body = nil)
|
542
|
-
|
695
|
+
uri = URI.parse(host)
|
696
|
+
|
697
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
698
|
+
http.use_ssl = (uri.scheme == "http")? false : true
|
699
|
+
|
700
|
+
headers = {}
|
701
|
+
headers = authenticate(self.username, self.password) if method != 'GET'
|
702
|
+
|
703
|
+
response = http.send_request(method, url, body, headers)
|
704
|
+
|
705
|
+
|
706
|
+
puts "Response #{response.code} #{response.message}: #{response.body}" if self.show_response
|
543
707
|
|
544
|
-
puts "Response #{response.code} #{response.message}: #{response.body}" if self.show_reponse
|
545
708
|
return response.body.strip
|
546
709
|
end
|
547
710
|
|
data/lib/ganeti_client.rb
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010 Michaël Rigart
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
|
1
25
|
require 'net/http'
|
2
26
|
require 'net/https'
|
3
27
|
require 'uri'
|
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: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Micha\xC3\xABl Rigart"
|