staugaard-cloudmaster 0.1.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.
Files changed (52) hide show
  1. data/VERSION.yml +4 -0
  2. data/bin/cloudmaster +45 -0
  3. data/lib/AWS/AWS.rb +3 -0
  4. data/lib/AWS/EC2.rb +14 -0
  5. data/lib/AWS/S3.rb +14 -0
  6. data/lib/AWS/SQS.rb +14 -0
  7. data/lib/AWS/SimpleDB.rb +14 -0
  8. data/lib/MockAWS/EC2.rb +119 -0
  9. data/lib/MockAWS/S3.rb +39 -0
  10. data/lib/MockAWS/SQS.rb +82 -0
  11. data/lib/MockAWS/SimpleDB.rb +46 -0
  12. data/lib/MockAWS/clock.rb +67 -0
  13. data/lib/OriginalAWS/AWS.rb +475 -0
  14. data/lib/OriginalAWS/EC2.rb +783 -0
  15. data/lib/OriginalAWS/S3.rb +559 -0
  16. data/lib/OriginalAWS/SQS.rb +159 -0
  17. data/lib/OriginalAWS/SimpleDB.rb +460 -0
  18. data/lib/RetryAWS/EC2.rb +88 -0
  19. data/lib/RetryAWS/S3.rb +77 -0
  20. data/lib/RetryAWS/SQS.rb +109 -0
  21. data/lib/RetryAWS/SimpleDB.rb +118 -0
  22. data/lib/SafeAWS/EC2.rb +63 -0
  23. data/lib/SafeAWS/S3.rb +56 -0
  24. data/lib/SafeAWS/SQS.rb +75 -0
  25. data/lib/SafeAWS/SimpleDB.rb +88 -0
  26. data/lib/aws_context.rb +165 -0
  27. data/lib/basic_configuration.rb +120 -0
  28. data/lib/clock.rb +10 -0
  29. data/lib/factory.rb +14 -0
  30. data/lib/file_logger.rb +36 -0
  31. data/lib/inifile.rb +148 -0
  32. data/lib/instance_logger.rb +25 -0
  33. data/lib/logger_factory.rb +38 -0
  34. data/lib/periodic.rb +29 -0
  35. data/lib/string_logger.rb +29 -0
  36. data/lib/sys_logger.rb +40 -0
  37. data/lib/user_data.rb +30 -0
  38. data/test/aws-config.ini +9 -0
  39. data/test/cloudmaster-tests.rb +329 -0
  40. data/test/configuration-test.rb +62 -0
  41. data/test/daytime-policy-tests.rb +47 -0
  42. data/test/enumerator-test.rb +47 -0
  43. data/test/fixed-policy-tests.rb +50 -0
  44. data/test/instance-pool-test.rb +359 -0
  45. data/test/instance-test.rb +98 -0
  46. data/test/job-policy-test.rb +95 -0
  47. data/test/manual-policy-tests.rb +63 -0
  48. data/test/named-queue-test.rb +90 -0
  49. data/test/resource-policy-tests.rb +126 -0
  50. data/test/suite +17 -0
  51. data/test/test-config.ini +47 -0
  52. metadata +111 -0
@@ -0,0 +1,783 @@
1
+ # Sample Ruby code for the O'Reilly book "Programming Amazon Web
2
+ # Services" by James Murty.
3
+ #
4
+ # This code was written for Ruby version 1.8.6 or greater.
5
+ #
6
+ # The EC2 module implements the Query API of the Amazon Elastic Compute Cloud
7
+ # service.
8
+ #
9
+ # Extended by Charles Hayden to cover EBS interface extensions.
10
+ require 'AWS'
11
+
12
+ class EC2
13
+ include AWS # Include the AWS module as a mixin
14
+
15
+ ENDPOINT_URI = URI.parse("https://ec2.amazonaws.com/")
16
+ API_VERSION = '2008-08-08'
17
+ SIGNATURE_VERSION = '1'
18
+
19
+ HTTP_METHOD = 'POST' # 'GET'
20
+
21
+ def parse_reservation(elem)
22
+ reservation = {
23
+ :reservation_id => elem.elements['reservationId'].text,
24
+ :owner_id => elem.elements['ownerId'].text,
25
+ }
26
+
27
+ group_names = []
28
+ elem.elements.each('groupSet/item') do |group|
29
+ group_names << group.elements['groupId'].text
30
+ end
31
+ reservation[:groups] = group_names
32
+
33
+ reservation[:instances] = []
34
+ elem.elements.each('instancesSet/item') do |instance|
35
+ elems = instance.elements
36
+ item = {
37
+ :id => elems['instanceId'].text,
38
+ :image_id => elems['imageId'].text,
39
+ :state => elems['instanceState/name'].text,
40
+ :private_dns => elems['privateDnsName'].text,
41
+ :public_dns => elems['dnsName'].text,
42
+ :type => elems['instanceType'].text,
43
+ :launch_time => elems['launchTime'].text
44
+ }
45
+
46
+ item[:reason] = elems['reason'].text if elems['reason']
47
+ item[:key_name] = elems['keyName'].text if elems['keyName']
48
+ item[:index] = elems['amiLaunchIndex'].text if elems['amiLaunchIndex']
49
+ if elems['placement']
50
+ item[:zone] = elems['placement/availabilityZone'].text
51
+ end
52
+ item[:kernel_id] = elems['kernelId'].text if elems['kernelId']
53
+ item[:ramdisk_id] = elems['ramdiskId'].text if elems['ramdiskId']
54
+
55
+ if elems['productCodes']
56
+ item[:product_codes] = []
57
+ elems.each('productCodes/item/productCode') do |code|
58
+ item[:product_codes] << code.text
59
+ end
60
+ end
61
+
62
+ reservation[:instances] << item
63
+ end
64
+
65
+ return reservation
66
+ end
67
+
68
+ def parse_volume(elem)
69
+ volume = {
70
+ :volume_id => elem.elements['volumeId'].text,
71
+ :size => elem.elements['size'].text,
72
+ :status => elem.elements['status'].text,
73
+ :create_time => elem.elements['createTime'].text,
74
+ :snapshot_id => elem.elements['snapshotId'].text,
75
+ :availability_zone => elem.elements['availabilityZone'].text,
76
+ }
77
+ attachments = []
78
+ elem.elements.each('attachmentSet/item') do |attachment|
79
+ attachments << {
80
+ :volume_id => attachment.elements['volumeId'].text,
81
+ :instance_id => attachment.elements['instanceId'].text,
82
+ :device => attachment.elements['device'].text,
83
+ :status => attachment.elements['status'].text,
84
+ :attach_time => attachment.elements['attachTime'].text
85
+ }
86
+ end
87
+ volume[:attachment_set] = attachments
88
+ return volume
89
+ end
90
+
91
+ def describe_instances(*instance_ids)
92
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
93
+ {
94
+ 'Action' => 'DescribeInstances',
95
+ },{
96
+ 'InstanceId' => instance_ids
97
+ })
98
+
99
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
100
+ xml_doc = REXML::Document.new(response.body)
101
+
102
+ reservations = []
103
+ xml_doc.elements.each('//reservationSet/item') do |elem|
104
+ reservations << parse_reservation(elem)
105
+ end
106
+ return reservations
107
+ end
108
+
109
+ def describe_availability_zones(*names)
110
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
111
+ {
112
+ 'Action' => 'DescribeAvailabilityZones',
113
+ },{
114
+ 'ZoneName' => names
115
+ })
116
+
117
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
118
+ xml_doc = REXML::Document.new(response.body)
119
+
120
+ zones = []
121
+ xml_doc.elements.each('//availabilityZoneInfo/item') do |elem|
122
+ zones << {
123
+ :name => elem.elements['zoneName'].text,
124
+ :state => elem.elements['zoneState'].text
125
+ }
126
+ end
127
+ return zones
128
+ end
129
+
130
+ def describe_keypairs(*keypair_names)
131
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
132
+ {
133
+ 'Action' => 'DescribeKeyPairs',
134
+ },{
135
+ 'KeyName' => keypair_names
136
+ })
137
+
138
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
139
+ xml_doc = REXML::Document.new(response.body)
140
+
141
+ keypairs = []
142
+ xml_doc.elements.each('//keySet/item') do |key|
143
+ keypairs << {
144
+ :name => key.elements['keyName'].text,
145
+ :fingerprint => key.elements['keyFingerprint'].text
146
+ }
147
+ end
148
+
149
+ return keypairs
150
+ end
151
+
152
+ def create_keypair(keyname, autosave=true)
153
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
154
+ {
155
+ 'Action' => 'CreateKeyPair',
156
+ 'KeyName' => keyname,
157
+ })
158
+
159
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
160
+ xml_doc = REXML::Document.new(response.body)
161
+
162
+ keypair = {
163
+ :name => xml_doc.elements['//keyName'].text,
164
+ :fingerprint => xml_doc.elements['//keyFingerprint'].text,
165
+ :material => xml_doc.elements['//keyMaterial'].text
166
+ }
167
+
168
+ if autosave
169
+ # Locate key material and save to a file named after the keyName
170
+ File.open("#{keypair[:name]}.pem",'w') do |file|
171
+ file.write(keypair[:material] + "\n")
172
+ keypair[:file_name] = file.path
173
+ end
174
+ end
175
+
176
+ return keypair
177
+ end
178
+
179
+ def delete_keypair(keyname)
180
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
181
+ {
182
+ 'Action' => 'DeleteKeyPair',
183
+ 'KeyName' => keyname,
184
+ })
185
+
186
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
187
+ return true
188
+ end
189
+
190
+ def describe_images(options={})
191
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
192
+ {
193
+ 'Action' => 'DescribeImages',
194
+ # Despite API documentation, the ImageType parameter is *not* supported, see:
195
+ # http://developer.amazonwebservices.com/connect/thread.jspa?threadID=20655&tstart=25
196
+ # 'ImageType' => options[:type]
197
+ },{
198
+ 'ImageId' => options[:image_ids],
199
+ 'Owner' => options[:owners],
200
+ 'ExecutableBy' => options[:executable_by]
201
+ })
202
+
203
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
204
+ xml_doc = REXML::Document.new(response.body)
205
+
206
+ images = []
207
+ xml_doc.elements.each('//imagesSet/item') do |image|
208
+ image_details = {
209
+ :id => image.elements['imageId'].text,
210
+ :location => image.elements['imageLocation'].text,
211
+ :state => image.elements['imageState'].text,
212
+ :owner_id => image.elements['imageOwnerId'].text,
213
+ :is_public => image.elements['isPublic'].text == 'true',
214
+ :architecture => image.elements['architecture'].text,
215
+ :type => image.elements['imageType'].text
216
+ }
217
+
218
+ # Items only available when listing 'machine' image types
219
+ # that have associated kernel and ramdisk metadata
220
+ if image.elements['kernelId']
221
+ image_details[:kernel_id] = image.elements['kernelId'].text
222
+ end
223
+ if image.elements['ramdiskId']
224
+ image_details[:ramdisk_id] = image.elements['ramdiskId'].text
225
+ end
226
+
227
+ image.elements.each('productCodes/item/productCode') do |code|
228
+ image_details[:product_codes] ||= []
229
+ image_details[:product_codes] << code.text
230
+ end
231
+
232
+ images << image_details
233
+ end
234
+
235
+ return images
236
+ end
237
+
238
+ def run_instances(image_id, min_count=1, max_count=min_count, options={})
239
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
240
+ {
241
+ 'Action' => 'RunInstances',
242
+ 'ImageId' => image_id,
243
+ 'MinCount' => min_count,
244
+ 'MaxCount' => max_count,
245
+ 'KeyName' => options[:key_name],
246
+ 'InstanceType' => options[:instance_type],
247
+ 'UserData' => encode_base64(options[:user_data]),
248
+
249
+ 'Placement.AvailabilityZone' => options[:zone],
250
+ 'KernelId' => options[:kernel_id],
251
+ 'RamdiskId' => options[:ramdisk_id]
252
+ },{
253
+ 'SecurityGroup' => options[:security_groups]
254
+ })
255
+
256
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
257
+ xml_doc = REXML::Document.new(response.body)
258
+ return parse_reservation(xml_doc.root)
259
+ end
260
+
261
+ def terminate_instances(*instance_ids)
262
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
263
+ {
264
+ 'Action' => 'TerminateInstances',
265
+ },{
266
+ 'InstanceId' => instance_ids,
267
+ })
268
+
269
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
270
+ xml_doc = REXML::Document.new(response.body)
271
+
272
+ instances = []
273
+ xml_doc.elements.each('//instancesSet/item') do |item|
274
+ instances << {
275
+ :id => item.elements['instanceId'].text,
276
+ :state => item.elements['shutdownState/name'].text,
277
+ :previous_state => item.elements['previousState/name'].text
278
+ }
279
+ end
280
+
281
+ return instances
282
+ end
283
+
284
+ def authorize_ingress_by_cidr(group_name, ip_protocol, from_port,
285
+ to_port=from_port, cidr_range='0.0.0.0/0')
286
+
287
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
288
+ {
289
+ 'Action' => 'AuthorizeSecurityGroupIngress',
290
+ 'GroupName' => group_name,
291
+ 'IpProtocol' => ip_protocol,
292
+ 'FromPort' => from_port,
293
+ 'ToPort' => to_port,
294
+ 'CidrIp' => cidr_range,
295
+ })
296
+
297
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
298
+ return true
299
+ end
300
+
301
+ def authorize_ingress_by_group(group_name, source_security_group_name,
302
+ source_security_group_owner_id)
303
+
304
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
305
+ {
306
+ 'Action' => 'AuthorizeSecurityGroupIngress',
307
+ 'GroupName' => group_name,
308
+ 'SourceSecurityGroupName' => source_security_group_name,
309
+ 'SourceSecurityGroupOwnerId' => source_security_group_owner_id,
310
+ })
311
+
312
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
313
+
314
+ return true
315
+ end
316
+
317
+ def describe_security_groups(*security_group_names)
318
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
319
+ {
320
+ 'Action' => 'DescribeSecurityGroups',
321
+ },{
322
+ 'GroupName' => security_group_names,
323
+ })
324
+
325
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
326
+ xml_doc = REXML::Document.new(response.body)
327
+
328
+ security_groups = []
329
+ xml_doc.elements.each('//securityGroupInfo/item') do |sec_group|
330
+ grants = []
331
+ sec_group.elements.each('ipPermissions/item') do |item|
332
+ grant = {
333
+ :protocol => item.elements['ipProtocol'].text,
334
+ :from_port => item.elements['fromPort'].text,
335
+ :to_port => item.elements['toPort'].text
336
+ }
337
+
338
+ item.elements.each('groups/item') do |group|
339
+ grant[:groups] ||= []
340
+ grant[:groups] << {
341
+ :user_id => group.elements['userId'].text,
342
+ :name => group.elements['groupName'].text
343
+ }
344
+ end
345
+
346
+ if item.elements['ipRanges/item']
347
+ grant[:ip_range] = item.elements['ipRanges/item/cidrIp'].text
348
+ end
349
+
350
+ grants << grant
351
+ end
352
+
353
+ security_groups << {
354
+ :name => sec_group.elements['groupName'].text,
355
+ :description => sec_group.elements['groupDescription'].text,
356
+ :owner_id => sec_group.elements['ownerId'].text,
357
+ :grants => grants
358
+ }
359
+ end
360
+
361
+ return security_groups
362
+ end
363
+
364
+ def revoke_ingress_by_cidr(group_name, ip_protocol, from_port,
365
+ to_port=from_port, cidr_range='0.0.0.0/0')
366
+
367
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
368
+ {
369
+ 'Action' => 'RevokeSecurityGroupIngress',
370
+ 'GroupName' => group_name,
371
+ 'IpProtocol' => ip_protocol,
372
+ 'FromPort' => from_port,
373
+ 'ToPort' => to_port,
374
+ 'CidrIp' => cidr_range,
375
+ })
376
+
377
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
378
+ return true
379
+ end
380
+
381
+ def revoke_ingress_by_group(group_name, source_security_group_name,
382
+ source_security_group_owner_id)
383
+
384
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
385
+ {
386
+ 'Action' => 'RevokeSecurityGroupIngress',
387
+ 'GroupName' => group_name,
388
+ 'SourceSecurityGroupName' => source_security_group_name,
389
+ 'SourceSecurityGroupOwnerId' => source_security_group_owner_id,
390
+ })
391
+
392
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
393
+ return true
394
+ end
395
+
396
+ def create_security_group(group_name, group_description=group_name)
397
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
398
+ {
399
+ 'Action' => 'CreateSecurityGroup',
400
+ 'GroupName' => group_name,
401
+ 'GroupDescription' => group_description,
402
+ })
403
+
404
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
405
+ return true
406
+ end
407
+
408
+ def delete_security_group(group_name)
409
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
410
+ {
411
+ 'Action' => 'DeleteSecurityGroup',
412
+ 'GroupName' => group_name,
413
+ })
414
+
415
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
416
+ return true
417
+ end
418
+
419
+
420
+ def register_image(image_location)
421
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
422
+ {
423
+ 'Action' => 'RegisterImage',
424
+ 'ImageLocation' => image_location,
425
+ })
426
+
427
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
428
+ xml_doc = REXML::Document.new(response.body)
429
+
430
+ return xml_doc.elements['//imageId'].text
431
+ end
432
+
433
+ def deregister_image(image_id)
434
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
435
+ {
436
+ 'Action' => 'DeregisterImage',
437
+ 'ImageId' => image_id,
438
+ })
439
+
440
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
441
+ return true
442
+ end
443
+
444
+ def describe_image_attribute(image_id, attribute='launchPermission')
445
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
446
+ {
447
+ 'Action' => 'DescribeImageAttribute',
448
+ 'ImageId' => image_id,
449
+ 'Attribute' => attribute,
450
+ })
451
+
452
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
453
+ xml_doc = REXML::Document.new(response.body)
454
+
455
+ result = {:id => xml_doc.elements['//imageId'].text}
456
+
457
+ if xml_doc.elements['//launchPermission']
458
+ result[:launch_perms_user] = []
459
+ result[:launch_perms_group] = []
460
+ xml_doc.elements.each('//launchPermission/item') do |lp|
461
+ elems = lp.elements
462
+ result[:launch_perms_group] << elems['group'].text if elems['group']
463
+ result[:launch_perms_user] << elems['userId'].text if elems['userId']
464
+ end
465
+ end
466
+
467
+ if xml_doc.elements['//productCodes']
468
+ result[:product_codes] = []
469
+ xml_doc.elements.each('//productCodes/item') do |pc|
470
+ result[:product_codes] << pc.text
471
+ end
472
+ end
473
+
474
+ return result
475
+ end
476
+
477
+ def modify_image_attribute(image_id, attribute,
478
+ operation_type, attribute_values)
479
+
480
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
481
+ {
482
+ 'Action' => 'ModifyImageAttribute',
483
+ 'ImageId' => image_id,
484
+ 'Attribute' => attribute,
485
+ 'OperationType' => operation_type,
486
+ }, attribute_values)
487
+
488
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
489
+ return true
490
+ end
491
+
492
+ def reset_image_attribute(image_id, attribute='launchPermission')
493
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
494
+ {
495
+ 'Action' => 'ResetImageAttribute',
496
+ 'ImageId' => image_id,
497
+ 'Attribute' => attribute,
498
+ })
499
+
500
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
501
+ return true
502
+ end
503
+
504
+ def get_console_output(instance_id)
505
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
506
+ {
507
+ 'Action' => 'GetConsoleOutput',
508
+ 'InstanceId' => instance_id,
509
+ })
510
+
511
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
512
+ elems = REXML::Document.new(response.body).elements
513
+
514
+ return {
515
+ :id => elems['//instanceId'].text,
516
+ :timestamp => elems['//timestamp'].text,
517
+ :output => Base64.decode64(elems['//output'].text).strip
518
+ }
519
+ end
520
+
521
+ def reboot_instances(*instance_ids)
522
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
523
+ {
524
+ 'Action' => 'RebootInstances',
525
+ },{
526
+ 'InstanceId' => instance_ids,
527
+ })
528
+
529
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
530
+ return true
531
+ end
532
+
533
+
534
+ def confirm_product_instance(product_code, instance_id)
535
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
536
+ {
537
+ 'Action' => 'ConfirmProductInstance',
538
+ 'ProductCode' => product_code,
539
+ 'InstanceId' => instance_id
540
+ })
541
+
542
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
543
+ elems = REXML::Document.new(response.body).elements
544
+
545
+ result = {
546
+ :result => elems['//result'].text == true
547
+ }
548
+ result[:owner_id] = elems['//ownerId'].text if elems['//ownerId']
549
+ return result
550
+ end
551
+
552
+ def describe_addresses(*addresses)
553
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
554
+ {
555
+ 'Action' => 'DescribeAddresses',
556
+ },{
557
+ 'PublicIp' => addresses
558
+ })
559
+
560
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
561
+ xml_doc = REXML::Document.new(response.body)
562
+
563
+ addresses = []
564
+ xml_doc.elements.each('//addressesSet/item') do |elem|
565
+ addresses << {
566
+ :public_ip => elem.elements['publicIp'].text,
567
+ :instance_id => elem.elements['instanceId'].text
568
+ }
569
+ end
570
+ return addresses
571
+ end
572
+
573
+ def allocate_address()
574
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
575
+ {
576
+ 'Action' => 'AllocateAddress',
577
+ })
578
+
579
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
580
+ xml_doc = REXML::Document.new(response.body)
581
+ return xml_doc.elements['//publicIp'].text
582
+ end
583
+
584
+ def release_address(public_ip)
585
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
586
+ {
587
+ 'Action' => 'ReleaseAddress',
588
+ 'PublicIp' => public_ip
589
+ })
590
+
591
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
592
+ xml_doc = REXML::Document.new(response.body)
593
+ return xml_doc.elements['//return'].text == 'true'
594
+ end
595
+
596
+ def associate_address(instance_id, public_ip)
597
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
598
+ {
599
+ 'Action' => 'AssociateAddress',
600
+ 'InstanceId' => instance_id,
601
+ 'PublicIp' => public_ip
602
+ })
603
+
604
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
605
+ xml_doc = REXML::Document.new(response.body)
606
+ return xml_doc.elements['//return'].text == 'true'
607
+ end
608
+
609
+ def disassociate_address(public_ip)
610
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
611
+ {
612
+ 'Action' => 'DisassociateAddress',
613
+ 'PublicIp' => public_ip
614
+ })
615
+
616
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
617
+ xml_doc = REXML::Document.new(response.body)
618
+ return xml_doc.elements['//return'].text == 'true'
619
+ end
620
+
621
+ def create_volume(size, availability_zone)
622
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
623
+ {
624
+ 'Action' => 'CreateVolume',
625
+ 'Size' => size,
626
+ 'AvailabilityZone' => availability_zone
627
+ })
628
+
629
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
630
+ xml_doc = REXML::Document.new(response.body)
631
+ res = {}
632
+ res[:volume_id] = xml_doc.elements['//volumeId'].text
633
+ res[:size] = xml_doc.elements['//size'].text
634
+ res[:status] = xml_doc.elements['//status'].text
635
+ res[:create_time] = xml_doc.elements['//createTime'].text
636
+ res[:availability_zone] = xml_doc.elements['//availabilityZone'].text
637
+ res[:snapshot_id] = xml_doc.elements['//snapshotId'].text
638
+ res
639
+ end
640
+
641
+ def create_volume_from_snapshot(snapshot_id, availability_zone)
642
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
643
+ {
644
+ 'Action' => 'CreateVolume',
645
+ 'SnapshotId' => snapshot_id,
646
+ 'AvailabilityZone' => availability_zone
647
+ })
648
+
649
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
650
+ xml_doc = REXML::Document.new(response.body)
651
+ res = {}
652
+ res[:volume_id] = xml_doc.elements['//volumeId'].text
653
+ res[:size] = xml_doc.elements['//size'].text
654
+ res[:status] = xml_doc.elements['//status'].text
655
+ res[:create_time] = xml_doc.elements['//createTime'].text
656
+ res[:availability_zone] = xml_doc.elements['//availabilityZone'].text
657
+ res[:snapshot_id] = xml_doc.elements['//snapshotId'].text
658
+ res
659
+ end
660
+
661
+ def delete_volume(volume_id)
662
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
663
+ {
664
+ 'Action' => 'DeleteVolume',
665
+ 'VolumeId' => volume_id
666
+ })
667
+
668
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
669
+ xml_doc = REXML::Document.new(response.body)
670
+ return xml_doc.elements['//return'].text == 'true'
671
+ end
672
+
673
+ def describe_volumes(*volume_ids)
674
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
675
+ {
676
+ 'Action' => 'DescribeVolumes',
677
+ },{
678
+ 'VolumeId' => volume_ids
679
+ })
680
+
681
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
682
+ xml_doc = REXML::Document.new(response.body)
683
+ volumes = []
684
+ xml_doc.elements.each('//volumeSet/item') do |elem|
685
+ volumes << parse_volume(elem)
686
+ end
687
+ return volumes
688
+ end
689
+
690
+ def attach_volume(volume_id, instance_id, device)
691
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
692
+ {
693
+ 'Action' => 'AttachVolume',
694
+ 'VolumeId' => volume_id,
695
+ 'InstanceId' => instance_id,
696
+ 'Device' => device
697
+ })
698
+
699
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
700
+ xml_doc = REXML::Document.new(response.body)
701
+ res = {}
702
+ res[:volume_id] = xml_doc.elements['//volumeId'].text
703
+ res[:instance_id] = xml_doc.elements['//instanceId'].text
704
+ res[:device] = xml_doc.elements['//device'].text
705
+ res[:status] = xml_doc.elements['//status'].text
706
+ res
707
+ end
708
+
709
+ def detach_volume(volume_id, instance_id = nil, device = nil, force = nil)
710
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
711
+ {
712
+ 'Action' => 'DetachVolume',
713
+ 'VolumeId' => volume_id,
714
+ 'InstanceId' => instance_id,
715
+ 'Device' => device,
716
+ 'Force' => force
717
+ })
718
+
719
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
720
+ xml_doc = REXML::Document.new(response.body)
721
+ res = {}
722
+ res[:volume_id] = xml_doc.elements['//volumeId'].text
723
+ res[:instance_id] = xml_doc.elements['//instanceId'].text
724
+ res[:device] = xml_doc.elements['//device'].text
725
+ res[:status] = xml_doc.elements['//status'].text
726
+ res[:attach_time] = xml_doc.elements['//attachTime'].text
727
+ res
728
+ end
729
+
730
+ def create_snapshot(volume_id)
731
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
732
+ {
733
+ 'Action' => 'CreateSnapshot',
734
+ 'VolumeId' => volume_id
735
+ })
736
+
737
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
738
+ xml_doc = REXML::Document.new(response.body)
739
+ res = {}
740
+ res[:snapshot_id] = xml_doc.elements['//snapshotId'].text
741
+ res[:volume_id] = xml_doc.elements['//volumeId'].text
742
+ res[:status] = xml_doc.elements['//status'].text
743
+ res[:start_time] = xml_doc.elements['//startTime'].text
744
+ res[:progress] = xml_doc.elements['//progress'].text
745
+ res
746
+ end
747
+
748
+ def delete_snapshot(snapshot_id)
749
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
750
+ {
751
+ 'Action' => 'DeleteSnapshot',
752
+ 'SnapshotId' => snapshot_id
753
+ })
754
+
755
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
756
+ xml_doc = REXML::Document.new(response.body)
757
+ return xml_doc.elements['//return'].text == 'true'
758
+ end
759
+
760
+ def describe_snapshots(*snapshot_ids)
761
+ parameters = build_query_params(API_VERSION, SIGNATURE_VERSION,
762
+ {
763
+ 'Action' => 'DescribeSnapshots',
764
+ },{
765
+ 'SnapshotId' => snapshot_ids
766
+ })
767
+
768
+ response = do_query(HTTP_METHOD, ENDPOINT_URI, parameters)
769
+ xml_doc = REXML::Document.new(response.body)
770
+ snapshots = []
771
+ xml_doc.elements.each('//snapshotSet/item') do |elem|
772
+ snapshots << {
773
+ :snapshot_id => elem.elements['snapshotId'].text,
774
+ :volume_id => elem.elements['volumeId'].text,
775
+ :status => elem.elements['status'].text,
776
+ :start_time => elem.elements['startTime'].text,
777
+ :progress => elem.elements['progress'].text
778
+ }
779
+ end
780
+ return snapshots
781
+ end
782
+
783
+ end