staugaard-cloudmaster 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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