ucloudstack 0.0.1
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/CHANGES.rdoc +68 -0
- data/LICENSE +202 -0
- data/README.rdoc +215 -0
- data/lib/chef/knife/cs_hosts.rb +83 -0
- data/lib/chef/knife/cs_network_list.rb +84 -0
- data/lib/chef/knife/cs_product_list.rb +70 -0
- data/lib/chef/knife/cs_server_create.rb +321 -0
- data/lib/chef/knife/cs_server_delete.rb +157 -0
- data/lib/chef/knife/cs_server_list.rb +92 -0
- data/lib/chef/knife/cs_server_reboot.rb +103 -0
- data/lib/chef/knife/cs_server_start.rb +103 -0
- data/lib/chef/knife/cs_server_stop.rb +114 -0
- data/lib/chef/knife/cs_service_list.rb +93 -0
- data/lib/chef/knife/cs_stack_create.rb +325 -0
- data/lib/chef/knife/cs_stack_delete.rb +88 -0
- data/lib/chef/knife/cs_template_list.rb +100 -0
- data/lib/chef/knife/cs_zone_list.rb +78 -0
- data/lib/knife-cloudstack/connection.rb +633 -0
- metadata +90 -0
@@ -0,0 +1,633 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Ryan Holmes (<rholmes@edmunds.com>)
|
3
|
+
# Author:: KC Braunschweig (<kbraunschweig@edmunds.com>)
|
4
|
+
# Copyright:: Copyright (c) 2011 Edmunds, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'rubygems'
|
21
|
+
require 'base64'
|
22
|
+
require 'openssl'
|
23
|
+
require 'uri'
|
24
|
+
require 'cgi'
|
25
|
+
require 'net/http'
|
26
|
+
require 'net/https'
|
27
|
+
require 'json'
|
28
|
+
|
29
|
+
module CloudstackClient
|
30
|
+
class Connection
|
31
|
+
|
32
|
+
ASYNC_POLL_INTERVAL = 5.0
|
33
|
+
ASYNC_TIMEOUT = 300
|
34
|
+
|
35
|
+
def initialize(api_url, api_key, secret_key)
|
36
|
+
@api_url = api_url
|
37
|
+
@api_key = api_key
|
38
|
+
@secret_key = secret_key
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Finds the server with the specified name.
|
43
|
+
|
44
|
+
def get_server(name)
|
45
|
+
params = {
|
46
|
+
'command' => 'listVirtualMachines',
|
47
|
+
'name' => name
|
48
|
+
}
|
49
|
+
json = send_request(params)
|
50
|
+
machines = json['virtualmachine']
|
51
|
+
|
52
|
+
if !machines || machines.empty? then
|
53
|
+
return nil
|
54
|
+
end
|
55
|
+
|
56
|
+
machines.first
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Finds the public ip for a server
|
61
|
+
|
62
|
+
def get_server_public_ip(server, cached_rules=nil)
|
63
|
+
return nil unless server
|
64
|
+
|
65
|
+
# find the public ip
|
66
|
+
nic = get_server_default_nic(server) || {}
|
67
|
+
if nic['type'] == 'Virtual' then
|
68
|
+
ssh_rule = get_ssh_port_forwarding_rule(server, cached_rules)
|
69
|
+
ssh_rule ? ssh_rule['ipaddress'] : nil
|
70
|
+
else
|
71
|
+
nic['ipaddress']
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Returns the fully qualified domain name for a server.
|
77
|
+
|
78
|
+
def get_server_fqdn(server)
|
79
|
+
return nil unless server
|
80
|
+
|
81
|
+
nic = get_server_default_nic(server) || {}
|
82
|
+
networks = list_networks || {}
|
83
|
+
|
84
|
+
id = nic['networkid']
|
85
|
+
network = networks.select { |net|
|
86
|
+
net['id'] == id
|
87
|
+
}.first
|
88
|
+
return nil unless network
|
89
|
+
|
90
|
+
"#{server['name']}.#{network['networkdomain']}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_server_default_nic(server)
|
94
|
+
server['nic'].each do |nic|
|
95
|
+
return nic if nic['isdefault']
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Lists all the servers in your account.
|
101
|
+
|
102
|
+
def list_servers
|
103
|
+
params = {
|
104
|
+
'command' => 'listVirtualMachines'
|
105
|
+
}
|
106
|
+
json = send_request(params)
|
107
|
+
json['virtualmachine'] || []
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Deploys a new server using the specified parameters.
|
112
|
+
|
113
|
+
def create_server(host_name, service_name, template_name, zone_name=nil, network_names=[])
|
114
|
+
|
115
|
+
if host_name then
|
116
|
+
if get_server(host_name) then
|
117
|
+
puts "Error: Server '#{host_name}' already exists."
|
118
|
+
exit 1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#service = get_service_offering(service_name)
|
123
|
+
#if !service then
|
124
|
+
# puts "Error: Service offering '#{service_name}' is invalid"
|
125
|
+
# exit 1
|
126
|
+
#end
|
127
|
+
|
128
|
+
#template = get_template(template_name)
|
129
|
+
#if !template then
|
130
|
+
# puts "Error: Template '#{template_name}' is invalid"
|
131
|
+
# exit 1
|
132
|
+
#end
|
133
|
+
|
134
|
+
#zone = zone_name ? get_zone(zone_name) : get_default_zone
|
135
|
+
#if !zone then
|
136
|
+
# msg = zone_name ? "Zone '#{zone_name}' is invalid" : "No default zone found"
|
137
|
+
# puts "Error: #{msg}"
|
138
|
+
# exit 1
|
139
|
+
#end
|
140
|
+
|
141
|
+
#networks = []
|
142
|
+
#network_names.each do |name|
|
143
|
+
# network = get_network(name)
|
144
|
+
# if !network then
|
145
|
+
# puts "Error: Network '#{name}' not found"
|
146
|
+
# exit 1
|
147
|
+
# end
|
148
|
+
# networks << get_network(name)
|
149
|
+
#end
|
150
|
+
#if networks.empty? then
|
151
|
+
# networks << get_default_network
|
152
|
+
#end
|
153
|
+
#if networks.empty? then
|
154
|
+
# puts "No default network found"
|
155
|
+
# exit 1
|
156
|
+
#end
|
157
|
+
#network_ids = networks.map { |network|
|
158
|
+
# network['id']
|
159
|
+
#}
|
160
|
+
|
161
|
+
params = {
|
162
|
+
'command' => 'deployVirtualMachine',
|
163
|
+
'serviceOfferingId' => service_name,
|
164
|
+
#'serviceOfferingId' => service['id'],
|
165
|
+
'templateId' => template_name,
|
166
|
+
#'templateId' => template['id'],
|
167
|
+
'zoneId' => zone_name
|
168
|
+
#'zoneId' => zone['id'],
|
169
|
+
#'networkids' => network_ids.join(',')
|
170
|
+
}
|
171
|
+
params['name'] = host_name if host_name
|
172
|
+
|
173
|
+
json = send_async_request(params)
|
174
|
+
json['virtualmachine']
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# Deletes the server with the specified name.
|
179
|
+
#
|
180
|
+
|
181
|
+
def delete_server(name)
|
182
|
+
server = get_server(name)
|
183
|
+
if !server || !server['id'] then
|
184
|
+
puts "Error: Virtual machine '#{name}' does not exist"
|
185
|
+
exit 1
|
186
|
+
end
|
187
|
+
|
188
|
+
params = {
|
189
|
+
'command' => 'destroyVirtualMachine',
|
190
|
+
'id' => server['id']
|
191
|
+
}
|
192
|
+
|
193
|
+
json = send_async_request(params)
|
194
|
+
json['virtualmachine']
|
195
|
+
end
|
196
|
+
|
197
|
+
##
|
198
|
+
# Stops the server with the specified name.
|
199
|
+
#
|
200
|
+
|
201
|
+
def stop_server(name, forced=nil)
|
202
|
+
server = get_server(name)
|
203
|
+
if !server || !server['id'] then
|
204
|
+
puts "Error: Virtual machine '#{name}' does not exist"
|
205
|
+
exit 1
|
206
|
+
end
|
207
|
+
|
208
|
+
params = {
|
209
|
+
'command' => 'stopVirtualMachine',
|
210
|
+
'id' => server['id']
|
211
|
+
}
|
212
|
+
params['forced'] = true if forced
|
213
|
+
|
214
|
+
json = send_async_request(params)
|
215
|
+
json['virtualmachine']
|
216
|
+
end
|
217
|
+
|
218
|
+
##
|
219
|
+
# Start the server with the specified name.
|
220
|
+
#
|
221
|
+
|
222
|
+
def start_server(name)
|
223
|
+
server = get_server(name)
|
224
|
+
if !server || !server['id'] then
|
225
|
+
puts "Error: Virtual machine '#{name}' does not exist"
|
226
|
+
exit 1
|
227
|
+
end
|
228
|
+
|
229
|
+
params = {
|
230
|
+
'command' => 'startVirtualMachine',
|
231
|
+
'id' => server['id']
|
232
|
+
}
|
233
|
+
|
234
|
+
json = send_async_request(params)
|
235
|
+
json['virtualmachine']
|
236
|
+
end
|
237
|
+
|
238
|
+
##
|
239
|
+
# Reboot the server with the specified name.
|
240
|
+
#
|
241
|
+
|
242
|
+
def reboot_server(name)
|
243
|
+
server = get_server(name)
|
244
|
+
if !server || !server['id'] then
|
245
|
+
puts "Error: Virtual machine '#{name}' does not exist"
|
246
|
+
exit 1
|
247
|
+
end
|
248
|
+
|
249
|
+
params = {
|
250
|
+
'command' => 'rebootVirtualMachine',
|
251
|
+
'id' => server['id']
|
252
|
+
}
|
253
|
+
|
254
|
+
json = send_async_request(params)
|
255
|
+
json['virtualmachine']
|
256
|
+
end
|
257
|
+
|
258
|
+
##
|
259
|
+
# Finds the service offering with the specified name.
|
260
|
+
|
261
|
+
def get_service_offering(name)
|
262
|
+
|
263
|
+
# TODO: use name parameter
|
264
|
+
# listServiceOfferings in CloudStack 2.2 doesn't seem to work
|
265
|
+
# when the name parameter is specified. When this is fixed,
|
266
|
+
# the name parameter should be added to the request.
|
267
|
+
params = {
|
268
|
+
'command' => 'listServiceOfferings'
|
269
|
+
}
|
270
|
+
json = send_request(params)
|
271
|
+
|
272
|
+
services = json['serviceoffering']
|
273
|
+
return nil unless services
|
274
|
+
|
275
|
+
services.each { |s|
|
276
|
+
if s['name'] == name then
|
277
|
+
return s
|
278
|
+
end
|
279
|
+
}
|
280
|
+
|
281
|
+
nil
|
282
|
+
end
|
283
|
+
|
284
|
+
##
|
285
|
+
# Lists all available service offerings.
|
286
|
+
|
287
|
+
def list_service_offerings
|
288
|
+
params = {
|
289
|
+
'command' => 'listServiceOfferings'
|
290
|
+
}
|
291
|
+
json = send_request(params)
|
292
|
+
json['serviceoffering'] || []
|
293
|
+
end
|
294
|
+
|
295
|
+
##
|
296
|
+
# Finds the template with the specified name.
|
297
|
+
|
298
|
+
def get_template(name)
|
299
|
+
|
300
|
+
# TODO: use name parameter
|
301
|
+
# listTemplates in CloudStack 2.2 doesn't seem to work
|
302
|
+
# when the name parameter is specified. When this is fixed,
|
303
|
+
# the name parameter should be added to the request.
|
304
|
+
params = {
|
305
|
+
'command' => 'listTemplates',
|
306
|
+
'templateFilter' => 'executable'
|
307
|
+
}
|
308
|
+
json = send_request(params)
|
309
|
+
|
310
|
+
templates = json['template']
|
311
|
+
if !templates then
|
312
|
+
return nil
|
313
|
+
end
|
314
|
+
|
315
|
+
templates.each { |t|
|
316
|
+
if t['name'] == name then
|
317
|
+
return t
|
318
|
+
end
|
319
|
+
}
|
320
|
+
|
321
|
+
nil
|
322
|
+
end
|
323
|
+
|
324
|
+
##
|
325
|
+
# Lists all templates that match the specified filter.
|
326
|
+
#
|
327
|
+
# Allowable filter values are:
|
328
|
+
#
|
329
|
+
# * featured - templates that are featured and are public
|
330
|
+
# * self - templates that have been registered/created by the owner
|
331
|
+
# * self-executable - templates that have been registered/created by the owner that can be used to deploy a new VM
|
332
|
+
# * executable - all templates that can be used to deploy a new VM
|
333
|
+
# * community - templates that are public
|
334
|
+
|
335
|
+
def list_templates(filter)
|
336
|
+
filter ||= 'featured'
|
337
|
+
params = {
|
338
|
+
'command' => 'listTemplates',
|
339
|
+
'templatefilter' => filter
|
340
|
+
}
|
341
|
+
json = send_request(params)
|
342
|
+
json['template'] || []
|
343
|
+
end
|
344
|
+
|
345
|
+
##
|
346
|
+
# Finds the network with the specified name.
|
347
|
+
|
348
|
+
def get_network(name)
|
349
|
+
params = {
|
350
|
+
'command' => 'listNetworks'
|
351
|
+
}
|
352
|
+
json = send_request(params)
|
353
|
+
|
354
|
+
networks = json['network']
|
355
|
+
return nil unless networks
|
356
|
+
|
357
|
+
networks.each { |n|
|
358
|
+
if n['name'] == name then
|
359
|
+
return n
|
360
|
+
end
|
361
|
+
}
|
362
|
+
|
363
|
+
nil
|
364
|
+
end
|
365
|
+
|
366
|
+
##
|
367
|
+
# Finds the default network.
|
368
|
+
|
369
|
+
def get_default_network
|
370
|
+
params = {
|
371
|
+
'command' => 'listNetworks',
|
372
|
+
'isDefault' => true
|
373
|
+
}
|
374
|
+
json = send_request(params)
|
375
|
+
|
376
|
+
networks = json['network']
|
377
|
+
return nil if !networks || networks.empty?
|
378
|
+
|
379
|
+
default = networks.first
|
380
|
+
return default if networks.length == 1
|
381
|
+
|
382
|
+
networks.each { |n|
|
383
|
+
if n['type'] == 'Direct' then
|
384
|
+
default = n
|
385
|
+
break
|
386
|
+
end
|
387
|
+
}
|
388
|
+
|
389
|
+
default
|
390
|
+
end
|
391
|
+
|
392
|
+
##
|
393
|
+
# Lists all available networks.
|
394
|
+
|
395
|
+
def list_networks
|
396
|
+
params = {
|
397
|
+
'command' => 'listNetworks'
|
398
|
+
}
|
399
|
+
json = send_request(params)
|
400
|
+
json['network'] || []
|
401
|
+
end
|
402
|
+
|
403
|
+
##
|
404
|
+
# Finds the zone with the specified name.
|
405
|
+
|
406
|
+
def get_zone(name)
|
407
|
+
params = {
|
408
|
+
'command' => 'listZones',
|
409
|
+
'available' => 'true'
|
410
|
+
}
|
411
|
+
json = send_request(params)
|
412
|
+
|
413
|
+
networks = json['zone']
|
414
|
+
return nil unless networks
|
415
|
+
|
416
|
+
networks.each { |z|
|
417
|
+
if z['name'] == name then
|
418
|
+
return z
|
419
|
+
end
|
420
|
+
}
|
421
|
+
|
422
|
+
nil
|
423
|
+
end
|
424
|
+
|
425
|
+
##
|
426
|
+
# Finds the default zone for your account.
|
427
|
+
|
428
|
+
def get_default_zone
|
429
|
+
params = {
|
430
|
+
'command' => 'listZones',
|
431
|
+
'available' => 'true'
|
432
|
+
}
|
433
|
+
json = send_request(params)
|
434
|
+
|
435
|
+
zones = json['zone']
|
436
|
+
return nil unless zones
|
437
|
+
|
438
|
+
zones.first
|
439
|
+
end
|
440
|
+
|
441
|
+
##
|
442
|
+
# Lists all available zones.
|
443
|
+
|
444
|
+
def list_zones
|
445
|
+
params = {
|
446
|
+
'command' => 'listZones',
|
447
|
+
'available' => 'true'
|
448
|
+
}
|
449
|
+
json = send_request(params)
|
450
|
+
json['zone'] || []
|
451
|
+
end
|
452
|
+
|
453
|
+
##
|
454
|
+
# Finds the public ip address for a given ip address string.
|
455
|
+
|
456
|
+
def get_public_ip_address(ip_address)
|
457
|
+
params = {
|
458
|
+
'command' => 'listPublicIpAddresses',
|
459
|
+
'ipaddress' => ip_address
|
460
|
+
}
|
461
|
+
json = send_request(params)
|
462
|
+
json['publicipaddress'].first
|
463
|
+
end
|
464
|
+
|
465
|
+
|
466
|
+
##
|
467
|
+
# Acquires and associates a public IP to an account.
|
468
|
+
|
469
|
+
def associate_ip_address(zone_id)
|
470
|
+
params = {
|
471
|
+
'command' => 'associateIpAddress',
|
472
|
+
'zoneId' => zone_id
|
473
|
+
}
|
474
|
+
|
475
|
+
json = send_async_request(params)
|
476
|
+
json['ipaddress']
|
477
|
+
end
|
478
|
+
|
479
|
+
##
|
480
|
+
# Disassociates an ip address from the account.
|
481
|
+
#
|
482
|
+
# Returns true if successful, false otherwise.
|
483
|
+
|
484
|
+
def disassociate_ip_address(id)
|
485
|
+
params = {
|
486
|
+
'command' => 'disassociateIpAddress',
|
487
|
+
'id' => id
|
488
|
+
}
|
489
|
+
json = send_async_request(params)
|
490
|
+
json['success']
|
491
|
+
end
|
492
|
+
|
493
|
+
##
|
494
|
+
# Lists all port forwarding rules.
|
495
|
+
|
496
|
+
def list_port_forwarding_rules(ip_address_id=nil)
|
497
|
+
params = {
|
498
|
+
'command' => 'listPortForwardingRules'
|
499
|
+
}
|
500
|
+
params['ipAddressId'] = ip_address_id if ip_address_id
|
501
|
+
json = send_request(params)
|
502
|
+
json['portforwardingrule']
|
503
|
+
end
|
504
|
+
|
505
|
+
##
|
506
|
+
# Gets the SSH port forwarding rule for the specified server.
|
507
|
+
|
508
|
+
def get_ssh_port_forwarding_rule(server, cached_rules=nil)
|
509
|
+
rules = cached_rules || list_port_forwarding_rules || []
|
510
|
+
rules.find_all { |r|
|
511
|
+
r['virtualmachineid'] == server['id'] &&
|
512
|
+
r['privateport'] == '22'&&
|
513
|
+
r['publicport'] == '22'
|
514
|
+
}.first
|
515
|
+
end
|
516
|
+
|
517
|
+
##
|
518
|
+
# Creates a port forwarding rule.
|
519
|
+
|
520
|
+
def create_port_forwarding_rule(ip_address_id, private_port, protocol, public_port, virtual_machine_id)
|
521
|
+
params = {
|
522
|
+
'command' => 'createPortForwardingRule',
|
523
|
+
'ipAddressId' => ip_address_id,
|
524
|
+
'privatePort' => private_port,
|
525
|
+
'protocol' => protocol,
|
526
|
+
'publicPort' => public_port,
|
527
|
+
'virtualMachineId' => virtual_machine_id
|
528
|
+
}
|
529
|
+
json = send_async_request(params)
|
530
|
+
json['portforwardingrule']
|
531
|
+
end
|
532
|
+
|
533
|
+
##
|
534
|
+
# Lists all the available products list in your account.
|
535
|
+
|
536
|
+
def list_products
|
537
|
+
params = {
|
538
|
+
'command' => 'listAvailableProductTypes'
|
539
|
+
}
|
540
|
+
|
541
|
+
json = send_request(params)
|
542
|
+
|
543
|
+
json["producttypes"] || []
|
544
|
+
|
545
|
+
#json['virtualmachine'] || []
|
546
|
+
end
|
547
|
+
|
548
|
+
|
549
|
+
##
|
550
|
+
# Sends a synchronous request to the CloudStack API and returns the response as a Hash.
|
551
|
+
#
|
552
|
+
# The wrapper element of the response (e.g. mycommandresponse) is discarded and the
|
553
|
+
# contents of that element are returned.
|
554
|
+
|
555
|
+
def send_request(params)
|
556
|
+
params['response'] = 'json'
|
557
|
+
params['apiKey'] = @api_key
|
558
|
+
|
559
|
+
params_arr = []
|
560
|
+
params.sort.each { |elem|
|
561
|
+
params_arr << elem[0].to_s + '=' + elem[1].to_s
|
562
|
+
}
|
563
|
+
data = params_arr.join('&')
|
564
|
+
encoded_data = URI.encode(data.downcase).gsub('+', '%20').gsub(',', '%2c')
|
565
|
+
signature = OpenSSL::HMAC.digest('sha1', @secret_key, encoded_data)
|
566
|
+
signature = Base64.encode64(signature).chomp
|
567
|
+
signature = CGI.escape(signature)
|
568
|
+
|
569
|
+
raw_url = "#{@api_url}?#{data}&signature=#{signature}"
|
570
|
+
|
571
|
+
#puts "request url : " + raw_url
|
572
|
+
url = URI.parse(raw_url)
|
573
|
+
|
574
|
+
http = Net::HTTP.new(url.host, url.port)
|
575
|
+
|
576
|
+
http.use_ssl = (url.scheme == 'https')
|
577
|
+
request = Net::HTTP::Get.new(url.to_s)
|
578
|
+
response = http.request(request)
|
579
|
+
|
580
|
+
#response = Net::HTTP.get_response(URI.parse(url))
|
581
|
+
|
582
|
+
if !response.is_a?(Net::HTTPOK) then
|
583
|
+
puts "Error #{response.code}: #{response.message}"
|
584
|
+
puts JSON.pretty_generate(JSON.parse(response.body))
|
585
|
+
puts "URL: #{url}"
|
586
|
+
exit 1
|
587
|
+
end
|
588
|
+
|
589
|
+
json = JSON.parse(response.body)
|
590
|
+
json[params['command'].downcase + 'response']
|
591
|
+
end
|
592
|
+
|
593
|
+
##
|
594
|
+
# Sends an asynchronous request and waits for the response.
|
595
|
+
#
|
596
|
+
# The contents of the 'jobresult' element are returned upon completion of the command.
|
597
|
+
|
598
|
+
def send_async_request(params)
|
599
|
+
|
600
|
+
json = send_request(params)
|
601
|
+
#puts json
|
602
|
+
params = {
|
603
|
+
'command' => 'queryAsyncJobResult',
|
604
|
+
'jobId' => json['jobid']
|
605
|
+
}
|
606
|
+
|
607
|
+
max_tries = (ASYNC_TIMEOUT / ASYNC_POLL_INTERVAL).round
|
608
|
+
max_tries.times do
|
609
|
+
json = send_request(params)
|
610
|
+
status = json['jobstatus']
|
611
|
+
#puts json
|
612
|
+
print "."
|
613
|
+
|
614
|
+
if status == 1 then
|
615
|
+
return json['jobresult']
|
616
|
+
elsif status == 2 then
|
617
|
+
print "\n"
|
618
|
+
puts "Request failed (#{json['jobresultcode']}): #{json['jobresult']}"
|
619
|
+
exit 1
|
620
|
+
end
|
621
|
+
|
622
|
+
STDOUT.flush
|
623
|
+
sleep ASYNC_POLL_INTERVAL
|
624
|
+
end
|
625
|
+
|
626
|
+
print "\n"
|
627
|
+
puts "Error: Asynchronous request timed out"
|
628
|
+
exit 1
|
629
|
+
end
|
630
|
+
|
631
|
+
end # class
|
632
|
+
end
|
633
|
+
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ucloudstack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Holmes
|
9
|
+
- KC Braunschweig
|
10
|
+
- John E. Vincent
|
11
|
+
- SeongSik. Kim
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2012-08-20 00:00:00 Z
|
17
|
+
dependencies:
|
18
|
+
- !ruby/object:Gem::Dependency
|
19
|
+
name: chef
|
20
|
+
prerelease: false
|
21
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
22
|
+
none: false
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.10.0
|
27
|
+
type: :runtime
|
28
|
+
version_requirements: *id001
|
29
|
+
description: A Knife plugin to create, list and manage ucloud servers
|
30
|
+
email:
|
31
|
+
- rholmes@edmunds.com
|
32
|
+
- kcbraunschweig@gmail.com
|
33
|
+
- lusis.org+github.com@gmail.com
|
34
|
+
- kssminus@gmail.com
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README.rdoc
|
41
|
+
- CHANGES.rdoc
|
42
|
+
- LICENSE
|
43
|
+
files:
|
44
|
+
- CHANGES.rdoc
|
45
|
+
- README.rdoc
|
46
|
+
- LICENSE
|
47
|
+
- lib/knife-cloudstack/connection.rb
|
48
|
+
- lib/chef/knife/cs_service_list.rb
|
49
|
+
- lib/chef/knife/cs_server_create.rb
|
50
|
+
- lib/chef/knife/cs_hosts.rb
|
51
|
+
- lib/chef/knife/cs_stack_create.rb
|
52
|
+
- lib/chef/knife/cs_product_list.rb
|
53
|
+
- lib/chef/knife/cs_network_list.rb
|
54
|
+
- lib/chef/knife/cs_template_list.rb
|
55
|
+
- lib/chef/knife/cs_zone_list.rb
|
56
|
+
- lib/chef/knife/cs_server_list.rb
|
57
|
+
- lib/chef/knife/cs_server_delete.rb
|
58
|
+
- lib/chef/knife/cs_server_reboot.rb
|
59
|
+
- lib/chef/knife/cs_server_start.rb
|
60
|
+
- lib/chef/knife/cs_server_stop.rb
|
61
|
+
- lib/chef/knife/cs_stack_delete.rb
|
62
|
+
homepage: http://cloudstack.org/
|
63
|
+
licenses: []
|
64
|
+
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
requirements: []
|
83
|
+
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.8.24
|
86
|
+
signing_key:
|
87
|
+
specification_version: 3
|
88
|
+
summary: A knife plugin for the ucloud API
|
89
|
+
test_files: []
|
90
|
+
|