gotime_aws 2.5.6

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/lib/ec2/ec2.rb ADDED
@@ -0,0 +1,2294 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (c) 2007-2008 RightScale Inc
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+
25
+ module Aws
26
+
27
+ # = Aws::EC2 -- RightScale Amazon EC2 interface
28
+ # The Aws::EC2 class provides a complete interface to Amazon's
29
+ # Elastic Compute Cloud service, as well as the associated EBS (Elastic Block
30
+ # Store).
31
+ # For explanations of the semantics
32
+ # of each call, please refer to Amazon's documentation at
33
+ # http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=87
34
+ #
35
+ # Examples:
36
+ #
37
+ # Create an EC2 interface handle:
38
+ #
39
+ # @ec2 = Aws::Ec2.new(aws_access_key_id,
40
+ # aws_secret_access_key)
41
+ # Create a new SSH key pair:
42
+ # @key = 'right_ec2_awesome_test_key'
43
+ # new_key = @ec2.create_key_pair(@key)
44
+ # keys = @ec2.describe_key_pairs
45
+ #
46
+ # Create a security group:
47
+ # @group = 'right_ec2_awesome_test_security_group'
48
+ # @ec2.create_security_group(@group,'My awesome test group')
49
+ # group = @ec2.describe_security_groups([@group])[0]
50
+ #
51
+ # Configure a security group:
52
+ # @ec2.authorize_security_group_named_ingress(@group, account_number, 'default')
53
+ # @ec2.authorize_security_group_IP_ingress(@group, 80,80,'udp','192.168.1.0/8')
54
+ #
55
+ # Describe the available images:
56
+ # images = @ec2.describe_images
57
+ #
58
+ # Launch an instance:
59
+ # ec2.run_instances('ami-9a9e7bf3', 1, 1, ['default'], @key, 'SomeImportantUserData', 'public')
60
+ #
61
+ #
62
+ # Describe running instances:
63
+ # @ec2.describe_instances
64
+ #
65
+ # Error handling: all operations raise an Aws::AwsError in case
66
+ # of problems. Note that transient errors are automatically retried.
67
+
68
+ class Ec2 < AwsBase
69
+ include AwsBaseInterface
70
+
71
+ # Amazon EC2 API version being used
72
+ API_VERSION = "2010-08-31"
73
+ DEFAULT_HOST = "ec2.amazonaws.com"
74
+ DEFAULT_PATH = '/'
75
+ DEFAULT_PROTOCOL = 'https'
76
+ DEFAULT_PORT = 443
77
+
78
+ # Default addressing type (public=NAT, direct=no-NAT) used when launching instances.
79
+ DEFAULT_ADDRESSING_TYPE = 'public'
80
+ DNS_ADDRESSING_SET = ['public', 'direct']
81
+
82
+ # Amazon EC2 Instance Types : http://www.amazon.com/b?ie=UTF8&node=370375011
83
+ # Default EC2 instance type (platform)
84
+ DEFAULT_INSTANCE_TYPE = 'm1.small'
85
+ INSTANCE_TYPES = ['t1.micro', 'm1.small', 'c1.medium', 'm1.large', 'm1.xlarge', 'c1.xlarge']
86
+
87
+ def self.connection_name
88
+ :ec2_connection
89
+ end
90
+
91
+ @@bench = AwsBenchmarkingBlock.new
92
+ def self.bench
93
+ @@bench
94
+ end
95
+
96
+ def self.bench_xml
97
+ @@bench.xml
98
+ end
99
+
100
+ def self.bench_ec2
101
+ @@bench.service
102
+ end
103
+
104
+ # Current API version (sometimes we have to check it outside the GEM).
105
+ @@api = ENV['EC2_API_VERSION'] || API_VERSION
106
+
107
+ def self.api
108
+ @@api
109
+ end
110
+
111
+ # Create a new handle to an EC2 account. All handles share the same per process or per thread
112
+ # HTTP connection to Amazon EC2. Each handle is for a specific account. The params have the
113
+ # following options:
114
+ # * <tt>:endpoint_url</tt> a fully qualified url to Amazon API endpoint (this overwrites: :server, :port, :service, :protocol and :region). Example: 'https://eu-west-1.ec2.amazonaws.com/'
115
+ # * <tt>:server</tt>: EC2 service host, default: DEFAULT_HOST
116
+ # * <tt>:region</tt>: EC2 region (North America by default)
117
+ # * <tt>:port</tt>: EC2 service port, default: DEFAULT_PORT
118
+ # * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
119
+ # * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
120
+ # * <tt>:logger</tt>: for log messages, default: Rails.logger else STDOUT
121
+ # * <tt>:signature_version</tt>: The signature version : '0' or '1'(default)
122
+ # * <tt>:cache</tt>: true/false: caching for: ec2_describe_images, describe_instances,
123
+ # describe_images_by_owner, describe_images_by_executable_by, describe_availability_zones,
124
+ # describe_security_groups, describe_key_pairs, describe_addresses,
125
+ # describe_volumes, describe_snapshots methods, default: false.
126
+ #
127
+ def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
128
+ init({:name => 'EC2',
129
+ :default_host => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).host : DEFAULT_HOST,
130
+ :default_port => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).port : DEFAULT_PORT,
131
+ :default_service => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).path : DEFAULT_PATH,
132
+ :default_protocol => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).scheme : DEFAULT_PROTOCOL,
133
+ :api_version => API_VERSION},
134
+ aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'],
135
+ aws_secret_access_key|| ENV['AWS_SECRET_ACCESS_KEY'],
136
+ params)
137
+ # EC2 doesn't really define any transient errors to retry, and in fact,
138
+ # when they return a 503 it is usually for 'request limit exceeded' which
139
+ # we most certainly should not retry. So let's pare down the list of
140
+ # retryable errors to InternalError only (see AwsBase for the default
141
+ # list)
142
+ amazon_problems = ['InternalError']
143
+ end
144
+
145
+
146
+ def generate_request(action, params={}) #:nodoc:
147
+ service_hash = {"Action" => action,
148
+ "AWSAccessKeyId" => @aws_access_key_id,
149
+ "Version" => @@api}
150
+ service_hash.update(params)
151
+ service_params = signed_service_params(@aws_secret_access_key, service_hash, :get, @params[:server], @params[:service])
152
+
153
+ # use POST method if the length of the query string is too large
154
+ if service_params.size > 2000
155
+ if signature_version == '2'
156
+ # resign the request because HTTP verb is included into signature
157
+ service_params = signed_service_params(@aws_secret_access_key, service_hash, :post, @params[:server], @params[:service])
158
+ end
159
+ request = Net::HTTP::Post.new(@params[:service])
160
+ request.body = service_params
161
+ request['Content-Type'] = 'application/x-www-form-urlencoded'
162
+ else
163
+ request = Net::HTTP::Get.new("#{@params[:service]}?#{service_params}")
164
+ end
165
+ # prepare output hash
166
+ {:request => request,
167
+ :server => @params[:server],
168
+ :port => @params[:port],
169
+ :protocol => @params[:protocol]}
170
+ end
171
+
172
+ # Sends request to Amazon and parses the response
173
+ # Raises AwsError if any banana happened
174
+ # todo: remove this and switch to using request_info2
175
+ def request_info(request, parser, options={}) #:nodoc:
176
+ conn = get_conn(self.class.connection_name, @params, @logger)
177
+ request_info_impl(conn, @@bench, request, parser, options)
178
+ end
179
+
180
+ def hash_params(prefix, list) #:nodoc:
181
+ groups = {}
182
+ list.each_index { |i| groups.update("#{prefix}.#{i+1}"=>list[i]) } if list
183
+ return groups
184
+ end
185
+
186
+ #-----------------------------------------------------------------
187
+ # Images
188
+ #-----------------------------------------------------------------
189
+
190
+ # params:
191
+ # { 'ImageId' => ['id1', ..., 'idN'],
192
+ # 'Owner' => ['self', ..., 'userN'],
193
+ # 'ExecutableBy' => ['self', 'all', ..., 'userN']
194
+ # }
195
+ def ec2_describe_images(params={}, image_type=nil, cache_for=nil) #:nodoc:
196
+ request_hash = {}
197
+ params.each do |list_by, list|
198
+ request_hash.merge! hash_params(list_by, list.to_a)
199
+ end
200
+ if image_type
201
+ request_hash['Filter.1.Name'] = "image-type"
202
+ request_hash['Filter.1.Value.1'] = image_type
203
+ end
204
+ link = generate_request("DescribeImages", request_hash)
205
+ request_cache_or_info cache_for, link, QEc2DescribeImagesParser, @@bench, cache_for
206
+ rescue Exception
207
+ on_exception
208
+ end
209
+
210
+ # Retrieve a list of images. Returns array of hashes describing the images or an exception:
211
+ # +image_type+ = 'machine' || 'kernel' || 'ramdisk'
212
+ #
213
+ # ec2.describe_images #=>
214
+ # [{:aws_owner => "522821470517",
215
+ # :aws_id => "ami-e4b6538d",
216
+ # :aws_state => "available",
217
+ # :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
218
+ # :aws_is_public => true,
219
+ # :aws_architecture => "i386",
220
+ # :aws_image_type => "machine"},
221
+ # {...},
222
+ # {...} ]
223
+ #
224
+ # If +list+ param is set, then retrieve information about the listed images only:
225
+ #
226
+ # ec2.describe_images(['ami-e4b6538d']) #=>
227
+ # [{:aws_owner => "522821470517",
228
+ # :aws_id => "ami-e4b6538d",
229
+ # :aws_state => "available",
230
+ # :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
231
+ # :aws_is_public => true,
232
+ # :aws_architecture => "i386",
233
+ # :aws_image_type => "machine"}]
234
+ #
235
+ def describe_images(list=[], image_type=nil)
236
+ list = list.to_a
237
+ cache_for = list.empty? && !image_type ? :describe_images : nil
238
+ ec2_describe_images({'ImageId' => list}, image_type, cache_for)
239
+ end
240
+
241
+ #
242
+ # Example:
243
+ #
244
+ # ec2.describe_images_by_owner('522821470517')
245
+ # ec2.describe_images_by_owner('self')
246
+ #
247
+ def describe_images_by_owner(list=['self'], image_type=nil)
248
+ list = list.to_a
249
+ cache_for = list==['self'] && !image_type ? :describe_images_by_owner : nil
250
+ ec2_describe_images({'Owner' => list}, image_type, cache_for)
251
+ end
252
+
253
+ #
254
+ # Example:
255
+ #
256
+ # ec2.describe_images_by_executable_by('522821470517')
257
+ # ec2.describe_images_by_executable_by('self')
258
+ # ec2.describe_images_by_executable_by('all')
259
+ #
260
+ def describe_images_by_executable_by(list=['self'], image_type=nil)
261
+ list = list.to_a
262
+ cache_for = list==['self'] && !image_type ? :describe_images_by_executable_by : nil
263
+ ec2_describe_images({'ExecutableBy' => list}, image_type, cache_for)
264
+ end
265
+
266
+
267
+ # Register new image at Amazon.
268
+ # Returns new image id or an exception.
269
+ #
270
+ # ec2.register_image('bucket/key/manifest') #=> 'ami-e444444d'
271
+ #
272
+ def register_image(image_location)
273
+ link = generate_request("RegisterImage",
274
+ 'ImageLocation' => image_location.to_s)
275
+ request_info(link, QEc2RegisterImageParser.new(:logger => @logger))
276
+ rescue Exception
277
+ on_exception
278
+ end
279
+
280
+ # Deregister image at Amazon. Returns +true+ or an exception.
281
+ #
282
+ # ec2.deregister_image('ami-e444444d') #=> true
283
+ #
284
+ def deregister_image(image_id)
285
+ link = generate_request("DeregisterImage",
286
+ 'ImageId' => image_id.to_s)
287
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
288
+ rescue Exception
289
+ on_exception
290
+ end
291
+
292
+
293
+ # Describe image attributes. Currently 'launchPermission', 'productCodes', 'kernel', 'ramdisk' and 'blockDeviceMapping' are supported.
294
+ #
295
+ # ec2.describe_image_attribute('ami-e444444d') #=> {:groups=>["all"], :users=>["000000000777"]}
296
+ #
297
+ def describe_image_attribute(image_id, attribute='launchPermission')
298
+ link = generate_request("DescribeImageAttribute",
299
+ 'ImageId' => image_id,
300
+ 'Attribute' => attribute)
301
+ request_info(link, QEc2DescribeImageAttributeParser.new(:logger => @logger))
302
+ rescue Exception
303
+ on_exception
304
+ end
305
+
306
+ # Reset image attribute. Currently, only 'launchPermission' is supported. Returns +true+ or an exception.
307
+ #
308
+ # ec2.reset_image_attribute('ami-e444444d') #=> true
309
+ #
310
+ def reset_image_attribute(image_id, attribute='launchPermission')
311
+ link = generate_request("ResetImageAttribute",
312
+ 'ImageId' => image_id,
313
+ 'Attribute' => attribute)
314
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
315
+ rescue Exception
316
+ on_exception
317
+ end
318
+
319
+ # Modify an image's attributes. It is recommended that you use
320
+ # modify_image_launch_perm_add_users, modify_image_launch_perm_remove_users, etc.
321
+ # instead of modify_image_attribute because the signature of
322
+ # modify_image_attribute may change with EC2 service changes.
323
+ #
324
+ # attribute : currently, only 'launchPermission' is supported.
325
+ # operation_type : currently, only 'add' & 'remove' are supported.
326
+ # vars:
327
+ # :user_group : currently, only 'all' is supported.
328
+ # :user_id
329
+ # :product_code
330
+ def modify_image_attribute(image_id, attribute, operation_type = nil, vars = {})
331
+ params = {'ImageId' => image_id,
332
+ 'Attribute' => attribute}
333
+ params['OperationType'] = operation_type if operation_type
334
+ params.update(hash_params('UserId', vars[:user_id].to_a)) if vars[:user_id]
335
+ params.update(hash_params('UserGroup', vars[:user_group].to_a)) if vars[:user_group]
336
+ params.update(hash_params('ProductCode', vars[:product_code])) if vars[:product_code]
337
+ link = generate_request("ModifyImageAttribute", params)
338
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
339
+ rescue Exception
340
+ on_exception
341
+ end
342
+
343
+ # Grant image launch permissions to users.
344
+ # Parameter +userId+ is a list of user AWS account ids.
345
+ # Returns +true+ or an exception.
346
+ #
347
+ # ec2.modify_image_launch_perm_add_users('ami-e444444d',['000000000777','000000000778']) #=> true
348
+ def modify_image_launch_perm_add_users(image_id, user_id=[])
349
+ modify_image_attribute(image_id, 'launchPermission', 'add', :user_id => user_id.to_a)
350
+ end
351
+
352
+ # Revokes image launch permissions for users. +userId+ is a list of users AWS accounts ids. Returns +true+ or an exception.
353
+ #
354
+ # ec2.modify_image_launch_perm_remove_users('ami-e444444d',['000000000777','000000000778']) #=> true
355
+ #
356
+ def modify_image_launch_perm_remove_users(image_id, user_id=[])
357
+ modify_image_attribute(image_id, 'launchPermission', 'remove', :user_id => user_id.to_a)
358
+ end
359
+
360
+ # Add image launch permissions for users groups (currently only 'all' is supported, which gives public launch permissions).
361
+ # Returns +true+ or an exception.
362
+ #
363
+ # ec2.modify_image_launch_perm_add_groups('ami-e444444d') #=> true
364
+ #
365
+ def modify_image_launch_perm_add_groups(image_id, user_group=['all'])
366
+ modify_image_attribute(image_id, 'launchPermission', 'add', :user_group => user_group.to_a)
367
+ end
368
+
369
+ # Remove image launch permissions for users groups (currently only 'all' is supported, which gives public launch permissions).
370
+ #
371
+ # ec2.modify_image_launch_perm_remove_groups('ami-e444444d') #=> true
372
+ #
373
+ def modify_image_launch_perm_remove_groups(image_id, user_group=['all'])
374
+ modify_image_attribute(image_id, 'launchPermission', 'remove', :user_group => user_group.to_a)
375
+ end
376
+
377
+ # Add product code to image
378
+ #
379
+ # ec2.modify_image_product_code('ami-e444444d','0ABCDEF') #=> true
380
+ #
381
+ def modify_image_product_code(image_id, product_code=[])
382
+ modify_image_attribute(image_id, 'productCodes', nil, :product_code => product_code.to_a)
383
+ end
384
+
385
+ #-----------------------------------------------------------------
386
+ # Instances
387
+ #-----------------------------------------------------------------
388
+
389
+ def get_desc_instances(instances) # :nodoc:
390
+ result = []
391
+ instances.each do |reservation|
392
+ reservation[:instances_set].each do |instance|
393
+ # Parse and remove timestamp from the reason string. The timestamp is of
394
+ # the request, not when EC2 took action, thus confusing & useless...
395
+ instance[:aws_reason] = instance[:aws_reason].sub(/\(\d[^)]*GMT\) */, '')
396
+ instance[:aws_owner] = reservation[:aws_owner]
397
+ instance[:aws_reservation_id] = reservation[:aws_reservation_id]
398
+ instance[:aws_groups] = reservation[:aws_groups]
399
+ result << instance
400
+ end
401
+ end
402
+ result
403
+ rescue Exception
404
+ on_exception
405
+ end
406
+
407
+ # Retrieve information about EC2 instances. If +list+ is omitted then returns the
408
+ # list of all instances.
409
+ #
410
+ # ec2.describe_instances #=>
411
+ # [{:aws_image_id => "ami-e444444d",
412
+ # :aws_reason => "",
413
+ # :aws_state_code => "16",
414
+ # :aws_owner => "000000000888",
415
+ # :aws_instance_id => "i-123f1234",
416
+ # :aws_reservation_id => "r-aabbccdd",
417
+ # :aws_state => "running",
418
+ # :dns_name => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com",
419
+ # :ssh_key_name => "staging",
420
+ # :aws_groups => ["default"],
421
+ # :private_dns_name => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com",
422
+ # :aws_instance_type => "m1.small",
423
+ # :aws_launch_time => "2008-1-1T00:00:00.000Z"},
424
+ # :aws_availability_zone => "us-east-1b",
425
+ # :aws_kernel_id => "aki-ba3adfd3",
426
+ # :aws_ramdisk_id => "ari-badbad00",
427
+ # :monitoring_state => ...,
428
+ # ..., {...}]
429
+ #
430
+ def describe_instances(list=[])
431
+ link = generate_request("DescribeInstances", hash_params('InstanceId', list.to_a))
432
+ request_cache_or_info(:describe_instances, link, QEc2DescribeInstancesParser, @@bench, list.nil? || list.empty?) do |parser|
433
+ get_desc_instances(parser.result)
434
+ end
435
+ rescue Exception
436
+ on_exception
437
+ end
438
+
439
+ # Return the product code attached to instance or +nil+ otherwise.
440
+ #
441
+ # ec2.confirm_product_instance('ami-e444444d','12345678') #=> nil
442
+ # ec2.confirm_product_instance('ami-e444444d','00001111') #=> "000000000888"
443
+ #
444
+ def confirm_product_instance(instance, product_code)
445
+ link = generate_request("ConfirmProductInstance", {'ProductCode' => product_code,
446
+ 'InstanceId' => instance})
447
+ request_info(link, QEc2ConfirmProductInstanceParser.new(:logger => @logger))
448
+ end
449
+
450
+ # DEPRECATED, USE launch_instances instead.
451
+ #
452
+ # Launch new EC2 instances. Returns a list of launched instances or an exception.
453
+ #
454
+ # ec2.run_instances('ami-e444444d',1,1,['my_awesome_group'],'my_awesome_key', 'Woohoo!!!', 'public') #=>
455
+ # [{:aws_image_id => "ami-e444444d",
456
+ # :aws_reason => "",
457
+ # :aws_state_code => "0",
458
+ # :aws_owner => "000000000888",
459
+ # :aws_instance_id => "i-123f1234",
460
+ # :aws_reservation_id => "r-aabbccdd",
461
+ # :aws_state => "pending",
462
+ # :dns_name => "",
463
+ # :ssh_key_name => "my_awesome_key",
464
+ # :aws_groups => ["my_awesome_group"],
465
+ # :private_dns_name => "",
466
+ # :aws_instance_type => "m1.small",
467
+ # :aws_launch_time => "2008-1-1T00:00:00.000Z"
468
+ # :aws_ramdisk_id => "ari-8605e0ef"
469
+ # :aws_kernel_id => "aki-9905e0f0",
470
+ # :ami_launch_index => "0",
471
+ # :aws_availability_zone => "us-east-1b"
472
+ # }]
473
+ #
474
+ def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='',
475
+ addressing_type = nil, instance_type = nil,
476
+ kernel_id = nil, ramdisk_id = nil, availability_zone = nil,
477
+ block_device_mappings = nil)
478
+ launch_instances(image_id, {:min_count => min_count,
479
+ :max_count => max_count,
480
+ :user_data => user_data,
481
+ :group_ids => group_ids,
482
+ :key_name => key_name,
483
+ :instance_type => instance_type,
484
+ :addressing_type => addressing_type,
485
+ :kernel_id => kernel_id,
486
+ :ramdisk_id => ramdisk_id,
487
+ :availability_zone => availability_zone,
488
+ :block_device_mappings => block_device_mappings
489
+ })
490
+ end
491
+
492
+
493
+ # Launch new EC2 instances. Returns a list of launched instances or an exception.
494
+ #
495
+ # +lparams+ keys (default values in parenthesis):
496
+ # :min_count fixnum, (1)
497
+ # :max_count fixnum, (1)
498
+ # :group_ids array or string ([] == 'default')
499
+ # :instance_type string (DEFAULT_INSTACE_TYPE)
500
+ # :addressing_type string (DEFAULT_ADDRESSING_TYPE
501
+ # :key_name string
502
+ # :kernel_id string
503
+ # :ramdisk_id string
504
+ # :availability_zone string
505
+ # :block_device_mappings string
506
+ # :user_data string
507
+ # :monitoring_enabled boolean (default=false)
508
+ #
509
+ # ec2.launch_instances('ami-e444444d', :group_ids => 'my_awesome_group',
510
+ # :user_data => "Woohoo!!!",
511
+ # :addressing_type => "public",
512
+ # :key_name => "my_awesome_key",
513
+ # :availability_zone => "us-east-1c") #=>
514
+ # [{:aws_image_id => "ami-e444444d",
515
+ # :aws_reason => "",
516
+ # :aws_state_code => "0",
517
+ # :aws_owner => "000000000888",
518
+ # :aws_instance_id => "i-123f1234",
519
+ # :aws_reservation_id => "r-aabbccdd",
520
+ # :aws_state => "pending",
521
+ # :dns_name => "",
522
+ # :ssh_key_name => "my_awesome_key",
523
+ # :aws_groups => ["my_awesome_group"],
524
+ # :private_dns_name => "",
525
+ # :aws_instance_type => "m1.small",
526
+ # :aws_launch_time => "2008-1-1T00:00:00.000Z",
527
+ # :aws_ramdisk_id => "ari-8605e0ef"
528
+ # :aws_kernel_id => "aki-9905e0f0",
529
+ # :ami_launch_index => "0",
530
+ # :aws_availability_zone => "us-east-1c"
531
+ # }]
532
+ #
533
+ def launch_instances(image_id, options={})
534
+ @logger.info("Launching instance of image #{image_id} for #{@aws_access_key_id}, " +
535
+ "key: #{options[:key_name]}, groups: #{(options[:group_ids]).to_a.join(',')}")
536
+ # careful: keyName and securityGroups may be nil
537
+ params = hash_params('SecurityGroup', options[:group_ids].to_a)
538
+ params.update({'ImageId' => image_id,
539
+ 'MinCount' => (options[:min_count] || 1).to_s,
540
+ 'MaxCount' => (options[:max_count] || 1).to_s,
541
+ 'AddressingType' => options[:addressing_type] || DEFAULT_ADDRESSING_TYPE,
542
+ 'InstanceType' => options[:instance_type] || DEFAULT_INSTANCE_TYPE})
543
+ # optional params
544
+ params['KeyName'] = options[:key_name] unless Aws::Utils.blank?(options[:key_name])
545
+ params['KernelId'] = options[:kernel_id] unless Aws::Utils.blank?(options[:kernel_id])
546
+ params['RamdiskId'] = options[:ramdisk_id] unless Aws::Utils.blank?(options[:ramdisk_id])
547
+ params['Placement.AvailabilityZone'] = options[:availability_zone] unless Aws::Utils.blank?(options[:availability_zone])
548
+ params['BlockDeviceMappings'] = options[:block_device_mappings] unless Aws::Utils.blank?(options[:block_device_mappings])
549
+ params['Monitoring.Enabled'] = options[:monitoring_enabled] unless Aws::Utils.blank?(options[:monitoring_enabled])
550
+ params['SubnetId'] = options[:subnet_id] unless Aws::Utils.blank?(options[:subnet_id])
551
+ params['AdditionalInfo'] = options[:additional_info] unless Aws::Utils.blank?(options[:additional_info])
552
+ params['DisableApiTermination'] = options[:disable_api_termination].to_s unless options[:disable_api_termination].nil?
553
+ params['InstanceInitiatedShutdownBehavior'] = options[:instance_initiated_shutdown_behavior] unless Aws::Utils.blank?(options[:instance_initiated_shutdown_behavior])
554
+ unless Aws::Utils.blank?(options[:user_data])
555
+ options[:user_data].strip!
556
+ # Do not use CGI::escape(encode64(...)) as it is done in Amazons EC2 library.
557
+ # Amazon 169.254.169.254 does not like escaped symbols!
558
+ # And it doesn't like "\n" inside of encoded string! Grrr....
559
+ # Otherwise, some of UserData symbols will be lost...
560
+ params['UserData'] = Base64.encode64(options[:user_data]).delete("\n").strip unless Aws::Utils.blank?(options[:user_data])
561
+ end
562
+ unless Aws::Utils.blank?(options[:block_device_mappings])
563
+ options[:block_device_mappings].size.times do |n|
564
+ if options[:block_device_mappings][n][:virtual_name]
565
+ params["BlockDeviceMapping.#{n+1}.VirtualName"] = options[:block_device_mappings][n][:virtual_name]
566
+ end
567
+ if options[:block_device_mappings][n][:device_name]
568
+ params["BlockDeviceMapping.#{n+1}.DeviceName"] = options[:block_device_mappings][n][:device_name]
569
+ end
570
+ if options[:block_device_mappings][n][:ebs_snapshot_id]
571
+ params["BlockDeviceMapping.#{n+1}.Ebs.SnapshotId"] = options[:block_device_mappings][n][:ebs_snapshot_id]
572
+ end
573
+ end
574
+ end
575
+ link = generate_request("RunInstances", params)
576
+ #debugger
577
+ instances = request_info(link, QEc2DescribeInstancesParser.new(:logger => @logger))
578
+ get_desc_instances(instances)
579
+ rescue Exception
580
+ on_exception
581
+ end
582
+
583
+ def monitor_instances(list=[])
584
+ link = generate_request("MonitorInstances", hash_params('InstanceId', list.to_a))
585
+ request_info(link, QEc2TerminateInstancesParser.new(:logger => @logger))
586
+ rescue Exception
587
+ on_exception
588
+ end
589
+
590
+ # Terminates EC2 instances. Returns a list of termination params or an exception.
591
+ #
592
+ # ec2.terminate_instances(['i-f222222d','i-f222222e']) #=>
593
+ # [{:aws_shutdown_state => "shutting-down",
594
+ # :aws_instance_id => "i-f222222d",
595
+ # :aws_shutdown_state_code => 32,
596
+ # :aws_prev_state => "running",
597
+ # :aws_prev_state_code => 16},
598
+ # {:aws_shutdown_state => "shutting-down",
599
+ # :aws_instance_id => "i-f222222e",
600
+ # :aws_shutdown_state_code => 32,
601
+ # :aws_prev_state => "running",
602
+ # :aws_prev_state_code => 16}]
603
+ #
604
+ def terminate_instances(list=[])
605
+ link = generate_request("TerminateInstances", hash_params('InstanceId', list.to_a))
606
+ request_info(link, QEc2TerminateInstancesParser.new(:logger => @logger))
607
+ rescue Exception
608
+ on_exception
609
+ end
610
+
611
+ # Stop EBS-backed EC2 instances. Returns a list of instance state changes or an exception.
612
+ #
613
+ # ec2.stop_instances(['i-f222222d', 'i-f222222e']) #=>
614
+ # [{:aws_instance_id => "i-f222222d",
615
+ # :aws_current_state_code => 64,
616
+ # :aws_current_state => "stopping",
617
+ # :aws_prev_state_code => 16,
618
+ # :aws_prev_state => "running"},
619
+ # {:aws_instance_id => "i-f222222e",
620
+ # :aws_current_state_code => 64,
621
+ # :aws_current_state => "stopping",
622
+ # :aws_prev_state_code => 16,
623
+ # :aws_prev_state => "running"}]
624
+ #
625
+ def stop_instances(list=[])
626
+ link = generate_request("StopInstances", hash_params('InstanceId', list.to_a))
627
+ request_info(link, QEc2StopInstancesParser.new(:logger => @logger))
628
+ rescue Exception
629
+ on_exception
630
+ end
631
+
632
+ # Start EBS-backed EC2 instances. Returns a list of instance state changes or an exception.
633
+ #
634
+ # ec2.start_instances(['i-f222222d', 'i-f222222e']) #=>
635
+ # [{:aws_instance_id => "i-f222222d",
636
+ # :aws_current_state_code => 0,
637
+ # :aws_current_state => "pending",
638
+ # :aws_prev_state_code => 80,
639
+ # :aws_prev_state => "stopped"},
640
+ # {:aws_instance_id => "i-f222222e",
641
+ # :aws_current_state_code => 0,
642
+ # :aws_current_state => "pending",
643
+ # :aws_prev_state_code => 80,
644
+ # :aws_prev_state => "stopped"}]
645
+ #
646
+ def start_instances(list=[])
647
+ link = generate_request("StartInstances", hash_params('InstanceId', list.to_a))
648
+ request_info(link, QEc2StartInstancesParser.new(:logger => @logger))
649
+ rescue Exception
650
+ on_exception
651
+ end
652
+
653
+ # Retreive EC2 instance OS logs. Returns a hash of data or an exception.
654
+ #
655
+ # ec2.get_console_output('i-f222222d') =>
656
+ # {:aws_instance_id => 'i-f222222d',
657
+ # :aws_timestamp => "2007-05-23T14:36:07.000-07:00",
658
+ # :timestamp => Wed May 23 21:36:07 UTC 2007, # Time instance
659
+ # :aws_output => "Linux version 2.6.16-xenU (builder@patchbat.amazonsa) (gcc version 4.0.1 20050727 ..."
660
+ def get_console_output(instance_id)
661
+ link = generate_request("GetConsoleOutput", {'InstanceId.1' => instance_id})
662
+ request_info(link, QEc2GetConsoleOutputParser.new(:logger => @logger))
663
+ rescue Exception
664
+ on_exception
665
+ end
666
+
667
+ # Reboot an EC2 instance. Returns +true+ or an exception.
668
+ #
669
+ # ec2.reboot_instances(['i-f222222d','i-f222222e']) #=> true
670
+ #
671
+ def reboot_instances(list)
672
+ link = generate_request("RebootInstances", hash_params('InstanceId', list.to_a))
673
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
674
+ rescue Exception
675
+ on_exception
676
+ end
677
+
678
+ #-----------------------------------------------------------------
679
+ # Instances: Windows addons
680
+ #-----------------------------------------------------------------
681
+
682
+ # Get initial Windows Server setup password from an instance console output.
683
+ #
684
+ # my_awesome_key = ec2.create_key_pair('my_awesome_key') #=>
685
+ # {:aws_key_name => "my_awesome_key",
686
+ # :aws_fingerprint => "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03",
687
+ # :aws_material => "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAK...Q8MDrCbuQ=\n-----END RSA PRIVATE KEY-----"}
688
+ #
689
+ # my_awesome_instance = ec2.run_instances('ami-a000000a',1,1,['my_awesome_group'],'my_awesome_key', 'WindowsInstance!!!') #=>
690
+ # [{:aws_image_id => "ami-a000000a",
691
+ # :aws_instance_id => "i-12345678",
692
+ # ...
693
+ # :aws_availability_zone => "us-east-1b"
694
+ # }]
695
+ #
696
+ # # wait until instance enters 'operational' state and get it's initial password
697
+ #
698
+ # puts ec2.get_initial_password(my_awesome_instance[:aws_instance_id], my_awesome_key[:aws_material]) #=> "MhjWcgZuY6"
699
+ #
700
+ def get_initial_password(instance_id, private_key)
701
+ console_output = get_console_output(instance_id)
702
+ crypted_password = console_output[:aws_output][%r{<Password>(.+)</Password>}m] && $1
703
+ unless crypted_password
704
+ raise AwsError.new("Initial password was not found in console output for #{instance_id}")
705
+ else
706
+ OpenSSL::PKey::RSA.new(private_key).private_decrypt(Base64.decode64(crypted_password))
707
+ end
708
+ rescue Exception
709
+ on_exception
710
+ end
711
+
712
+ # Bundle a Windows image.
713
+ # Internally, it queues the bundling task and shuts down the instance.
714
+ # It then takes a snapshot of the Windows volume bundles it, and uploads it to
715
+ # S3. After bundling completes, Aws::Ec2#register_image may be used to
716
+ # register the new Windows AMI for subsequent launches.
717
+ #
718
+ # ec2.bundle_instance('i-e3e24e8a', 'my-awesome-bucket', 'my-win-image-1') #=>
719
+ # [{:aws_update_time => "2008-10-16T13:58:25.000Z",
720
+ # :s3_bucket => "kd-win-1",
721
+ # :s3_prefix => "win2pr",
722
+ # :aws_state => "pending",
723
+ # :aws_id => "bun-26a7424f",
724
+ # :aws_instance_id => "i-878a25ee",
725
+ # :aws_start_time => "2008-10-16T13:58:02.000Z"}]
726
+ #
727
+ def bundle_instance(instance_id, s3_bucket, s3_prefix,
728
+ s3_owner_aws_access_key_id=nil, s3_owner_aws_secret_access_key=nil,
729
+ s3_expires = S3Interface::DEFAULT_EXPIRES_AFTER,
730
+ s3_upload_policy='ec2-bundle-read')
731
+ # S3 access and signatures
732
+ s3_owner_aws_access_key_id ||= @aws_access_key_id
733
+ s3_owner_aws_secret_access_key ||= @aws_secret_access_key
734
+ s3_expires = Time.now.utc + s3_expires if s3_expires.is_a?(Fixnum) && (s3_expires < S3Interface::ONE_YEAR_IN_SECONDS)
735
+ # policy
736
+ policy = {'expiration' => s3_expires.strftime('%Y-%m-%dT%H:%M:%SZ'),
737
+ 'conditions' => [{'bucket' => s3_bucket},
738
+ {'acl' => s3_upload_policy},
739
+ ['starts-with', '$key', s3_prefix]]}.to_json
740
+ policy64 = Base64.encode64(policy).gsub("\n", "")
741
+ signed_policy64 = Utils.sign(s3_owner_aws_secret_access_key, policy64)
742
+ # fill request params
743
+ params = {'InstanceId' => instance_id,
744
+ 'Storage.S3.AWSAccessKeyId' => s3_owner_aws_access_key_id,
745
+ 'Storage.S3.UploadPolicy' => policy64,
746
+ 'Storage.S3.UploadPolicySignature' => signed_policy64,
747
+ 'Storage.S3.Bucket' => s3_bucket,
748
+ 'Storage.S3.Prefix' => s3_prefix,
749
+ }
750
+ link = generate_request("BundleInstance", params)
751
+ request_info(link, QEc2BundleInstanceParser.new)
752
+ rescue Exception
753
+ on_exception
754
+ end
755
+
756
+ # Describe the status of the Windows AMI bundlings.
757
+ # If +list+ is omitted the returns the whole list of tasks.
758
+ #
759
+ # ec2.describe_bundle_tasks(['bun-4fa74226']) #=>
760
+ # [{:s3_bucket => "my-awesome-bucket"
761
+ # :aws_id => "bun-0fa70206",
762
+ # :s3_prefix => "win1pr",
763
+ # :aws_start_time => "2008-10-14T16:27:57.000Z",
764
+ # :aws_update_time => "2008-10-14T16:37:10.000Z",
765
+ # :aws_error_code => "Client.S3Error",
766
+ # :aws_error_message =>
767
+ # "AccessDenied(403)- Invalid according to Policy: Policy Condition failed: [\"eq\", \"$acl\", \"aws-exec-read\"]",
768
+ # :aws_state => "failed",
769
+ # :aws_instance_id => "i-e3e24e8a"}]
770
+ #
771
+ def describe_bundle_tasks(list=[])
772
+ link = generate_request("DescribeBundleTasks", hash_params('BundleId', list.to_a))
773
+ request_info(link, QEc2DescribeBundleTasksParser.new)
774
+ rescue Exception
775
+ on_exception
776
+ end
777
+
778
+ # Cancel an in‐progress or pending bundle task by id.
779
+ #
780
+ # ec2.cancel_bundle_task('bun-73a7421a') #=>
781
+ # [{:s3_bucket => "my-awesome-bucket"
782
+ # :aws_id => "bun-0fa70206",
783
+ # :s3_prefix => "win02",
784
+ # :aws_start_time => "2008-10-14T13:00:29.000Z",
785
+ # :aws_error_message => "User has requested bundling operation cancellation",
786
+ # :aws_state => "failed",
787
+ # :aws_update_time => "2008-10-14T13:01:31.000Z",
788
+ # :aws_error_code => "Client.Cancelled",
789
+ # :aws_instance_id => "i-e3e24e8a"}
790
+ #
791
+ def cancel_bundle_task(bundle_id)
792
+ link = generate_request("CancelBundleTask", {'BundleId' => bundle_id})
793
+ request_info(link, QEc2BundleInstanceParser.new)
794
+ rescue Exception
795
+ on_exception
796
+ end
797
+
798
+ #-----------------------------------------------------------------
799
+ # Security groups
800
+ #-----------------------------------------------------------------
801
+
802
+ # Retrieve Security Group information. If +list+ is omitted the returns the whole list of groups.
803
+ #
804
+ # ec2.describe_security_groups #=>
805
+ # [{:aws_group_name => "default-1",
806
+ # :aws_owner => "000000000888",
807
+ # :aws_description => "a default security group",
808
+ # :aws_perms =>
809
+ # [ {:protocol => "tcp", :from_port=>"1000", :to_port=>"2000",
810
+ # :ip_ranges=>[{cidr_ip=>"10.1.2.3/32"}, {cidr_ip=>"192.168.1.10/24"}],
811
+ # :groups => [{:owner=>"123456789012", :group_name="default"}] },
812
+ #
813
+ # {:protocol ="icmp", :from_port="-1", :to_port=>"-1",
814
+ # :ip_ranges=>[{:cidr_ip=>"0.0.0.0/0"}],
815
+ # :groups=>[] },
816
+ #
817
+ # {:protocol=>"udp", :from_port=>"0", :to_port=>"65535",
818
+ # :ip_ranges=>[],
819
+ # :groups=>[{:owner=>"123456789012", :group_name=>"newgroup"}, {:owner=>"123456789012", :group_name=>"default"}],
820
+ #
821
+ # {:protocol=>"tcp", :from_port="22", :to_port=>"22",
822
+ # :ip_ranges=>[{:cidr_ip=>"0.0.0.0/0"}],
823
+ # :groups=>[{:owner=>"", :group_name=>"default"}] },
824
+ #
825
+ # ..., {...}
826
+ # ]
827
+ #
828
+ def describe_security_groups(list=[])
829
+ link = generate_request("DescribeSecurityGroups", hash_params('GroupName', list.to_a))
830
+ request_cache_or_info(:describe_security_groups, link, QEc2DescribeSecurityGroupsParser, @@bench, list.nil? || list.empty?) do |parser|
831
+ result = []
832
+ parser.result.each do |item|
833
+ perms = []
834
+ item.ipPermissions.each do |perm|
835
+ current = {:from_port => perm.fromPort,
836
+ :to_port => perm.toPort,
837
+ :protocol => perm.ipProtocol,
838
+ :groups => [], :ip_ranges => []}
839
+ perm.groups.each do |ngroup|
840
+ current[:groups] << {:group_name => ngroup.groupName, :owner => ngroup.userId}
841
+ end
842
+ perm.ipRanges.each do |cidr_ip|
843
+ current[:ip_ranges] << {:cidr_ip => cidr_ip.cidrIp}
844
+ end
845
+ perms << current
846
+ end
847
+ result << {:aws_owner => item.ownerId,
848
+ :aws_group_name => item.groupName,
849
+ :aws_description => item.groupDescription,
850
+ :aws_perms => perms}
851
+ end
852
+ result
853
+ end
854
+ rescue Exception
855
+ on_exception
856
+ end
857
+
858
+ # Create new Security Group. Returns +true+ or an exception.
859
+ #
860
+ # ec2.create_security_group('default-1',"Default allowing SSH, HTTP, and HTTPS ingress") #=> true
861
+ #
862
+ def create_security_group(name, description)
863
+ # EC2 doesn't like an empty description...
864
+ description = " " if Aws::Utils.blank?(description)
865
+ link = generate_request("CreateSecurityGroup",
866
+ 'GroupName' => name.to_s,
867
+ 'GroupDescription' => description.to_s)
868
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
869
+ rescue Exception
870
+ on_exception
871
+ end
872
+
873
+ # Remove Security Group. Returns +true+ or an exception.
874
+ #
875
+ # ec2.delete_security_group('default-1') #=> true
876
+ #
877
+ def delete_security_group(name)
878
+ link = generate_request("DeleteSecurityGroup",
879
+ 'GroupName' => name.to_s)
880
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
881
+ rescue Exception
882
+ on_exception
883
+ end
884
+
885
+ # Authorize OR Revoke ingress for security group, depending on the value of the 'action' parameter.
886
+ # If you 'authorize' then you allow instances that are member of some other
887
+ # security groups, or some range of ip addresses to open connections to instances in
888
+ # my group. Can specify an array of ip addresses, source groups or mix of both in a single rule:
889
+ #
890
+ # ec2.manage_security_group_ingress('authorize', 'new_firewall', 80, 80, 'tcp', ['192.168.0.1/32', '10.0.0.1/24'],
891
+ # [{'group_name'=>'default', 'owner'=>'297467797945'}, {'group_name'=>'test', 'owner'=>'123456789012'}])
892
+ #
893
+ # ec2.manage_security_group_ingress('new_firewall', 0, 1000, 'udp', 'revoke', [],
894
+ # [{'group_name'=>'default', 'owner'=>'123456789012'}])
895
+ #
896
+ # ec2.manage_security_group_ingress('new_firewall', 0, 1000, 'udp', 'authorize', ['0.0.0.0/0'])
897
+ #
898
+ # Similarly, if you specify 'revoke' as the action parameter then you will remove the specified
899
+ # source ip addresses or source groups from access to instances in the named group:
900
+ #
901
+ def manage_security_group_ingress(name, from_port, to_port, protocol, action, source_ip_ranges, source_groups = [])
902
+ call_params = { 'GroupName' => name.to_s,
903
+ 'IpPermissions.1.IpProtocol' => protocol.to_s,
904
+ 'IpPermissions.1.FromPort' => from_port.to_s,
905
+ 'IpPermissions.1.ToPort' => to_port.to_s }
906
+ source_ip_ranges.each_index do |i|
907
+ call_params.merge!({"IpPermissions.1.IpRanges.#{i+1}.CidrIp" => source_ip_ranges[i].to_s})
908
+ end
909
+ source_groups.each_index do |i|
910
+ call_params.merge!({"IpPermissions.1.Groups.#{i+1}.GroupName" => source_groups[i]['group_name'].to_s,
911
+ "IpPermissions.1.Groups.#{i+1}.UserId"=> source_groups[i]['owner'].to_s.gsub(/-/,'')})
912
+ end
913
+ unless ['Authorize', 'Revoke'].include?(action.capitalize)
914
+ raise AwsError.new("Invalid action #{action} - must be one of \'Authorize\' or \'Revoke\'")
915
+ end
916
+ link = generate_request("#{action.capitalize}SecurityGroupIngress", call_params)
917
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
918
+ rescue Exception
919
+ on_exception
920
+ end
921
+
922
+ # Authorize named ingress for security group. Allows instances that are member of someone
923
+ # else's security group to open connections to instances in my group.
924
+ #
925
+ # ec2.authorize_security_group_named_ingress('my_awesome_group', '7011-0219-8268', 'their_group_name') #=> true
926
+ #
927
+ def authorize_security_group_named_ingress(name, owner, group)
928
+ link = generate_request("AuthorizeSecurityGroupIngress",
929
+ 'GroupName' => name.to_s,
930
+ 'SourceSecurityGroupName' => group.to_s,
931
+ 'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/, ''))
932
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
933
+ rescue Exception
934
+ on_exception
935
+ end
936
+
937
+ # Revoke named ingress for security group.
938
+ #
939
+ # ec2.revoke_security_group_named_ingress('my_awesome_group', aws_user_id, 'another_group_name') #=> true
940
+ #
941
+ def revoke_security_group_named_ingress(name, owner, group)
942
+ link = generate_request("RevokeSecurityGroupIngress",
943
+ 'GroupName' => name.to_s,
944
+ 'SourceSecurityGroupName' => group.to_s,
945
+ 'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/, ''))
946
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
947
+ rescue Exception
948
+ on_exception
949
+ end
950
+
951
+ # Add permission to a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp'.
952
+ #
953
+ # ec2.authorize_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
954
+ # ec2.authorize_security_group_IP_ingress('my_awesome_group', -1, -1, 'icmp') #=> true
955
+ #
956
+ def authorize_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
957
+ link = generate_request("AuthorizeSecurityGroupIngress",
958
+ 'GroupName' => name.to_s,
959
+ 'IpProtocol' => protocol.to_s,
960
+ 'FromPort' => from_port.to_s,
961
+ 'ToPort' => to_port.to_s,
962
+ 'CidrIp' => cidr_ip.to_s)
963
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
964
+ rescue Exception
965
+ on_exception
966
+ end
967
+
968
+ # Remove permission from a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp' ('tcp' is default).
969
+ #
970
+ # ec2.revoke_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
971
+ #
972
+ def revoke_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
973
+ link = generate_request("RevokeSecurityGroupIngress",
974
+ 'GroupName' => name.to_s,
975
+ 'IpProtocol' => protocol.to_s,
976
+ 'FromPort' => from_port.to_s,
977
+ 'ToPort' => to_port.to_s,
978
+ 'CidrIp' => cidr_ip.to_s)
979
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
980
+ rescue Exception
981
+ on_exception
982
+ end
983
+
984
+ #-----------------------------------------------------------------
985
+ # Keys
986
+ #-----------------------------------------------------------------
987
+
988
+ # Retrieve a list of SSH keys. Returns an array of keys or an exception. Each key is
989
+ # represented as a two-element hash.
990
+ #
991
+ # ec2.describe_key_pairs #=>
992
+ # [{:aws_fingerprint=> "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03", :aws_key_name=>"key-1"},
993
+ # {:aws_fingerprint=> "1e:29:30:47:58:6d:7b:8c:9f:08:11:20:3c:44:52:69:74:80:97:08", :aws_key_name=>"key-2"},
994
+ # ..., {...} ]
995
+ #
996
+ def describe_key_pairs(list=[])
997
+ link = generate_request("DescribeKeyPairs", hash_params('KeyName', list.to_a))
998
+ request_cache_or_info :describe_key_pairs, link, QEc2DescribeKeyPairParser, @@bench, list.nil? || list.empty?
999
+ rescue Exception
1000
+ on_exception
1001
+ end
1002
+
1003
+ # Create new SSH key. Returns a hash of the key's data or an exception.
1004
+ #
1005
+ # ec2.create_key_pair('my_awesome_key') #=>
1006
+ # {:aws_key_name => "my_awesome_key",
1007
+ # :aws_fingerprint => "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03",
1008
+ # :aws_material => "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAK...Q8MDrCbuQ=\n-----END RSA PRIVATE KEY-----"}
1009
+ #
1010
+ def create_key_pair(name)
1011
+ link = generate_request("CreateKeyPair",
1012
+ 'KeyName' => name.to_s)
1013
+ request_info(link, QEc2CreateKeyPairParser.new(:logger => @logger))
1014
+ rescue Exception
1015
+ on_exception
1016
+ end
1017
+
1018
+ # Delete a key pair. Returns +true+ or an exception.
1019
+ #
1020
+ # ec2.delete_key_pair('my_awesome_key') #=> true
1021
+ #
1022
+ def delete_key_pair(name)
1023
+ link = generate_request("DeleteKeyPair",
1024
+ 'KeyName' => name.to_s)
1025
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
1026
+ rescue Exception
1027
+ on_exception
1028
+ end
1029
+
1030
+ #-----------------------------------------------------------------
1031
+ # Elastic IPs
1032
+ #-----------------------------------------------------------------
1033
+
1034
+ # Acquire a new elastic IP address for use with your account.
1035
+ # Returns allocated IP address or an exception.
1036
+ #
1037
+ # ec2.allocate_address #=> '75.101.154.140'
1038
+ #
1039
+ def allocate_address
1040
+ link = generate_request("AllocateAddress")
1041
+ request_info(link, QEc2AllocateAddressParser.new(:logger => @logger))
1042
+ rescue Exception
1043
+ on_exception
1044
+ end
1045
+
1046
+ # Associate an elastic IP address with an instance.
1047
+ # Returns +true+ or an exception.
1048
+ #
1049
+ # ec2.associate_address('i-d630cbbf', '75.101.154.140') #=> true
1050
+ #
1051
+ def associate_address(instance_id, public_ip)
1052
+ link = generate_request("AssociateAddress",
1053
+ "InstanceId" => instance_id.to_s,
1054
+ "PublicIp" => public_ip.to_s)
1055
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
1056
+ rescue Exception
1057
+ on_exception
1058
+ end
1059
+
1060
+ # List elastic IP addresses assigned to your account.
1061
+ # Returns an array of 2 keys (:instance_id and :public_ip) hashes:
1062
+ #
1063
+ # ec2.describe_addresses #=> [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.154.140"},
1064
+ # {:instance_id=>nil, :public_ip=>"75.101.154.141"}]
1065
+ #
1066
+ # ec2.describe_addresses('75.101.154.140') #=> [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.154.140"}]
1067
+ #
1068
+ def describe_addresses(list=[])
1069
+ link = generate_request("DescribeAddresses",
1070
+ hash_params('PublicIp', list.to_a))
1071
+ request_cache_or_info :describe_addresses, link, QEc2DescribeAddressesParser, @@bench, list.nil? || list.empty?
1072
+ rescue Exception
1073
+ on_exception
1074
+ end
1075
+
1076
+ # Disassociate the specified elastic IP address from the instance to which it is assigned.
1077
+ # Returns +true+ or an exception.
1078
+ #
1079
+ # ec2.disassociate_address('75.101.154.140') #=> true
1080
+ #
1081
+ def disassociate_address(public_ip)
1082
+ link = generate_request("DisassociateAddress",
1083
+ "PublicIp" => public_ip.to_s)
1084
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
1085
+ rescue Exception
1086
+ on_exception
1087
+ end
1088
+
1089
+ # Release an elastic IP address associated with your account.
1090
+ # Returns +true+ or an exception.
1091
+ #
1092
+ # ec2.release_address('75.101.154.140') #=> true
1093
+ #
1094
+ def release_address(public_ip)
1095
+ link = generate_request("ReleaseAddress",
1096
+ "PublicIp" => public_ip.to_s)
1097
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
1098
+ rescue Exception
1099
+ on_exception
1100
+ end
1101
+
1102
+ #-----------------------------------------------------------------
1103
+ # Availability zones
1104
+ #-----------------------------------------------------------------
1105
+
1106
+ # Describes availability zones that are currently available to the account and their states.
1107
+ # Returns an array of 2 keys (:zone_name and :zone_state) hashes:
1108
+ #
1109
+ # ec2.describe_availability_zones #=> [{:region_name=>"us-east-1",
1110
+ # :zone_name=>"us-east-1a",
1111
+ # :zone_state=>"available"}, ... ]
1112
+ #
1113
+ # ec2.describe_availability_zones('us-east-1c') #=> [{:region_name=>"us-east-1",
1114
+ # :zone_state=>"available",
1115
+ # :zone_name=>"us-east-1c"}]
1116
+ #
1117
+ def describe_availability_zones(list=[])
1118
+ link = generate_request("DescribeAvailabilityZones",
1119
+ hash_params('ZoneName', list.to_a))
1120
+ request_cache_or_info :describe_availability_zones, link, QEc2DescribeAvailabilityZonesParser, @@bench, list.nil? || list.empty?
1121
+ rescue Exception
1122
+ on_exception
1123
+ end
1124
+
1125
+ # This is using the new way, but not sure it's backwrads compatible
1126
+ def describe_availability_zones2(options={})
1127
+ link = generate_request("DescribeAvailabilityZones", options={})
1128
+ request_info_xml_simple(self.class.connection_name, @params, link, @logger,
1129
+ :group_tags =>{"DBInstances" =>"DBInstance",
1130
+ "DBParameterGroups"=>"DBParameterGroup",
1131
+ "DBSecurityGroups" =>"DBSecurityGroup",
1132
+ "EC2SecurityGroups"=>"EC2SecurityGroup",
1133
+ "IPRanges" =>"IPRange"},
1134
+ :force_array =>["DBInstances",
1135
+ "DBParameterGroups",
1136
+ "DBSecurityGroups",
1137
+ "EC2SecurityGroups",
1138
+ "IPRanges"],
1139
+ :pull_out_array =>options[:pull_out_array],
1140
+ :pull_out_single=>options[:pull_out_single],
1141
+ :wrapper =>options[:wrapper])
1142
+ rescue Exception
1143
+ on_exception
1144
+ end
1145
+
1146
+
1147
+ #-----------------------------------------------------------------
1148
+ # Regions
1149
+ #-----------------------------------------------------------------
1150
+
1151
+ # Describe regions.
1152
+ #
1153
+ # ec2.describe_regions #=> ["eu-west-1", "us-east-1"]
1154
+ #
1155
+ def describe_regions(list=[])
1156
+ link = generate_request("DescribeRegions",
1157
+ hash_params('RegionName', list.to_a))
1158
+ request_cache_or_info :describe_regions, link, QEc2DescribeRegionsParser, @@bench, list.nil? || list.empty?
1159
+ rescue Exception
1160
+ on_exception
1161
+ end
1162
+
1163
+
1164
+ #-----------------------------------------------------------------
1165
+ # EBS: Volumes
1166
+ #-----------------------------------------------------------------
1167
+
1168
+ # Describe all EBS volumes.
1169
+ #
1170
+ # ec2.describe_volumes #=>
1171
+ # [{:aws_size => 94,
1172
+ # :aws_device => "/dev/sdc",
1173
+ # :aws_attachment_status => "attached",
1174
+ # :zone => "merlot",
1175
+ # :snapshot_id => nil,
1176
+ # :aws_attached_at => Wed Jun 18 08:19:28 UTC 2008,
1177
+ # :aws_status => "in-use",
1178
+ # :aws_id => "vol-60957009",
1179
+ # :aws_created_at => Wed Jun 18 08:19:20s UTC 2008,
1180
+ # :aws_instance_id => "i-c014c0a9"},
1181
+ # {:aws_size => 1,
1182
+ # :zone => "merlot",
1183
+ # :snapshot_id => nil,
1184
+ # :aws_status => "available",
1185
+ # :aws_id => "vol-58957031",
1186
+ # :aws_created_at => Wed Jun 18 08:19:21 UTC 2008,}, ... ]
1187
+ #
1188
+ def describe_volumes(list=[])
1189
+ link = generate_request("DescribeVolumes",
1190
+ hash_params('VolumeId', list.to_a))
1191
+ request_cache_or_info :describe_volumes, link, QEc2DescribeVolumesParser, @@bench, list.nil? || list.empty?
1192
+ rescue Exception
1193
+ on_exception
1194
+ end
1195
+
1196
+ # Create new EBS volume based on previously created snapshot.
1197
+ # +Size+ in Gigabytes.
1198
+ #
1199
+ # ec2.create_volume('snap-000000', 10, zone) #=>
1200
+ # {:snapshot_id => "snap-e21df98b",
1201
+ # :aws_status => "creating",
1202
+ # :aws_id => "vol-fc9f7a95",
1203
+ # :zone => "merlot",
1204
+ # :aws_created_at => Tue Jun 24 18:13:32 UTC 2008,
1205
+ # :aws_size => 94}
1206
+ #
1207
+ def create_volume(snapshot_id, size, zone)
1208
+ params = {'Size' => size.to_s, 'AvailabilityZone' => zone.to_s}
1209
+ params['SnapshotId'] = snapshot_id if snapshot_id && snapshot_id.length > 0 # snapshotId is conditional
1210
+ link = generate_request("CreateVolume",
1211
+ params)
1212
+ request_info(link, QEc2CreateVolumeParser.new(:logger => @logger))
1213
+ rescue Exception
1214
+ on_exception
1215
+ end
1216
+
1217
+ # Delete the specified EBS volume.
1218
+ # This does not deletes any snapshots created from this volume.
1219
+ #
1220
+ # ec2.delete_volume('vol-b48a6fdd') #=> true
1221
+ #
1222
+ def delete_volume(volume_id)
1223
+ link = generate_request("DeleteVolume",
1224
+ "VolumeId" => volume_id.to_s)
1225
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
1226
+ rescue Exception
1227
+ on_exception
1228
+ end
1229
+
1230
+ # Creates an Amazon EBS-backed AMI from an Amazon EBS-backed instance
1231
+ # Instance must be either the running or stopped state
1232
+ #
1233
+ # ec2.create_image('i-4jhdmaw', 'New image')
1234
+ #
1235
+ def create_image(instance_id, name, description="")
1236
+ link = generate_request("CreateImage",
1237
+ "InstanceId" => instance_id,
1238
+ "Name" => name,
1239
+ "Description" => description)
1240
+ request_info(link, QEc2CreateImageParser.new(:logger => @logger))
1241
+ rescue
1242
+ on_exception
1243
+ end
1244
+
1245
+ # Attach the specified EBS volume to a specified instance, exposing the
1246
+ # volume using the specified device name.
1247
+ #
1248
+ # ec2.attach_volume('vol-898a6fe0', 'i-7c905415', '/dev/sdh') #=>
1249
+ # { :aws_instance_id => "i-7c905415",
1250
+ # :aws_device => "/dev/sdh",
1251
+ # :aws_status => "attaching",
1252
+ # :aws_attached_at => "2008-03-28T14:14:39.000Z",
1253
+ # :aws_id => "vol-898a6fe0" }
1254
+ #
1255
+ def attach_volume(volume_id, instance_id, device)
1256
+ link = generate_request("AttachVolume",
1257
+ "VolumeId" => volume_id.to_s,
1258
+ "InstanceId" => instance_id.to_s,
1259
+ "Device" => device.to_s)
1260
+ request_info(link, QEc2AttachAndDetachVolumeParser.new(:logger => @logger))
1261
+ rescue Exception
1262
+ on_exception
1263
+ end
1264
+
1265
+ # Detach the specified EBS volume from the instance to which it is attached.
1266
+ #
1267
+ # ec2.detach_volume('vol-898a6fe0') #=>
1268
+ # { :aws_instance_id => "i-7c905415",
1269
+ # :aws_device => "/dev/sdh",
1270
+ # :aws_status => "detaching",
1271
+ # :aws_attached_at => "2008-03-28T14:38:34.000Z",
1272
+ # :aws_id => "vol-898a6fe0"}
1273
+ #
1274
+ def detach_volume(volume_id, instance_id=nil, device=nil, force=nil)
1275
+ hash = {"VolumeId" => volume_id.to_s}
1276
+ hash["InstanceId"] = instance_id.to_s unless Aws::Utils.blank?(instance_id)
1277
+ hash["Device"] = device.to_s unless Aws::Utils.blank?(device)
1278
+ hash["Force"] = 'true' if force
1279
+ #
1280
+ link = generate_request("DetachVolume", hash)
1281
+ request_info(link, QEc2AttachAndDetachVolumeParser.new(:logger => @logger))
1282
+ rescue Exception
1283
+ on_exception
1284
+ end
1285
+
1286
+
1287
+ #-----------------------------------------------------------------
1288
+ # EBS: Snapshots
1289
+ #-----------------------------------------------------------------
1290
+
1291
+ # Describe all EBS snapshots.
1292
+ #
1293
+ # ec2.describe_snapshots #=>
1294
+ # [ { :aws_progress => "100%",
1295
+ # :aws_status => "completed",
1296
+ # :aws_id => "snap-72a5401b",
1297
+ # :aws_volume_id => "vol-5582673c",
1298
+ # :aws_started_at => "2008-02-23T02:50:48.000Z"},
1299
+ # { :aws_progress => "100%",
1300
+ # :aws_status => "completed",
1301
+ # :aws_id => "snap-75a5401c",
1302
+ # :aws_volume_id => "vol-5582673c",
1303
+ # :aws_started_at => "2008-02-23T16:23:19.000Z" },...]
1304
+ #
1305
+ def describe_snapshots(list=[])
1306
+ link = generate_request("DescribeSnapshots",
1307
+ hash_params('SnapshotId', list.to_a))
1308
+ request_cache_or_info :describe_snapshots, link, QEc2DescribeSnapshotsParser, @@bench, list.nil? || list.empty?
1309
+ rescue Exception
1310
+ on_exception
1311
+ end
1312
+
1313
+ def describe_owned_snapshots(list=[])
1314
+ params = {"Owner" => "self"}
1315
+ snap_ids = hash_params('SnapshotId', list.to_a)
1316
+ params.update(snap_ids)
1317
+ link = generate_request("DescribeSnapshots",
1318
+ params)
1319
+ request_cache_or_info :describe_owned_snapshots, link, QEc2DescribeSnapshotsParser, @@bench, list.nil? || list.empty?
1320
+ rescue Exception
1321
+ on_exception
1322
+ end
1323
+
1324
+
1325
+ # Create a snapshot of specified volume.
1326
+ #
1327
+ # ec2.create_snapshot('vol-898a6fe0') #=>
1328
+ # {:aws_volume_id => "vol-fd9f7a94",
1329
+ # :aws_started_at => Tue Jun 24 18:40:40 UTC 2008,
1330
+ # :aws_progress => "",
1331
+ # :aws_status => "pending",
1332
+ # :aws_id => "snap-d56783bc"}
1333
+ #
1334
+ def create_snapshot(volume_id, options={})
1335
+ link = generate_request("CreateSnapshot", options.merge({"VolumeId" => volume_id.to_s}))
1336
+ request_info(link, QEc2CreateSnapshotParser.new(:logger => @logger))
1337
+ rescue Exception
1338
+ on_exception
1339
+ end
1340
+
1341
+ # Create a snapshot of specified volume, but with the normal retry algorithms disabled.
1342
+ # This method will return immediately upon error. The user can specify connect and read timeouts (in s)
1343
+ # for the connection to AWS. If the user does not specify timeouts, try_create_snapshot uses the default values
1344
+ # in Rightscale::HttpConnection.
1345
+ #
1346
+ # ec2.try_create_snapshot('vol-898a6fe0') #=>
1347
+ # {:aws_volume_id => "vol-fd9f7a94",
1348
+ # :aws_started_at => Tue Jun 24 18:40:40 UTC 2008,
1349
+ # :aws_progress => "",
1350
+ # :aws_status => "pending",
1351
+ # :aws_id => "snap-d56783bc"}
1352
+ #
1353
+ def try_create_snapshot(volume_id, connect_timeout = nil, read_timeout = nil)
1354
+ # For safety in the ensure block...we don't want to restore values
1355
+ # if we never read them in the first place
1356
+ orig_reiteration_time = nil
1357
+ orig_http_params = nil
1358
+
1359
+ orig_reiteration_time = Aws::AWSErrorHandler::reiteration_time
1360
+ Aws::AWSErrorHandler::reiteration_time = 0
1361
+
1362
+ orig_http_params = Rightscale::HttpConnection::params()
1363
+ new_http_params = orig_http_params.dup
1364
+ new_http_params[:http_connection_retry_count] = 0
1365
+ new_http_params[:http_connection_open_timeout] = connect_timeout if !connect_timeout.nil?
1366
+ new_http_params[:http_connection_read_timeout] = read_timeout if !read_timeout.nil?
1367
+ Rightscale::HttpConnection::params = new_http_params
1368
+
1369
+ link = generate_request("CreateSnapshot",
1370
+ "VolumeId" => volume_id.to_s)
1371
+ request_info(link, QEc2CreateSnapshotParser.new(:logger => @logger))
1372
+
1373
+ rescue Exception
1374
+ on_exception
1375
+ ensure
1376
+ Aws::AWSErrorHandler::reiteration_time = orig_reiteration_time if orig_reiteration_time
1377
+ Rightscale::HttpConnection::params = orig_http_params if orig_http_params
1378
+ end
1379
+
1380
+ # Delete the specified snapshot.
1381
+ #
1382
+ # ec2.delete_snapshot('snap-55a5403c') #=> true
1383
+ #
1384
+ def delete_snapshot(snapshot_id)
1385
+ link = generate_request("DeleteSnapshot",
1386
+ "SnapshotId" => snapshot_id.to_s)
1387
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
1388
+ rescue Exception
1389
+ on_exception
1390
+ end
1391
+
1392
+ # Add/replace one tag to a resource
1393
+ # http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference_query_CreateTags.html
1394
+ #
1395
+ # ec2.create_tag('ami-1a2b3c4d', 'webserver') #=> true
1396
+ # ec2.create_tag('i-7f4d3a2b', 'stack', 'Production') #=> true
1397
+ #
1398
+ def create_tag(resource_id, key, value = nil)
1399
+ link = generate_request("CreateTags",
1400
+ "ResourceId.1" => resource_id.to_s,
1401
+ "Tag.1.Key" => key.to_s,
1402
+ "Tag.1.Value" => value.to_s)
1403
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
1404
+ rescue Exception
1405
+ on_exception
1406
+ end
1407
+
1408
+ # Describe tags
1409
+ # http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference_query_DescribeTags.html
1410
+ #
1411
+ # ec2.describe_tags
1412
+ # ec2.describe_tags(
1413
+ # 'Filter.1.Name' => 'resource-type', 'Filter.1.Value.1' => 'instance',
1414
+ # 'Filter.2.Name' => 'value', 'Filter.2.Value.1' => 'Test', 'Filter.2.Value.2' => 'Production'
1415
+ # )
1416
+ #
1417
+ def describe_tags(filters = {})
1418
+ link = generate_request("DescribeTags", filters)
1419
+ request_info(link, QEc2DescribeTagsParser.new(:logger => @logger))
1420
+ rescue Exception
1421
+ on_exception
1422
+ end
1423
+
1424
+ # Delete one or all tags from a resource
1425
+ # http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference_query_DeleteTags.html
1426
+ #
1427
+ # ec2.delete_tag('i-7f4d3a2b', 'stack') #=> true
1428
+ # ec2.delete_tag('i-7f4d3a2b', 'stack', 'Production') #=> true
1429
+ #
1430
+ # "If you omit Tag.n.Value, we delete the tag regardless of its value. If
1431
+ # you specify this parameter with an empty string as the value, we delete the
1432
+ # key only if its value is an empty string."
1433
+ # http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference_query_DeleteTags.html
1434
+ #
1435
+ def delete_tag(resource_id, key, value = nil)
1436
+ request_args = {"ResourceId.1" => resource_id.to_s, "Tag.1.Key" => key.to_s}
1437
+ request_args["Tag.1.Value"] = value.to_s if value
1438
+
1439
+ link = generate_request("DeleteTags", request_args)
1440
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
1441
+ rescue Exception
1442
+ on_exception
1443
+ end
1444
+
1445
+ #-----------------------------------------------------------------
1446
+ # PARSERS: Boolean Response Parser
1447
+ #-----------------------------------------------------------------
1448
+
1449
+ class RightBoolResponseParser < AwsParser #:nodoc:
1450
+ def tagend(name)
1451
+ @result = @text=='true' ? true : false if name == 'return'
1452
+ end
1453
+ end
1454
+
1455
+ #-----------------------------------------------------------------
1456
+ # PARSERS: Key Pair
1457
+ #-----------------------------------------------------------------
1458
+
1459
+ class QEc2DescribeKeyPairParser < AwsParser #:nodoc:
1460
+ def tagstart(name, attributes)
1461
+ @item = {} if name == 'item'
1462
+ end
1463
+
1464
+ def tagend(name)
1465
+ case name
1466
+ when 'keyName' then
1467
+ @item[:aws_key_name] = @text
1468
+ when 'keyFingerprint' then
1469
+ @item[:aws_fingerprint] = @text
1470
+ when 'item' then
1471
+ @result << @item
1472
+ end
1473
+ end
1474
+
1475
+ def reset
1476
+ @result = [];
1477
+ end
1478
+ end
1479
+
1480
+ class QEc2CreateKeyPairParser < AwsParser #:nodoc:
1481
+ def tagstart(name, attributes)
1482
+ @result = {} if name == 'CreateKeyPairResponse'
1483
+ end
1484
+
1485
+ def tagend(name)
1486
+ case name
1487
+ when 'keyName' then
1488
+ @result[:aws_key_name] = @text
1489
+ when 'keyFingerprint' then
1490
+ @result[:aws_fingerprint] = @text
1491
+ when 'keyMaterial' then
1492
+ @result[:aws_material] = @text
1493
+ end
1494
+ end
1495
+ end
1496
+
1497
+ #-----------------------------------------------------------------
1498
+ # PARSERS: Security Groups
1499
+ #-----------------------------------------------------------------
1500
+
1501
+ class QEc2UserIdGroupPairType #:nodoc:
1502
+ attr_accessor :userId
1503
+ attr_accessor :groupName
1504
+ end
1505
+
1506
+ class QEc2IpRangeItemType #:nodoc:
1507
+ attr_accessor :cidrIp
1508
+ end
1509
+
1510
+ class QEc2IpPermissionType #:nodoc:
1511
+ attr_accessor :ipProtocol
1512
+ attr_accessor :fromPort
1513
+ attr_accessor :toPort
1514
+ attr_accessor :groups
1515
+ attr_accessor :ipRanges
1516
+ end
1517
+
1518
+ class QEc2SecurityGroupItemType #:nodoc:
1519
+ attr_accessor :groupName
1520
+ attr_accessor :groupDescription
1521
+ attr_accessor :ownerId
1522
+ attr_accessor :ipPermissions
1523
+ end
1524
+
1525
+
1526
+ class QEc2DescribeSecurityGroupsParser < AwsParser #:nodoc:
1527
+ def tagstart(name, attributes)
1528
+ case name
1529
+ when 'item'
1530
+ if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo'
1531
+ @group = QEc2SecurityGroupItemType.new
1532
+ @group.ipPermissions = []
1533
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions'
1534
+ @perm = QEc2IpPermissionType.new
1535
+ @perm.ipRanges = []
1536
+ @perm.groups = []
1537
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups'
1538
+ @sgroup = QEc2UserIdGroupPairType.new
1539
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/ipRanges'
1540
+ @sIpRange = QEc2IpRangeItemType.new
1541
+ end
1542
+ end
1543
+ end
1544
+
1545
+ def tagend(name)
1546
+ case name
1547
+ when 'ownerId' then @group.ownerId = @text
1548
+ when 'groupDescription' then @group.groupDescription = @text
1549
+ when 'groupName'
1550
+ if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item'
1551
+ @group.groupName = @text
1552
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups/item'
1553
+ @sgroup.groupName = @text
1554
+ end
1555
+ when 'ipProtocol' then @perm.ipProtocol = @text
1556
+ when 'fromPort' then @perm.fromPort = @text
1557
+ when 'toPort' then @perm.toPort = @text
1558
+ when 'userId' then @sgroup.userId = @text
1559
+ when 'cidrIp' then @sIpRange.cidrIp = @text
1560
+ when 'item'
1561
+ if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups'
1562
+ @perm.groups << @sgroup
1563
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/ipRanges'
1564
+ @perm.ipRanges << @sIpRange
1565
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions'
1566
+ @group.ipPermissions << @perm
1567
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo'
1568
+ @result << @group
1569
+ end
1570
+ end
1571
+ end
1572
+
1573
+ def reset
1574
+ @result = []
1575
+ end
1576
+ end
1577
+
1578
+ #-----------------------------------------------------------------
1579
+ # PARSERS: Images
1580
+ #-----------------------------------------------------------------
1581
+
1582
+ class QEc2DescribeImagesParser < AwsParser #:nodoc:
1583
+ def tagstart(name, attributes)
1584
+ if name == 'item' && @xmlpath[%r{.*/imagesSet$}]
1585
+ @image = {}
1586
+ end
1587
+ end
1588
+
1589
+ def tagend(name)
1590
+ case name
1591
+ when 'imageId' then
1592
+ @image[:aws_id] = @text
1593
+ when 'name' then
1594
+ @image[:aws_name] = @text
1595
+ when 'description' then
1596
+ @image[:aws_description] = @text
1597
+ when 'imageLocation' then
1598
+ @image[:aws_location] = @text
1599
+ when 'imageState' then
1600
+ @image[:aws_state] = @text
1601
+ when 'imageOwnerId' then
1602
+ @image[:aws_owner] = @text
1603
+ when 'isPublic' then
1604
+ @image[:aws_is_public]= @text == 'true' ? true : false
1605
+ when 'productCode' then
1606
+ (@image[:aws_product_codes] ||= []) << @text
1607
+ when 'architecture' then
1608
+ @image[:aws_architecture] = @text
1609
+ when 'imageType' then
1610
+ @image[:aws_image_type] = @text
1611
+ when 'kernelId' then
1612
+ @image[:aws_kernel_id] = @text
1613
+ when 'ramdiskId' then
1614
+ @image[:aws_ramdisk_id] = @text
1615
+ when 'item' then
1616
+ @result << @image if @xmlpath[%r{.*/imagesSet$}]
1617
+ end
1618
+ end
1619
+
1620
+ def reset
1621
+ @result = []
1622
+ end
1623
+ end
1624
+
1625
+ class QEc2RegisterImageParser < AwsParser #:nodoc:
1626
+ def tagend(name)
1627
+ @result = @text if name == 'imageId'
1628
+ end
1629
+ end
1630
+
1631
+ #-----------------------------------------------------------------
1632
+ # PARSERS: Image Attribute
1633
+ #-----------------------------------------------------------------
1634
+
1635
+ class QEc2DescribeImageAttributeParser < AwsParser #:nodoc:
1636
+ def tagstart(name, attributes)
1637
+ case name
1638
+ when 'launchPermission'
1639
+ @result[:groups] = []
1640
+ @result[:users] = []
1641
+ when 'productCodes'
1642
+ @result[:aws_product_codes] = []
1643
+ end
1644
+ end
1645
+
1646
+ def tagend(name)
1647
+ # right now only 'launchPermission' is supported by Amazon.
1648
+ # But nobody know what will they xml later as attribute. That is why we
1649
+ # check for 'group' and 'userId' inside of 'launchPermission/item'
1650
+ case name
1651
+ when 'imageId' then
1652
+ @result[:aws_id] = @text
1653
+ when 'group' then
1654
+ @result[:groups] << @text if @xmlpath == 'DescribeImageAttributeResponse/launchPermission/item'
1655
+ when 'userId' then
1656
+ @result[:users] << @text if @xmlpath == 'DescribeImageAttributeResponse/launchPermission/item'
1657
+ when 'productCode' then
1658
+ @result[:aws_product_codes] << @text
1659
+ when 'kernel' then
1660
+ @result[:aws_kernel] = @text
1661
+ when 'ramdisk' then
1662
+ @result[:aws_ramdisk] = @text
1663
+ when 'blockDeviceMapping' then
1664
+ @result[:block_device_mapping] = @text
1665
+ end
1666
+ end
1667
+
1668
+ def reset
1669
+ @result = {}
1670
+ end
1671
+ end
1672
+
1673
+ #-----------------------------------------------------------------
1674
+ # PARSERS: Instances
1675
+ #-----------------------------------------------------------------
1676
+
1677
+ class QEc2DescribeInstancesParser < AwsParser #:nodoc:
1678
+ def tagstart(name, attributes)
1679
+ # DescribeInstances property
1680
+ if (name == 'item' && @xmlpath == 'DescribeInstancesResponse/reservationSet') ||
1681
+ # RunInstances property
1682
+ (name == 'RunInstancesResponse')
1683
+ @reservation = {:aws_groups => [],
1684
+ :instances_set => []}
1685
+
1686
+ elsif (name == 'item') &&
1687
+ # DescribeInstances property
1688
+ (@xmlpath=='DescribeInstancesResponse/reservationSet/item/instancesSet' ||
1689
+ # RunInstances property
1690
+ @xmlpath=='RunInstancesResponse/instancesSet')
1691
+ # the optional params (sometimes are missing and we dont want them to be nil)
1692
+ @instance = {:aws_reason => '',
1693
+ :dns_name => '',
1694
+ :private_dns_name => '',
1695
+ :ami_launch_index => '',
1696
+ :ssh_key_name => '',
1697
+ :aws_state => '',
1698
+ :root_device_type => '',
1699
+ :root_device_name => '',
1700
+ :architecture => '',
1701
+ :block_device_mappings => [],
1702
+ :aws_product_codes => [],
1703
+ :tags => {}}
1704
+ end
1705
+ end
1706
+
1707
+ def tagend(name)
1708
+ case name
1709
+ when 'rootDeviceType' then
1710
+ @instance[:root_device_type] = @text
1711
+ when 'architecture' then
1712
+ @instance[:architecture] = @text
1713
+ when 'rootDeviceName' then
1714
+ @instance[:root_device_name] = @text
1715
+ # reservation
1716
+ when 'reservationId' then
1717
+ @reservation[:aws_reservation_id] = @text
1718
+ when 'ownerId' then
1719
+ @reservation[:aws_owner] = @text
1720
+ when 'groupId' then
1721
+ @reservation[:aws_groups] << @text
1722
+ # instance
1723
+ when 'instanceId' then
1724
+ @instance[:aws_instance_id] = @text
1725
+ when 'imageId' then
1726
+ @instance[:aws_image_id] = @text
1727
+ when 'dnsName' then
1728
+ @instance[:dns_name] = @text
1729
+ when 'privateDnsName' then
1730
+ @instance[:private_dns_name] = @text
1731
+ when 'reason' then
1732
+ @instance[:aws_reason] = @text
1733
+ when 'keyName' then
1734
+ @instance[:ssh_key_name] = @text
1735
+ when 'amiLaunchIndex' then
1736
+ @instance[:ami_launch_index] = @text
1737
+ when 'code' then
1738
+ @instance[:aws_state_code] = @text
1739
+ when 'name' then
1740
+ @instance[:aws_state] = @text
1741
+ when 'productCode' then
1742
+ @instance[:aws_product_codes] << @text
1743
+ when 'instanceType' then
1744
+ @instance[:aws_instance_type] = @text
1745
+ when 'launchTime' then
1746
+ @instance[:aws_launch_time] = @text
1747
+ when 'kernelId' then
1748
+ @instance[:aws_kernel_id] = @text
1749
+ when 'ramdiskId' then
1750
+ @instance[:aws_ramdisk_id] = @text
1751
+ when 'platform' then
1752
+ @instance[:aws_platform] = @text
1753
+ when 'availabilityZone' then
1754
+ @instance[:aws_availability_zone] = @text
1755
+ when 'privateIpAddress' then
1756
+ @instance[:aws_private_ip_address] = @text
1757
+ when 'key' then
1758
+ @tag_key = @text
1759
+ when 'value' then
1760
+ @tag_value = @text
1761
+ when 'deviceName' then
1762
+ @device_name = @text
1763
+ when 'volumeId' then
1764
+ @volume_id = @text
1765
+ when 'state'
1766
+ if @xmlpath == 'DescribeInstancesResponse/reservationSet/item/instancesSet/item/monitoring' || # DescribeInstances property
1767
+ @xmlpath == 'RunInstancesResponse/instancesSet/item/monitoring' # RunInstances property
1768
+ @instance[:monitoring_state] = @text
1769
+ end
1770
+ when 'item'
1771
+ if @xmlpath=='DescribeInstancesResponse/reservationSet/item/instancesSet/item/tagSet' # Tags
1772
+ @instance[:tags][@tag_key] = @tag_value
1773
+ elsif @xmlpath == 'DescribeInstancesResponse/reservationSet/item/instancesSet/item/blockDeviceMapping' # Block device mappings
1774
+ @instance[:block_device_mappings] << { @device_name => @volume_id }
1775
+ elsif @xmlpath == 'DescribeInstancesResponse/reservationSet/item/instancesSet' || # DescribeInstances property
1776
+ @xmlpath == 'RunInstancesResponse/instancesSet' # RunInstances property
1777
+ @reservation[:instances_set] << @instance
1778
+ elsif @xmlpath=='DescribeInstancesResponse/reservationSet' # DescribeInstances property
1779
+ @result << @reservation
1780
+ end
1781
+ when 'RunInstancesResponse' then
1782
+ @result << @reservation # RunInstances property
1783
+ end
1784
+ end
1785
+
1786
+ def reset
1787
+ @result = []
1788
+ end
1789
+ end
1790
+
1791
+ class QEc2ConfirmProductInstanceParser < AwsParser #:nodoc:
1792
+ def tagend(name)
1793
+ @result = @text if name == 'ownerId'
1794
+ end
1795
+ end
1796
+
1797
+ class QEc2MonitorInstancesParser < AwsParser #:nodoc:
1798
+ def tagstart(name, attributes)
1799
+ @instance = {} if name == 'item'
1800
+ end
1801
+
1802
+ def tagend(name)
1803
+ case name
1804
+ when 'instanceId' then
1805
+ @instance[:aws_instance_id] = @text
1806
+ when 'state' then
1807
+ @instance[:aws_monitoring_state] = @text
1808
+ when 'item' then
1809
+ @result << @instance
1810
+ end
1811
+ end
1812
+
1813
+ def reset
1814
+ @result = []
1815
+ end
1816
+ end
1817
+
1818
+ class QEc2CreateImageParser < AwsParser #:nodoc:
1819
+ def tagend(name)
1820
+ @result = @text if name == 'imageId'
1821
+ end
1822
+ end
1823
+
1824
+
1825
+ class QEc2TerminateInstancesParser < AwsParser #:nodoc:
1826
+ def tagstart(name, attributes)
1827
+ @instance = {} if name == 'item'
1828
+ end
1829
+
1830
+ def tagend(name)
1831
+ case name
1832
+ when 'instanceId' then
1833
+ @instance[:aws_instance_id] = @text
1834
+ when 'code'
1835
+ if @xmlpath == 'TerminateInstancesResponse/instancesSet/item/shutdownState'
1836
+ @instance[:aws_shutdown_state_code] = @text.to_i
1837
+ else
1838
+ @instance[:aws_prev_state_code] = @text.to_i
1839
+ end
1840
+ when 'name'
1841
+ if @xmlpath == 'TerminateInstancesResponse/instancesSet/item/shutdownState'
1842
+ @instance[:aws_shutdown_state] = @text
1843
+ else
1844
+ @instance[:aws_prev_state] = @text
1845
+ end
1846
+ when 'item' then
1847
+ @result << @instance
1848
+ end
1849
+ end
1850
+
1851
+ def reset
1852
+ @result = []
1853
+ end
1854
+ end
1855
+
1856
+ class QEc2StopInstancesParser < AwsParser #:nodoc:
1857
+ def tagstart(name, attributes)
1858
+ @instance = {} if name == 'item'
1859
+ end
1860
+
1861
+ def tagend(name)
1862
+ case name
1863
+ when 'instanceId' then
1864
+ @instance[:aws_instance_id] = @text
1865
+ when 'code'
1866
+ if @xmlpath == 'StopInstancesResponse/instancesSet/item/currentState'
1867
+ @instance[:aws_current_state_code] = @text.to_i
1868
+ elsif @xmlpath == 'StopInstancesResponse/instancesSet/item/previousState'
1869
+ @instance[:aws_prev_state_code] = @text.to_i
1870
+ end
1871
+ when 'name'
1872
+ if @xmlpath == 'StopInstancesResponse/instancesSet/item/currentState'
1873
+ @instance[:aws_current_state] = @text
1874
+ elsif @xmlpath == 'StopInstancesResponse/instancesSet/item/previousState'
1875
+ @instance[:aws_prev_state] = @text
1876
+ end
1877
+ when 'item' then
1878
+ @result << @instance
1879
+ end
1880
+ end
1881
+
1882
+ def reset
1883
+ @result = []
1884
+ end
1885
+ end
1886
+
1887
+ class QEc2StartInstancesParser < AwsParser #:nodoc:
1888
+ def tagstart(name, attributes)
1889
+ @instance = {} if name == 'item'
1890
+ end
1891
+
1892
+ def tagend(name)
1893
+ case name
1894
+ when 'instanceId' then
1895
+ @instance[:aws_instance_id] = @text
1896
+ when 'code'
1897
+ if @xmlpath == 'StartInstancesResponse/instancesSet/item/currentState'
1898
+ @instance[:aws_current_state_code] = @text.to_i
1899
+ elsif @xmlpath == 'StartInstancesResponse/instancesSet/item/previousState'
1900
+ @instance[:aws_prev_state_code] = @text.to_i
1901
+ end
1902
+ when 'name'
1903
+ if @xmlpath == 'StartInstancesResponse/instancesSet/item/currentState'
1904
+ @instance[:aws_current_state] = @text
1905
+ elsif @xmlpath == 'StartInstancesResponse/instancesSet/item/previousState'
1906
+ @instance[:aws_prev_state] = @text
1907
+ end
1908
+ when 'item' then
1909
+ @result << @instance
1910
+ end
1911
+ end
1912
+
1913
+ def reset
1914
+ @result = []
1915
+ end
1916
+ end
1917
+
1918
+
1919
+ #-----------------------------------------------------------------
1920
+ # PARSERS: Console
1921
+ #-----------------------------------------------------------------
1922
+
1923
+ class QEc2GetConsoleOutputParser < AwsParser #:nodoc:
1924
+ def tagend(name)
1925
+ case name
1926
+ when 'instanceId' then
1927
+ @result[:aws_instance_id] = @text
1928
+ when 'timestamp' then
1929
+ @result[:aws_timestamp] = @text
1930
+ @result[:timestamp] = (Time.parse(@text)).utc
1931
+ when 'output' then
1932
+ @result[:aws_output] = Base64.decode64(@text)
1933
+ end
1934
+ end
1935
+
1936
+ def reset
1937
+ @result = {}
1938
+ end
1939
+ end
1940
+
1941
+ #-----------------------------------------------------------------
1942
+ # Instances: Wondows related part
1943
+ #-----------------------------------------------------------------
1944
+ class QEc2DescribeBundleTasksParser < AwsParser #:nodoc:
1945
+ def tagstart(name, attributes)
1946
+ @bundle = {} if name == 'item'
1947
+ end
1948
+
1949
+ def tagend(name)
1950
+ case name
1951
+ # when 'requestId' then @bundle[:request_id] = @text
1952
+ when 'instanceId' then
1953
+ @bundle[:aws_instance_id] = @text
1954
+ when 'bundleId' then
1955
+ @bundle[:aws_id] = @text
1956
+ when 'bucket' then
1957
+ @bundle[:s3_bucket] = @text
1958
+ when 'prefix' then
1959
+ @bundle[:s3_prefix] = @text
1960
+ when 'startTime' then
1961
+ @bundle[:aws_start_time] = @text
1962
+ when 'updateTime' then
1963
+ @bundle[:aws_update_time] = @text
1964
+ when 'state' then
1965
+ @bundle[:aws_state] = @text
1966
+ when 'progress' then
1967
+ @bundle[:aws_progress] = @text
1968
+ when 'code' then
1969
+ @bundle[:aws_error_code] = @text
1970
+ when 'message' then
1971
+ @bundle[:aws_error_message] = @text
1972
+ when 'item' then
1973
+ @result << @bundle
1974
+ end
1975
+ end
1976
+
1977
+ def reset
1978
+ @result = []
1979
+ end
1980
+ end
1981
+
1982
+ class QEc2BundleInstanceParser < AwsParser #:nodoc:
1983
+ def tagend(name)
1984
+ case name
1985
+ # when 'requestId' then @result[:request_id] = @text
1986
+ when 'instanceId' then
1987
+ @result[:aws_instance_id] = @text
1988
+ when 'bundleId' then
1989
+ @result[:aws_id] = @text
1990
+ when 'bucket' then
1991
+ @result[:s3_bucket] = @text
1992
+ when 'prefix' then
1993
+ @result[:s3_prefix] = @text
1994
+ when 'startTime' then
1995
+ @result[:aws_start_time] = @text
1996
+ when 'updateTime' then
1997
+ @result[:aws_update_time] = @text
1998
+ when 'state' then
1999
+ @result[:aws_state] = @text
2000
+ when 'progress' then
2001
+ @result[:aws_progress] = @text
2002
+ when 'code' then
2003
+ @result[:aws_error_code] = @text
2004
+ when 'message' then
2005
+ @result[:aws_error_message] = @text
2006
+ end
2007
+ end
2008
+
2009
+ def reset
2010
+ @result = {}
2011
+ end
2012
+ end
2013
+
2014
+ #-----------------------------------------------------------------
2015
+ # PARSERS: Elastic IPs
2016
+ #-----------------------------------------------------------------
2017
+
2018
+ class QEc2AllocateAddressParser < AwsParser #:nodoc:
2019
+ def tagend(name)
2020
+ @result = @text if name == 'publicIp'
2021
+ end
2022
+ end
2023
+
2024
+ class QEc2DescribeAddressesParser < AwsParser #:nodoc:
2025
+ def tagstart(name, attributes)
2026
+ @address = {} if name == 'item'
2027
+ end
2028
+
2029
+ def tagend(name)
2030
+ case name
2031
+ when 'instanceId' then
2032
+ @address[:instance_id] = Aws::Utils.blank?(@text) ? nil : @text
2033
+ when 'publicIp' then
2034
+ @address[:public_ip] = @text
2035
+ when 'item' then
2036
+ @result << @address
2037
+ end
2038
+ end
2039
+
2040
+ def reset
2041
+ @result = []
2042
+ end
2043
+ end
2044
+
2045
+ #-----------------------------------------------------------------
2046
+ # PARSERS: AvailabilityZones
2047
+ #-----------------------------------------------------------------
2048
+
2049
+ class QEc2DescribeAvailabilityZonesParser < AwsParser #:nodoc:
2050
+ def tagstart(name, attributes)
2051
+ @zone = {} if name == 'item'
2052
+ end
2053
+
2054
+ def tagend(name)
2055
+ case name
2056
+ when 'regionName' then
2057
+ @zone[:region_name] = @text
2058
+ when 'zoneName' then
2059
+ @zone[:zone_name] = @text
2060
+ when 'zoneState' then
2061
+ @zone[:zone_state] = @text
2062
+ when 'item' then
2063
+ @result << @zone
2064
+ end
2065
+ end
2066
+
2067
+ def reset
2068
+ @result = []
2069
+ end
2070
+ end
2071
+
2072
+ #-----------------------------------------------------------------
2073
+ # PARSERS: Regions
2074
+ #-----------------------------------------------------------------
2075
+
2076
+ class QEc2DescribeRegionsParser < AwsParser #:nodoc:
2077
+ def tagend(name)
2078
+ @result << @text if name == 'regionName'
2079
+ end
2080
+
2081
+ def reset
2082
+ @result = []
2083
+ end
2084
+ end
2085
+
2086
+ #-----------------------------------------------------------------
2087
+ # PARSERS: EBS - Volumes
2088
+ #-----------------------------------------------------------------
2089
+
2090
+ class QEc2CreateVolumeParser < AwsParser #:nodoc:
2091
+ def tagend(name)
2092
+ case name
2093
+ when 'volumeId' then
2094
+ @result[:aws_id] = @text
2095
+ when 'status' then
2096
+ @result[:aws_status] = @text
2097
+ when 'createTime' then
2098
+ @result[:aws_created_at] = Time.parse(@text)
2099
+ when 'size' then
2100
+ @result[:aws_size] = @text.to_i ###
2101
+ when 'snapshotId' then
2102
+ @result[:snapshot_id] = Aws::Utils.blank?(@text) ? nil : @text ###
2103
+ when 'availabilityZone' then
2104
+ @result[:zone] = @text ###
2105
+ end
2106
+ end
2107
+
2108
+ def reset
2109
+ @result = {}
2110
+ end
2111
+ end
2112
+
2113
+ class QEc2AttachAndDetachVolumeParser < AwsParser #:nodoc:
2114
+ def tagend(name)
2115
+ case name
2116
+ when 'volumeId' then
2117
+ @result[:aws_id] = @text
2118
+ when 'instanceId' then
2119
+ @result[:aws_instance_id] = @text
2120
+ when 'device' then
2121
+ @result[:aws_device] = @text
2122
+ when 'status' then
2123
+ @result[:aws_attachment_status] = @text
2124
+ when 'attachTime' then
2125
+ @result[:aws_attached_at] = Time.parse(@text)
2126
+ end
2127
+ end
2128
+
2129
+ def reset
2130
+ @result = {}
2131
+ end
2132
+ end
2133
+
2134
+ class QEc2DescribeVolumesParser < AwsParser #:nodoc:
2135
+ def tagstart(name, attributes)
2136
+ case name
2137
+ when 'item'
2138
+ case @xmlpath
2139
+ when 'DescribeVolumesResponse/volumeSet' then
2140
+ @volume = {}
2141
+ end
2142
+ end
2143
+ end
2144
+
2145
+ def tagend(name)
2146
+ case name
2147
+ when 'volumeId'
2148
+ case @xmlpath
2149
+ when 'DescribeVolumesResponse/volumeSet/item' then
2150
+ @volume[:aws_id] = @text
2151
+ end
2152
+ when 'status'
2153
+ case @xmlpath
2154
+ when 'DescribeVolumesResponse/volumeSet/item' then
2155
+ @volume[:aws_status] = @text
2156
+ when 'DescribeVolumesResponse/volumeSet/item/attachmentSet/item' then
2157
+ @volume[:aws_attachment_status] = @text
2158
+ end
2159
+ when 'size' then
2160
+ @volume[:aws_size] = @text.to_i
2161
+ when 'createTime' then
2162
+ @volume[:aws_created_at] = Time.parse(@text)
2163
+ when 'instanceId' then
2164
+ @volume[:aws_instance_id] = @text
2165
+ when 'device' then
2166
+ @volume[:aws_device] = @text
2167
+ when 'attachTime' then
2168
+ @volume[:aws_attached_at] = Time.parse(@text)
2169
+ when 'snapshotId' then
2170
+ @volume[:snapshot_id] = Aws::Utils.blank?(@text) ? nil : @text
2171
+ when 'availabilityZone' then
2172
+ @volume[:zone] = @text
2173
+ when 'item'
2174
+ case @xmlpath
2175
+ when 'DescribeVolumesResponse/volumeSet' then
2176
+ @result << @volume
2177
+ end
2178
+ end
2179
+ end
2180
+
2181
+ def reset
2182
+ @result = []
2183
+ end
2184
+ end
2185
+
2186
+ #-----------------------------------------------------------------
2187
+ # PARSERS: EBS - Snapshots
2188
+ #-----------------------------------------------------------------
2189
+
2190
+ class QEc2DescribeSnapshotsParser < AwsParser #:nodoc:
2191
+
2192
+ def initialize (params={})
2193
+ @inside_tagset = false
2194
+ super(params)
2195
+ end
2196
+
2197
+ def tagstart(name, attributes)
2198
+ case name
2199
+ when 'tagSet'
2200
+ @inside_tagset = true
2201
+ when 'item'
2202
+ @snapshot = {} unless @inside_tagset
2203
+ end
2204
+ end
2205
+
2206
+ def tagend(name)
2207
+ case name
2208
+ when 'volumeId' then
2209
+ @snapshot[:aws_volume_id] = @text
2210
+ when 'snapshotId' then
2211
+ @snapshot[:aws_id] = @text
2212
+ when 'status' then
2213
+ @snapshot[:aws_status] = @text
2214
+ when 'startTime' then
2215
+ @snapshot[:aws_started_at] = Time.parse(@text)
2216
+ when 'progress' then
2217
+ @snapshot[:aws_progress] = @text
2218
+ when 'description' then
2219
+ @snapshot[:aws_description] = @text
2220
+ when 'ownerId' then
2221
+ @snapshot[:aws_owner] = @text
2222
+ when 'volumeSize' then
2223
+ @snapshot[:aws_volume_size] = @text.to_i
2224
+ when 'tagSet' then
2225
+ @inside_tagset = false
2226
+ when 'key' then
2227
+ @key = ('aws_tag_' + @text).to_sym
2228
+ when 'value' then
2229
+ @snapshot[@key] = @text
2230
+ when 'item' then
2231
+ @result << @snapshot unless @inside_tagset
2232
+ end
2233
+ end
2234
+
2235
+ def reset
2236
+ @result = []
2237
+ end
2238
+ end
2239
+
2240
+ class QEc2CreateSnapshotParser < AwsParser #:nodoc:
2241
+ def tagend(name)
2242
+ case name
2243
+ when 'volumeId' then
2244
+ @result[:aws_volume_id] = @text
2245
+ when 'snapshotId' then
2246
+ @result[:aws_id] = @text
2247
+ when 'status' then
2248
+ @result[:aws_status] = @text
2249
+ when 'startTime' then
2250
+ @result[:aws_started_at] = Time.parse(@text)
2251
+ when 'progress' then
2252
+ @result[:aws_progress] = @text
2253
+ end
2254
+ end
2255
+
2256
+ def reset
2257
+ @result = {}
2258
+ end
2259
+ end
2260
+
2261
+ #-----------------------------------------------------------------
2262
+ # PARSERS: Tags
2263
+ #-----------------------------------------------------------------
2264
+
2265
+ class QEc2DescribeTagsParser < AwsParser #:nodoc:
2266
+ def tagstart(name, attributes)
2267
+ @tag = {} if name == 'item'
2268
+ end
2269
+
2270
+ def tagend(name)
2271
+ case name
2272
+ when 'resourceId' then
2273
+ @tag[:aws_resource_id] = @text
2274
+ when 'resourceType' then
2275
+ @tag[:aws_resource_type] = @text
2276
+ when 'key' then
2277
+ @tag[:aws_key] = @text
2278
+ when 'value' then
2279
+ @tag[:aws_value] = @text
2280
+ when 'item' then
2281
+ @result << @tag
2282
+ end
2283
+ end
2284
+
2285
+ def reset
2286
+ @result = []
2287
+ end
2288
+ end
2289
+
2290
+ end
2291
+
2292
+ end
2293
+
2294
+