right_aws 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,55 +23,106 @@
23
23
 
24
24
  module RightAws
25
25
 
26
+ # = RightAWS::EC2 -- RightScale Amazon EC2 interface
27
+ # The RightAws::EC2 class provides a complete interface to Amazon's
28
+ # Elastic Compute Cloud service.
29
+ # For explanations of the semantics
30
+ # of each call, please refer to Amazon's documentation at
31
+ # http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=87
32
+ #
33
+ # Examples:
34
+ #
35
+ # Create an EC2 interface handle:
36
+ #
37
+ # @ec2 = RightAws::Ec2.new(aws_access_key_id,
38
+ # aws_secret_access_key)
39
+ # Create a new SSH key pair:
40
+ # @key = 'right_ec2_awesome_test_key'
41
+ # new_key = @ec2.create_key_pair(@key)
42
+ # keys = @ec2.describe_key_pairs
43
+ #
44
+ # Create a security group:
45
+ # @group = 'right_ec2_awesome_test_security_group'
46
+ # @ec2.create_security_group(@group,'My awesome test group')
47
+ # group = @ec2.describe_security_groups([@group])[0]
48
+ #
49
+ # Configure a security group:
50
+ # @ec2.authorize_security_group_named_ingress(@group, account_number, 'default')
51
+ # @ec2.authorize_security_group_IP_ingress(@group, 80,80,'udp','192.168.1.0/8')
52
+ #
53
+ # Describe the available images:
54
+ # images = @ec2.describe_images
55
+ #
56
+ # Launch an instance:
57
+ # ec2.run_instances('ami-9a9e7bf3', 1, 1, ['default'], @key, 'SomeImportantUserData', 'public')
58
+ #
59
+ #
60
+ # Describe running instances:
61
+ # @ec2.describe_instances
62
+ #
63
+ # Error handling: all operations raise an RightAws::AwsError in case
64
+ # of problems. Note that transient errors are automatically retried.
65
+
26
66
  class Ec2
27
67
 
28
68
  SIGNATURE_VERSION = "1"
29
- API_VERSION = "2007-01-19"
69
+ # Amazon EC2 API version being used
70
+ API_VERSION = "2007-03-01"
30
71
  DEFAULT_HOST = "ec2.amazonaws.com"
31
72
  DEFAULT_PROTOCOL = 'https'
32
73
  DEFAULT_PORT = 443
33
74
 
75
+ # Default addressing type (public=NAT, direct=no-NAT) used when launching instances.
34
76
  DEFAULT_ADDRESSING_TYPE = 'public'
35
77
  DNS_ADDRESSING_SET = ['public','direct']
36
78
 
37
- # A list if Amazons problems we can handle by AWSErrorHandler.
79
+ # A list of Amazon problems we can handle by AWSErrorHandler.
38
80
  @@amazon_problems = RightAws::AMAZON_PROBLEMS
39
81
 
40
- # Current aws_access_key_id
82
+ # Current aws_access_key_id
41
83
  attr_reader :aws_access_key_id
42
- # Last HTTP request object
84
+ # Last HTTP request object
43
85
  attr_reader :last_request
44
- # Last HTTP response object
86
+ # Last HTTP response object
45
87
  attr_reader :last_response
46
- # Last AWS errors list (used by AWSErrorHandler)
88
+ # Last AWS errors list (used by AWSErrorHandler)
47
89
  attr_accessor :last_errors
48
- # Last AWS request id (used by AWSErrorHandler)
90
+ # Last AWS request id (used by AWSErrorHandler)
49
91
  attr_accessor :last_request_id
50
- # Logger object
92
+ # Logger object, used by this class to generate log messages
51
93
  attr_accessor :logger
52
- # Initial params hash
94
+ # Option params passed into new
53
95
  attr_accessor :params
54
96
 
55
97
  @@bench_ec2 = Benchmark::Tms.new()
56
98
  @@bench_xml = Benchmark::Tms.new()
57
99
 
58
- # Benchmark::Tms instance for EC2 access benchmark.
100
+ # Benchmark::Tms instance that accumulates time spent in requests to EC2.
59
101
  def self.bench_ec2; @@bench_ec2; end
60
102
 
61
- # Benchmark::Tms instance for XML parsing benchmark.
103
+ # Benchmark::Tms instance that accumulates time spent in XML parsing.
62
104
  def self.bench_xml; @@bench_xml; end
63
105
 
64
- # Returns a list of Amazon service responses which are known as problems on Amazon side.
65
- # We have to re-request again if we've got any of them - probably the problem will disappear. By default returns the same value as AMAZON_PROBLEMS const.
106
+ # Returns a list of Amazon service responses which are known to be transient errors.
107
+ # By default returns the same value as AMAZON_PROBLEMS const. See AWSErrorHandler.
66
108
  def self.amazon_problems
67
109
  @@amazon_problems
68
110
  end
69
111
 
70
- # Sets a list of Amazon side problems.
112
+ # Sets the list of Amazon problems that are automatically retried. See AWSErrorHandler.
71
113
  def self.amazon_problems=(problems_list)
72
114
  @@amazon_problems = problems_list
73
115
  end
74
116
 
117
+ # Create a new handle to an EC2 account. All handles share the same per process or per thread
118
+ # HTTP connection to Amazon EC2. Each handle is for a specific account. The params have the
119
+ # following options:
120
+ # * <tt>:server</tt>: EC2 service host, default: DEFAULT_HOST
121
+ # * <tt>:port</tt>: EC2 service port, default: DEFAULT_PORT
122
+ # * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
123
+ # * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
124
+ # * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
125
+ #
75
126
  def initialize(aws_access_key_id, aws_secret_access_key, params={})
76
127
  @params = params
77
128
  raise AwsError.new("AWS access keys are required to operate on EC2") \
@@ -94,7 +145,7 @@ module RightAws
94
145
  AwsError::on_aws_exception(self, options)
95
146
  end
96
147
 
97
- # Return the +true+ if this RightEc2NativeQuery instance works in multi_thread state and +false+ otherwise.
148
+ # Return +true+ if this RightEc2NativeQuery instance works in multi_thread mode and +false+ otherwise.
98
149
  def multi_thread
99
150
  @params[:multi_thread]
100
151
  end
@@ -132,13 +183,7 @@ module RightAws
132
183
  @last_response = response
133
184
  if response.is_a?(Net::HTTPSuccess)
134
185
  @error_handler = nil
135
- @@bench_xml.add! do
136
- if parser.kind_of?(RightAWSParser)
137
- REXML::Document.parse_stream(response.body, parser)
138
- else
139
- parser.parse(response)
140
- end
141
- end
186
+ @@bench_xml.add! { parser.parse(response) }
142
187
  return parser.result
143
188
  else
144
189
  @error_handler = AWSErrorHandler.new(self, parser, @@amazon_problems) unless @error_handler
@@ -167,49 +212,66 @@ module RightAws
167
212
  #-----------------------------------------------------------------
168
213
 
169
214
  def ec2_describe_images(type, list) #:nodoc:
170
- link = generate_request("DescribeImages", hash_params(type,list))
171
- return request_info(link, QEc2DescribeImagesParser.new)
172
- end
173
-
174
- def ec2_describe_images_by_id( list) #:nodoc:
175
- return ec2_describe_images('ImageId', list)
176
- end
177
-
178
- def ec2_describe_images_by_owner(list) #:nodoc:
179
- return ec2_describe_images('Owner', list)
180
- end
181
-
182
- def ec2_describe_images_by_executable_by(list) #:nodoc:
183
- return ec2_describe_images('ExecutableBy', list)
215
+ link = generate_request("DescribeImages", hash_params(type,list.to_a))
216
+ images = request_info(link, QEc2DescribeImagesParser.new(:logger => @logger))
217
+ images.collect! do |image|
218
+ {:aws_id => image.imageId,
219
+ :aws_location => image.imageLocation,
220
+ :aws_owner => image.imageOwnerId,
221
+ :aws_state => image.imageState.downcase,
222
+ :aws_is_public => image.isPublic,
223
+ :aws_product_codes => image.productCodes}
224
+ end
225
+ images
226
+ rescue Exception
227
+ on_exception
184
228
  end
185
229
 
186
- # Retrieve a list of images. Returns array of hashes or an exception:
230
+ # Retrieve a list of images. Returns array of hashes describing the images or an exception:
187
231
  #
188
232
  # ec2.describe_images #=>
189
- # [{:aws_owner=>"522821470517", :aws_id=>"ami-e4b6538d", :aws_state=>"available",
190
- # :aws_location=>"marcins_cool_public_images/ubuntu-6.10.manifest.xml",:aws_is_public=>true},
191
- # ..., {...} ]
233
+ # [{:aws_owner => "522821470517",
234
+ # :aws_id => "ami-e4b6538d",
235
+ # :aws_state => "available",
236
+ # :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
237
+ # :aws_is_public => true},
238
+ # {...},
239
+ # {...} ]
192
240
  #
193
241
  # If +list+ param is set, then retrieve information about the listed images only:
194
242
  #
195
243
  # ec2.describe_images(['ami-e4b6538d']) #=>
196
- # [{:aws_owner=>"522821470517", :aws_id=>"ami-e4b6538d", :aws_state=>"available",
197
- # :aws_location=>"marcins_cool_public_images/ubuntu-6.10.manifest.xml",:aws_is_public=>true}]
244
+ # [{:aws_owner => "522821470517",
245
+ # :aws_id => "ami-e4b6538d",
246
+ # :aws_state => "available",
247
+ # :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
248
+ # :aws_is_public => true}]
198
249
  #
199
250
  def describe_images(list=[])
200
- images = list.nil? ? ec2_describe_images_by_executable_by(['self']) : ec2_describe_images_by_id(list)
201
- images.collect! do |image|
202
- {:aws_id => image.imageId,
203
- :aws_location => image.imageLocation,
204
- :aws_owner => image.imageOwnerId,
205
- :aws_state => image.imageState.downcase,
206
- :aws_is_public => image.isPublic }
207
- end
208
- images
209
- rescue Exception
210
- on_exception
251
+ ec2_describe_images('ImageId', list)
252
+ end
253
+
254
+ #
255
+ # Example:
256
+ #
257
+ # ec2.describe_images_by_owner('522821470517')
258
+ # ec2.describe_images_by_owner('self')
259
+ #
260
+ def describe_images_by_owner(list)
261
+ ec2_describe_images('Owner', list)
262
+ end
263
+
264
+ #
265
+ # Example:
266
+ #
267
+ # ec2.describe_images_by_executable_by('522821470517')
268
+ # ec2.describe_images_by_executable_by('self')
269
+ #
270
+ def describe_images_by_executable_by(list)
271
+ ec2_describe_images('ExecutableBy', list)
211
272
  end
212
-
273
+
274
+
213
275
  # Register new image at Amazon.
214
276
  # Returns new image id or an exception.
215
277
  #
@@ -218,7 +280,7 @@ module RightAws
218
280
  def register_image(image_location)
219
281
  link = generate_request("RegisterImage",
220
282
  'ImageLocation' => image_location.to_s)
221
- request_info(link, QEc2RegisterImageParser.new)
283
+ request_info(link, QEc2RegisterImageParser.new(:logger => @logger))
222
284
  rescue Exception
223
285
  on_exception
224
286
  end
@@ -230,13 +292,13 @@ module RightAws
230
292
  def deregister_image(image_id)
231
293
  link = generate_request("DeregisterImage",
232
294
  'ImageId' => image_id.to_s)
233
- request_info(link, RightBoolResponseParser.new)
295
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
234
296
  rescue Exception
235
297
  on_exception
236
298
  end
237
299
 
238
300
 
239
- # Describe image attributes. Currently, only 'launchPermission' is supported.
301
+ # Describe image attributes. Currently 'launchPermission' and 'productCodes' are supported.
240
302
  #
241
303
  # ec2.describe_image_attribute('ami-e444444d') #=> {:groups=>["all"], :users=>["000000000777"]}
242
304
  #
@@ -244,9 +306,15 @@ module RightAws
244
306
  link = generate_request("DescribeImageAttribute",
245
307
  'ImageId' => image_id,
246
308
  'Attribute' => attribute)
247
- image_attr = request_info(link, QEc2DescribeImageAttributeParser.new)
248
- { :users => image_attr.launchPermission.userIds,
249
- :groups => image_attr.launchPermission.groups }
309
+ image_attr = request_info(link, QEc2DescribeImageAttributeParser.new(:logger => @logger))
310
+ result = {}
311
+ if image_attr.launchPermission
312
+ result = { :users => image_attr.launchPermission.userIds,
313
+ :groups => image_attr.launchPermission.groups }
314
+ elsif image_attr.productCodes
315
+ result = { :aws_product_codes => image_attr.productCodes}
316
+ end
317
+ result
250
318
  rescue Exception
251
319
  on_exception
252
320
  end
@@ -259,37 +327,42 @@ module RightAws
259
327
  link = generate_request("ResetImageAttribute",
260
328
  'ImageId' => image_id,
261
329
  'Attribute' => attribute)
262
- request_info(link, RightBoolResponseParser.new)
330
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
263
331
  rescue Exception
264
332
  on_exception
265
333
  end
266
334
 
267
- # Users should prefer modify_image_launch_perm_add|remove_users|groups() instead of modify_image_attribute() because the signature of
268
- # modify_image_attribute() may change with EC2 service changes.
335
+ # Modify an image's attributes. It is recommended that you use
336
+ # modify_image_launch_perm_add_users, modify_image_launch_perm_remove_users, etc.
337
+ # instead of modify_image_attribute because the signature of
338
+ # modify_image_attribute may change with EC2 service changes.
269
339
  #
270
- # attribute : currently, only 'launchPermission' is supported.
271
- # operationType : currently, only 'add' & 'remove' are supported.
272
- # userGroup : currently, only 'all' is supported.
273
- def modify_image_attribute(image_id, attribute, operation_type, user_id=[], user_group=[])
274
- user_id = user_id.to_a
275
- user_group = user_group.to_a
276
- params = {'ImageId' => image_id,
277
- 'Attribute' => attribute,
278
- 'OperationType' => operation_type}
279
- params.update(hash_params('UserId', user_id)) unless user_id.empty?
280
- params.update(hash_params('UserGroup', user_group)) unless user_group.empty?
340
+ # attribute : currently, only 'launchPermission' is supported.
341
+ # operation_type : currently, only 'add' & 'remove' are supported.
342
+ # vars:
343
+ # :user_group : currently, only 'all' is supported.
344
+ # :user_id
345
+ # :product_code
346
+ def modify_image_attribute(image_id, attribute, operation_type = nil, vars = {})
347
+ params = {'ImageId' => image_id,
348
+ 'Attribute' => attribute}
349
+ params['OperationType'] = operation_type if operation_type
350
+ params.update(hash_params('UserId', vars[:user_id].to_a)) if vars[:user_id]
351
+ params.update(hash_params('UserGroup', vars[:user_group].to_a)) if vars[:user_group]
352
+ params.update(hash_params('ProductCode', vars[:product_code])) if vars[:product_code]
281
353
  link = generate_request("ModifyImageAttribute", params)
282
- request_info(link, RightBoolResponseParser.new)
354
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
283
355
  rescue Exception
284
356
  on_exception
285
357
  end
286
358
 
287
- # Grant image launch permissions for users. Parameter +userId+ is a list of users' AWS account ids. Returns +true+ or an exception.
359
+ # Grant image launch permissions to users.
360
+ # Parameter +userId+ is a list of user AWS account ids.
361
+ # Returns +true+ or an exception.
288
362
  #
289
363
  # ec2.modify_image_launch_perm_add_users('ami-e444444d',['000000000777','000000000778']) #=> true
290
- #
291
364
  def modify_image_launch_perm_add_users(image_id, user_id=[])
292
- modify_image_attribute(image_id, 'launchPermission', 'add', user_id, [])
365
+ modify_image_attribute(image_id, 'launchPermission', 'add', :user_id => user_id.to_a)
293
366
  end
294
367
 
295
368
  # Revokes image launch permissions for users. +userId+ is a list of users AWS accounts ids. Returns +true+ or an exception.
@@ -297,7 +370,7 @@ module RightAws
297
370
  # ec2.modify_image_launch_perm_remove_users('ami-e444444d',['000000000777','000000000778']) #=> true
298
371
  #
299
372
  def modify_image_launch_perm_remove_users(image_id, user_id=[])
300
- modify_image_attribute(image_id, 'launchPermission', 'remove', user_id, [])
373
+ modify_image_attribute(image_id, 'launchPermission', 'remove', :user_id => user_id.to_a)
301
374
  end
302
375
 
303
376
  # Add image launch permissions for users groups (currently only 'all' is supported, which gives public launch permissions).
@@ -306,7 +379,7 @@ module RightAws
306
379
  # ec2.modify_image_launch_perm_add_groups('ami-e444444d') #=> true
307
380
  #
308
381
  def modify_image_launch_perm_add_groups(image_id, userGroup=['all'])
309
- modify_image_attribute(image_id, 'launchPermission', 'add', [], userGroup)
382
+ modify_image_attribute(image_id, 'launchPermission', 'add', :user_group => userGroup.to_a)
310
383
  end
311
384
 
312
385
  # Remove image launch permissions for users groups (currently only 'all' is supported, which gives public launch permissions).
@@ -314,7 +387,15 @@ module RightAws
314
387
  # ec2.modify_image_launch_perm_remove_groups('ami-e444444d') #=> true
315
388
  #
316
389
  def modify_image_launch_perm_remove_groups(image_id, userGroup=['all'])
317
- modify_image_attribute(image_id, 'launchPermission', 'remove', [], userGroup)
390
+ modify_image_attribute(image_id, 'launchPermission', 'remove', :user_group => userGroup.to_a)
391
+ end
392
+
393
+ # Add product code to image
394
+ #
395
+ # ec2.modify_image_product_code('ami-e444444d','0ABCDEF') #=> true
396
+ #
397
+ def modify_image_product_code(image_id, productCode=[])
398
+ modify_image_attribute(image_id, 'productCodes', nil, :product_code => productCode.to_a)
318
399
  end
319
400
 
320
401
  def get_desc_instances(instances) # :nodoc:
@@ -334,7 +415,8 @@ module RightAws
334
415
  :aws_state => instance.instanceState.name,
335
416
  :ssh_key_name => instance.keyName,
336
417
  :aws_image_id => instance.imageId,
337
- :aws_reason => reason}
418
+ :aws_reason => reason,
419
+ :aws_product_codes => instance.productCodes}
338
420
  end
339
421
  end
340
422
  result
@@ -342,7 +424,8 @@ module RightAws
342
424
  on_exception
343
425
  end
344
426
 
345
- # Retrieve information about EC2 instances. If +list+ is omitted then returns the whole list.
427
+ # Retrieve information about EC2 instances. If +list+ is omitted then returns the
428
+ # list of all instances.
346
429
  #
347
430
  # ec2.describe_instances #=>
348
431
  # [{:aws_image_id => "ami-e444444d",
@@ -359,16 +442,27 @@ module RightAws
359
442
  # ..., {...}]
360
443
  #
361
444
  def describe_instances(list=[])
362
- link = generate_request("DescribeInstances", hash_params('InstanceId',list))
363
- instances = request_info(link, QEc2DescribeInstancesParser.new)
445
+ link = generate_request("DescribeInstances", hash_params('InstanceId',list.to_a))
446
+ instances = request_info(link, QEc2DescribeInstancesParser.new(:logger => @logger))
364
447
  get_desc_instances(instances)
365
448
  rescue Exception
366
449
  on_exception
367
450
  end
368
451
 
452
+ # Return the product code attached to instance or +nil+ otherwise.
453
+ #
454
+ # ec2.confirm_product_instance('ami-e444444d','12345678') #=> nil
455
+ # ec2.confirm_product_instance('ami-e444444d','00001111') #=> "000000000888"
456
+ #
457
+ def confirm_product_instance(instance, product_code)
458
+ link = generate_request("ConfirmProductInstance", { 'ProductCode' => product_code,
459
+ 'InstanceId' => instance })
460
+ request_info(link, QEc2ConfirmProductInstanceParser.new(:logger => @logger))
461
+ end
462
+
369
463
  # Launch new EC2 instances. Returns a list of launched instances or an exception.
370
464
  #
371
- # ec2.run_instances('ami-e444444d',1,1,['my_awesome_group'],'my_awesome_key', 'Woohoo!!!', public) #=>
465
+ # ec2.run_instances('ami-e444444d',1,1,['my_awesome_group'],'my_awesome_key', 'Woohoo!!!', 'public') #=>
372
466
  # [{:aws_image_id => "ami-e444444d",
373
467
  # :aws_reason => "",
374
468
  # :aws_state_code => "0",
@@ -382,9 +476,9 @@ module RightAws
382
476
  # :private_dns_name => ""}]
383
477
  #
384
478
  def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='', addressing_type=DEFAULT_ADDRESSING_TYPE)
385
- @logger.info("Launching instance of image #{image_id} for #{@aws_access_key_id}, key: #{key_name}, groups: #{(group_ids||[]).join(',')}")
479
+ @logger.info("Launching instance of image #{image_id} for #{@aws_access_key_id}, key: #{key_name}, groups: #{(group_ids||[]).to_a.join(',')}")
386
480
  # careful: keyName and securityGroups may be nil
387
- params = hash_params('SecurityGroup', group_ids)
481
+ params = hash_params('SecurityGroup', group_ids.to_a)
388
482
  params.update( {'ImageId' => image_id,
389
483
  'MinCount' => min_count.to_s,
390
484
  'MaxCount' => max_count.to_s,
@@ -394,13 +488,13 @@ module RightAws
394
488
  user_data.strip!
395
489
  # Do not use CGI::escape(encode64(...)) as it is done in Amazons EC2 library.
396
490
  # Amazon 169.254.169.254 does not like escaped symbols!
397
- # And it dont like "\n" inside of encoded string! Grrr....
491
+ # And it doesn't like "\n" inside of encoded string! Grrr....
398
492
  # Otherwise, some of UserData symbols will be lost...
399
- params['UserData'] = Base64.encode64(user_data).delete("\n") unless user_data.empty?
493
+ params['UserData'] = Base64.encode64(user_data).delete("\n") unless user_data.blank?
400
494
  end
401
495
  link = generate_request("RunInstances", params)
402
496
  #debugger
403
- instances = request_info(link, QEc2RunInstancesParser.new)
497
+ instances = request_info(link, QEc2RunInstancesParser.new(:logger => @logger))
404
498
  get_desc_instances(instances)
405
499
  rescue Exception
406
500
  on_exception
@@ -421,8 +515,8 @@ module RightAws
421
515
  # :aws_prev_state_code => 16}]
422
516
  #
423
517
  def terminate_instances(list=[])
424
- link = generate_request("TerminateInstances", hash_params('InstanceId',list))
425
- instances = request_info(link, QEc2TerminateInstancesParser.new)
518
+ link = generate_request("TerminateInstances", hash_params('InstanceId',list.to_a))
519
+ instances = request_info(link, QEc2TerminateInstancesParser.new(:logger => @logger))
426
520
  instances.collect! do |instance|
427
521
  { :aws_instance_id => instance.instanceId,
428
522
  :aws_shutdown_state => instance.shutdownState.name,
@@ -444,7 +538,7 @@ module RightAws
444
538
  # :aws_output => "Linux version 2.6.16-xenU (builder@patchbat.amazonsa) (gcc version 4.0.1 20050727 ..."
445
539
  def get_console_output(instance_id)
446
540
  link = generate_request("GetConsoleOutput", { 'InstanceId.1' => instance_id })
447
- result = request_info(link, QEc2GetConsoleOutputParser.new)
541
+ result = request_info(link, QEc2GetConsoleOutputParser.new(:logger => @logger))
448
542
  { :aws_instance_id => result.instanceId,
449
543
  :aws_timestamp => result.timestamp,
450
544
  :timestamp => (Time.parse(result.timestamp)).utc,
@@ -459,7 +553,7 @@ module RightAws
459
553
  #
460
554
  def reboot_instances(list)
461
555
  link = generate_request("RebootInstances", hash_params('InstanceId', list.to_a))
462
- request_info(link, RightBoolResponseParser.new)
556
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
463
557
  rescue Exception
464
558
  on_exception
465
559
  end
@@ -480,8 +574,8 @@ module RightAws
480
574
  # ..., {...}]
481
575
  #
482
576
  def describe_security_groups(list=[])
483
- link = generate_request("DescribeSecurityGroups", hash_params('GroupName',list))
484
- groups = request_info(link, QEc2DescribeSecurityGroupsParser.new)
577
+ link = generate_request("DescribeSecurityGroups", hash_params('GroupName',list.to_a))
578
+ groups = request_info(link, QEc2DescribeSecurityGroupsParser.new(:logger => @logger))
485
579
 
486
580
  result = []
487
581
  groups.each do |item|
@@ -527,7 +621,7 @@ module RightAws
527
621
  link = generate_request("CreateSecurityGroup",
528
622
  'GroupName' => name.to_s,
529
623
  'GroupDescription' => description.to_s)
530
- request_info(link, RightBoolResponseParser.new)
624
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
531
625
  rescue Exception
532
626
  on_exception
533
627
  end
@@ -539,21 +633,22 @@ module RightAws
539
633
  def delete_security_group(name)
540
634
  link = generate_request("DeleteSecurityGroup",
541
635
  'GroupName' => name.to_s)
542
- request_info(link, RightBoolResponseParser.new)
636
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
543
637
  rescue Exception
544
638
  on_exception
545
639
  end
546
640
 
547
- # Authorize named ingress for security group.
641
+ # Authorize named ingress for security group. Allows instances that are member of someone
642
+ # else's security group to open connections to instances in my group.
548
643
  #
549
- # ec2.authorize_security_group_named_ingress('my_awesome_group', aws_user_id, 'another_group_name') #=> true
644
+ # ec2.authorize_security_group_named_ingress('my_awesome_group', '7011-0219-8268', 'their_group_name') #=> true
550
645
  #
551
646
  def authorize_security_group_named_ingress(name, owner, group)
552
647
  link = generate_request("AuthorizeSecurityGroupIngress",
553
648
  'GroupName' => name.to_s,
554
649
  'SourceSecurityGroupName' => group.to_s,
555
650
  'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
556
- request_info(link, RightBoolResponseParser.new)
651
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
557
652
  rescue Exception
558
653
  on_exception
559
654
  end
@@ -567,12 +662,12 @@ module RightAws
567
662
  'GroupName' => name.to_s,
568
663
  'SourceSecurityGroupName' => group.to_s,
569
664
  'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
570
- request_info(link, RightBoolResponseParser.new)
665
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
571
666
  rescue Exception
572
667
  on_exception
573
668
  end
574
669
 
575
- # Add permission to a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp' ('tcp' is default).
670
+ # Add permission to a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp'.
576
671
  #
577
672
  # ec2.authorize_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
578
673
  # ec2.authorize_security_group_IP_ingress('my_awesome_group', -1, -1, 'icmp') #=> true
@@ -584,7 +679,7 @@ module RightAws
584
679
  'FromPort' => from_port.to_s,
585
680
  'ToPort' => to_port.to_s,
586
681
  'CidrIp' => cidr_ip.to_s)
587
- request_info(link, RightBoolResponseParser.new)
682
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
588
683
  rescue Exception
589
684
  on_exception
590
685
  end
@@ -600,12 +695,13 @@ module RightAws
600
695
  'FromPort' => from_port.to_s,
601
696
  'ToPort' => to_port.to_s,
602
697
  'CidrIp' => cidr_ip.to_s)
603
- request_info(link, RightBoolResponseParser.new)
698
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
604
699
  rescue Exception
605
700
  on_exception
606
701
  end
607
702
 
608
- # Retrieve a list of SSH keys. Returms an array of keys or an exception.
703
+ # Retrieve a list of SSH keys. Returns an array of keys or an exception. Each key is
704
+ # represented as a two-element hash.
609
705
  #
610
706
  # ec2.describe_key_pairs #=>
611
707
  # [{: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"},
@@ -613,8 +709,8 @@ module RightAws
613
709
  # ..., {...} ]
614
710
  #
615
711
  def describe_key_pairs(list=[])
616
- link = generate_request("DescribeKeyPairs", hash_params('KeyName',list))
617
- result = request_info(link, QEc2DescribeKeyPairParser.new)
712
+ link = generate_request("DescribeKeyPairs", hash_params('KeyName',list.to_a))
713
+ result = request_info(link, QEc2DescribeKeyPairParser.new(:logger => @logger))
618
714
  result.collect! do |key|
619
715
  {:aws_key_name => key.keyName,
620
716
  :aws_fingerprint => key.keyFingerprint }
@@ -624,7 +720,7 @@ module RightAws
624
720
  on_exception
625
721
  end
626
722
 
627
- # Create new SSH key. Returns a hash of key's data or an exception.
723
+ # Create new SSH key. Returns a hash of the key's data or an exception.
628
724
  #
629
725
  # ec2.create_key_pair('my_awesome_key') #=>
630
726
  # {:aws_key_name => "my_awesome_key",
@@ -634,7 +730,7 @@ module RightAws
634
730
  def create_key_pair(name)
635
731
  link = generate_request("CreateKeyPair",
636
732
  'KeyName' => name.to_s)
637
- key = request_info(link, QEc2CreateKeyPairParser.new)
733
+ key = request_info(link, QEc2CreateKeyPairParser.new(:logger => @logger))
638
734
  { :aws_key_name => key.keyName,
639
735
  :aws_fingerprint => key.keyFingerprint,
640
736
  :aws_material => key.keyMaterial}
@@ -642,24 +738,26 @@ module RightAws
642
738
  on_exception
643
739
  end
644
740
 
645
- # Delete key pair. Returns +true+ or an exception.
741
+ # Delete a key pair. Returns +true+ or an exception.
646
742
  #
647
743
  # ec2.delete_key_pair('my_awesome_key') #=> true
648
744
  #
649
745
  def delete_key_pair(name)
650
746
  link = generate_request("DeleteKeyPair",
651
747
  'KeyName' => name.to_s)
652
- request_info(link, RightBoolResponseParser.new)
748
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
653
749
  rescue Exception
654
750
  on_exception
655
751
  end
752
+
753
+ #- Internal stuff from here on down...
656
754
 
657
755
 
658
756
  #-----------------------------------------------------------------
659
757
  # PARSERS: Boolean Response Parser
660
758
  #-----------------------------------------------------------------
661
759
 
662
- class RightBoolResponseParser < RightAWSParser # :nodoc:
760
+ class RightBoolResponseParser < RightAWSParser
663
761
  def tagend(name)
664
762
  @result = @text=='true' ? true : false if name == 'return'
665
763
  end
@@ -669,16 +767,16 @@ module RightAws
669
767
  # PARSERS: Key Pair
670
768
  #-----------------------------------------------------------------
671
769
 
672
- class QEc2DescribeKeyPairType # :nodoc:
770
+ class QEc2DescribeKeyPairType
673
771
  attr_accessor :keyName
674
772
  attr_accessor :keyFingerprint
675
773
  end
676
774
 
677
- class QEc2CreateKeyPairType < QEc2DescribeKeyPairType # :nodoc:
775
+ class QEc2CreateKeyPairType < QEc2DescribeKeyPairType
678
776
  attr_accessor :keyMaterial
679
777
  end
680
778
 
681
- class QEc2DescribeKeyPairParser < RightAWSParser # :nodoc:
779
+ class QEc2DescribeKeyPairParser < RightAWSParser
682
780
  def tagstart(name, attributes)
683
781
  @item = QEc2DescribeKeyPairType.new if name == 'item'
684
782
  end
@@ -694,7 +792,7 @@ module RightAws
694
792
  end
695
793
  end
696
794
 
697
- class QEc2CreateKeyPairParser < RightAWSParser # :nodoc:
795
+ class QEc2CreateKeyPairParser < RightAWSParser
698
796
  def tagstart(name, attributes)
699
797
  @result = QEc2CreateKeyPairType.new if !@result
700
798
  end
@@ -711,12 +809,12 @@ module RightAws
711
809
  # PARSERS: Security Groups
712
810
  #-----------------------------------------------------------------
713
811
 
714
- class QEc2UserIdGroupPairType # :nodoc:
812
+ class QEc2UserIdGroupPairType
715
813
  attr_accessor :userId
716
814
  attr_accessor :groupName
717
815
  end
718
816
 
719
- class QEc2IpPermissionType # :nodoc:
817
+ class QEc2IpPermissionType
720
818
  attr_accessor :ipProtocol
721
819
  attr_accessor :fromPort
722
820
  attr_accessor :toPort
@@ -724,7 +822,7 @@ module RightAws
724
822
  attr_accessor :ipRanges
725
823
  end
726
824
 
727
- class QEc2SecurityGroupItemType # :nodoc:
825
+ class QEc2SecurityGroupItemType
728
826
  attr_accessor :groupName
729
827
  attr_accessor :groupDescription
730
828
  attr_accessor :ownerId
@@ -732,7 +830,7 @@ module RightAws
732
830
  end
733
831
 
734
832
 
735
- class QEc2DescribeSecurityGroupsParser < RightAWSParser # :nodoc:
833
+ class QEc2DescribeSecurityGroupsParser < RightAWSParser
736
834
  def tagstart(name, attributes)
737
835
  case name
738
836
  when 'item'
@@ -782,17 +880,20 @@ module RightAws
782
880
  # PARSERS: Images
783
881
  #-----------------------------------------------------------------
784
882
 
785
- class QEc2DescribeImagesResponseItemType # :nodoc:
883
+ class QEc2DescribeImagesResponseItemType
786
884
  attr_accessor :imageId
787
885
  attr_accessor :imageState
788
886
  attr_accessor :imageLocation
789
887
  attr_accessor :imageOwnerId
790
888
  attr_accessor :isPublic
889
+ attr_accessor :productCodes
791
890
  end
792
891
 
793
- class QEc2DescribeImagesParser < RightAWSParser # :nodoc:
892
+ class QEc2DescribeImagesParser < RightAWSParser
794
893
  def tagstart(name, attributes)
795
- @image = QEc2DescribeImagesResponseItemType.new if name == 'item'
894
+ if name == 'item' && @xmlpath[%r{.*/imagesSet$}]
895
+ @image = QEc2DescribeImagesResponseItemType.new
896
+ end
796
897
  end
797
898
  def tagend(name)
798
899
  case name
@@ -801,7 +902,8 @@ module RightAws
801
902
  when 'imageState' ; @image.imageState = @text
802
903
  when 'imageOwnerId' ; @image.imageOwnerId = @text
803
904
  when 'isPublic' ; @image.isPublic = @text == 'true' ? true : false
804
- when 'item' ; @result << @image
905
+ when 'productCode' ; (@image.productCodes ||= []) << @text
906
+ when 'item' ; @result << @image if @xmlpath[%r{.*/imagesSet$}]
805
907
  end
806
908
  end
807
909
  def reset
@@ -809,7 +911,7 @@ module RightAws
809
911
  end
810
912
  end
811
913
 
812
- class QEc2RegisterImageParser < RightAWSParser # :nodoc:
914
+ class QEc2RegisterImageParser < RightAWSParser
813
915
  def tagend(name)
814
916
  @result = @text if name == 'imageId'
815
917
  end
@@ -819,21 +921,22 @@ module RightAws
819
921
  # PARSERS: Image Attribute
820
922
  #-----------------------------------------------------------------
821
923
 
822
- class QEc2LaunchPermissionItemType # :nodoc:
924
+ class QEc2LaunchPermissionItemType
823
925
  attr_accessor :groups
824
926
  attr_accessor :userIds
825
927
  end
826
928
 
827
- class QEc2DescribeImageAttributeType # :nodoc:
929
+ class QEc2DescribeImageAttributeType
828
930
  attr_accessor :imageId
829
931
  attr_accessor :launchPermission
932
+ attr_accessor :productCodes
830
933
  end
831
934
 
832
- class QEc2DescribeImageAttributeParser < RightAWSParser # :nodoc:
935
+ class QEc2DescribeImageAttributeParser < RightAWSParser
833
936
  def tagstart(name, attributes)
834
937
  case name
835
938
  when 'launchPermission'
836
- @result.launchPermission = QEc2LaunchPermissionItemType.new
939
+ @result.launchPermission = QEc2LaunchPermissionItemType.new
837
940
  @result.launchPermission.groups = []
838
941
  @result.launchPermission.userIds = []
839
942
  end
@@ -848,6 +951,8 @@ module RightAws
848
951
  @result.launchPermission.groups << @text if @xmlpath == 'DescribeImageAttributeResponse/launchPermission/item'
849
952
  when 'userId'
850
953
  @result.launchPermission.userIds << @text if @xmlpath == 'DescribeImageAttributeResponse/launchPermission/item'
954
+ when 'productCode'
955
+ (@result.productCodes ||= []) << @text
851
956
  end
852
957
  end
853
958
  def reset
@@ -859,12 +964,12 @@ module RightAws
859
964
  # PARSERS: Instances
860
965
  #-----------------------------------------------------------------
861
966
 
862
- class QEc2InstanceStateType # :nodoc:
967
+ class QEc2InstanceStateType
863
968
  attr_accessor :code
864
969
  attr_accessor :name
865
970
  end
866
971
 
867
- class QEc2RunningInstancesItemType # :nodoc:
972
+ class QEc2RunningInstancesItemType
868
973
  attr_accessor :instanceId
869
974
  attr_accessor :imageId
870
975
  attr_accessor :instanceState
@@ -873,16 +978,17 @@ module RightAws
873
978
  attr_accessor :reason
874
979
  attr_accessor :keyName
875
980
  attr_accessor :amiLaunchIndex
981
+ attr_accessor :productCodes
876
982
  end
877
983
 
878
- class QEc2DescribeInstancesType # :nodoc:
984
+ class QEc2DescribeInstancesType
879
985
  attr_accessor :reservationId
880
986
  attr_accessor :ownerId
881
987
  attr_accessor :groupSet
882
988
  attr_accessor :instancesSet
883
989
  end
884
990
 
885
- class QEc2DescribeInstancesParser < RightAWSParser # :nodoc:
991
+ class QEc2DescribeInstancesParser < RightAWSParser
886
992
  def tagstart(name, attributes)
887
993
  case name
888
994
  when 'item'
@@ -922,6 +1028,7 @@ module RightAws
922
1028
  elsif @xmlpath=='DescribeInstancesResponse/reservationSet'
923
1029
  @result << @reservation
924
1030
  end
1031
+ when 'productCode' ; (@instance.productCodes ||= []) << @text
925
1032
  end
926
1033
  end
927
1034
  def reset
@@ -929,7 +1036,16 @@ module RightAws
929
1036
  end
930
1037
  end
931
1038
 
932
- class QEc2RunInstancesParser < RightAWSParser # :nodoc:
1039
+ class QEc2ConfirmProductInstanceParser < RightAWSParser
1040
+ def tagend(name)
1041
+ @result = @text if name == 'ownerId'
1042
+ end
1043
+ def reset
1044
+ @result = nil
1045
+ end
1046
+ end
1047
+
1048
+ class QEc2RunInstancesParser < RightAWSParser
933
1049
  def tagstart(name, attributes)
934
1050
  case name
935
1051
  when 'RunInstancesResponse'
@@ -966,6 +1082,7 @@ module RightAws
966
1082
  when 'item'
967
1083
  @reservation.instancesSet << @instance if @xmlpath == 'RunInstancesResponse/instancesSet'
968
1084
  when 'RunInstancesResponse'; @result << @reservation
1085
+ when 'productCode' ; (@instance.productCodes ||= []) << @text
969
1086
  end
970
1087
  end
971
1088
  def reset
@@ -973,13 +1090,13 @@ module RightAws
973
1090
  end
974
1091
  end
975
1092
 
976
- class QEc2TerminateInstancesResponseInfoType # :nodoc:
1093
+ class QEc2TerminateInstancesResponseInfoType
977
1094
  attr_accessor :instanceId
978
1095
  attr_accessor :shutdownState
979
1096
  attr_accessor :previousState
980
1097
  end
981
1098
 
982
- class QEc2TerminateInstancesParser < RightAWSParser # :nodoc:
1099
+ class QEc2TerminateInstancesParser < RightAWSParser
983
1100
  def tagstart(name, attributes)
984
1101
  if name == 'item'
985
1102
  @instance = QEc2TerminateInstancesResponseInfoType.new
@@ -1010,13 +1127,13 @@ module RightAws
1010
1127
  # PARSERS: Console
1011
1128
  #-----------------------------------------------------------------
1012
1129
 
1013
- class QEc2GetConsoleOutputResponseType # :nodoc:
1130
+ class QEc2GetConsoleOutputResponseType
1014
1131
  attr_accessor :instanceId
1015
1132
  attr_accessor :timestamp
1016
1133
  attr_accessor :output
1017
1134
  end
1018
1135
 
1019
- class QEc2GetConsoleOutputParser < RightAWSParser # :nodoc:
1136
+ class QEc2GetConsoleOutputParser < RightAWSParser
1020
1137
  def tagend(name)
1021
1138
  case name
1022
1139
  when 'instanceId' ; @result.instanceId = @text