ijin-right_aws 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/History.txt +239 -0
  2. data/Manifest.txt +46 -0
  3. data/README.txt +167 -0
  4. data/Rakefile +125 -0
  5. data/VERSION +1 -0
  6. data/lib/acf/right_acf_interface.rb +413 -0
  7. data/lib/acw/right_acw_interface.rb +249 -0
  8. data/lib/as/right_as_interface.rb +690 -0
  9. data/lib/awsbase/benchmark_fix.rb +39 -0
  10. data/lib/awsbase/right_awsbase.rb +931 -0
  11. data/lib/awsbase/support.rb +115 -0
  12. data/lib/ec2/right_ec2.rb +617 -0
  13. data/lib/ec2/right_ec2_ebs.rb +451 -0
  14. data/lib/ec2/right_ec2_images.rb +373 -0
  15. data/lib/ec2/right_ec2_instances.rb +760 -0
  16. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  17. data/lib/ec2/right_ec2_reserved_instances.rb +167 -0
  18. data/lib/ec2/right_ec2_vpc.rb +571 -0
  19. data/lib/elb/right_elb_interface.rb +407 -0
  20. data/lib/rds/right_rds_interface.rb +998 -0
  21. data/lib/right_aws.rb +79 -0
  22. data/lib/s3/right_s3.rb +1102 -0
  23. data/lib/s3/right_s3_interface.rb +1195 -0
  24. data/lib/sdb/active_sdb.rb +930 -0
  25. data/lib/sdb/right_sdb_interface.rb +672 -0
  26. data/lib/sqs/right_sqs.rb +388 -0
  27. data/lib/sqs/right_sqs_gen2.rb +343 -0
  28. data/lib/sqs/right_sqs_gen2_interface.rb +523 -0
  29. data/lib/sqs/right_sqs_interface.rb +594 -0
  30. data/test/acf/test_helper.rb +2 -0
  31. data/test/acf/test_right_acf.rb +146 -0
  32. data/test/awsbase/test_helper.rb +2 -0
  33. data/test/awsbase/test_right_awsbase.rb +12 -0
  34. data/test/ec2/test_helper.rb +2 -0
  35. data/test/ec2/test_right_ec2.rb +108 -0
  36. data/test/http_connection.rb +87 -0
  37. data/test/rds/test_helper.rb +2 -0
  38. data/test/rds/test_right_rds.rb +120 -0
  39. data/test/s3/test_helper.rb +2 -0
  40. data/test/s3/test_right_s3.rb +419 -0
  41. data/test/s3/test_right_s3_stubbed.rb +95 -0
  42. data/test/sdb/test_active_sdb.rb +299 -0
  43. data/test/sdb/test_helper.rb +3 -0
  44. data/test/sdb/test_right_sdb.rb +247 -0
  45. data/test/sqs/test_helper.rb +2 -0
  46. data/test/sqs/test_right_sqs.rb +291 -0
  47. data/test/sqs/test_right_sqs_gen2.rb +276 -0
  48. data/test/test_credentials.rb +37 -0
  49. data/test/ts_right_aws.rb +14 -0
  50. metadata +122 -0
@@ -0,0 +1,115 @@
1
+ # If ActiveSupport is loaded, then great - use it. But we don't
2
+ # want a dependency on it, so if it's not present, define the few
3
+ # extensions that we want to use...
4
+ unless defined? ActiveSupport::CoreExtensions
5
+ # These are ActiveSupport-;like extensions to do a few handy things in the gems
6
+ # Derived from ActiveSupport, so the AS copyright notice applies:
7
+ #
8
+ #
9
+ #
10
+ # Copyright (c) 2005 David Heinemeier Hansson
11
+ #
12
+ # Permission is hereby granted, free of charge, to any person obtaining
13
+ # a copy of this software and associated documentation files (the
14
+ # "Software"), to deal in the Software without restriction, including
15
+ # without limitation the rights to use, copy, modify, merge, publish,
16
+ # distribute, sublicense, and/or sell copies of the Software, and to
17
+ # permit persons to whom the Software is furnished to do so, subject to
18
+ # the following conditions:
19
+ #
20
+ # The above copyright notice and this permission notice shall be
21
+ # included in all copies or substantial portions of the Software.
22
+ #
23
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
+ #++
31
+ #
32
+ #
33
+ class String #:nodoc:
34
+
35
+ # Constantize tries to find a declared constant with the name specified
36
+ # in the string. It raises a NameError when the name is not in CamelCase
37
+ # or is not initialized.
38
+ #
39
+ # Examples
40
+ # "Module".constantize #=> Module
41
+ # "Class".constantize #=> Class
42
+ def constantize()
43
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
44
+ raise NameError, "#{self.inspect} is not a valid constant name!"
45
+ end
46
+
47
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
48
+ end
49
+
50
+ def camelize()
51
+ self.dup.split(/_/).map{ |word| word.capitalize }.join('')
52
+ end
53
+
54
+ end
55
+
56
+
57
+ class Object #:nodoc:
58
+ # "", " ", nil, [], and {} are blank
59
+ def blank?
60
+ if respond_to?(:empty?) && respond_to?(:strip)
61
+ empty? or strip.empty?
62
+ elsif respond_to?(:empty?)
63
+ empty?
64
+ else
65
+ !self
66
+ end
67
+ end
68
+ end
69
+
70
+ class NilClass #:nodoc:
71
+ def blank?
72
+ true
73
+ end
74
+ end
75
+
76
+ class FalseClass #:nodoc:
77
+ def blank?
78
+ true
79
+ end
80
+ end
81
+
82
+ class TrueClass #:nodoc:
83
+ def blank?
84
+ false
85
+ end
86
+ end
87
+
88
+ class Array #:nodoc:
89
+ alias_method :blank?, :empty?
90
+ end
91
+
92
+ class Hash #:nodoc:
93
+ alias_method :blank?, :empty?
94
+
95
+ # Return a new hash with all keys converted to symbols.
96
+ def symbolize_keys
97
+ inject({}) do |options, (key, value)|
98
+ options[key.to_sym] = value
99
+ options
100
+ end
101
+ end
102
+ end
103
+
104
+ class String #:nodoc:
105
+ def blank?
106
+ empty? || strip.empty?
107
+ end
108
+ end
109
+
110
+ class Numeric #:nodoc:
111
+ def blank?
112
+ false
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,617 @@
1
+ #
2
+ # Copyright (c) 2007-2009 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ module RightAws
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, as well as the associated EBS (Elastic Block
29
+ # Store).
30
+ # For explanations of the semantics
31
+ # of each call, please refer to Amazon's documentation at
32
+ # http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=87
33
+ #
34
+ # Examples:
35
+ #
36
+ # Create an EC2 interface handle:
37
+ #
38
+ # @ec2 = RightAws::Ec2.new(aws_access_key_id,
39
+ # aws_secret_access_key)
40
+ # Create a new SSH key pair:
41
+ # @key = 'right_ec2_awesome_test_key'
42
+ # new_key = @ec2.create_key_pair(@key)
43
+ # keys = @ec2.describe_key_pairs
44
+ #
45
+ # Create a security group:
46
+ # @group = 'right_ec2_awesome_test_security_group'
47
+ # @ec2.create_security_group(@group,'My awesome test group')
48
+ # group = @ec2.describe_security_groups([@group])[0]
49
+ #
50
+ # Configure a security group:
51
+ # @ec2.authorize_security_group_named_ingress(@group, account_number, 'default')
52
+ # @ec2.authorize_security_group_IP_ingress(@group, 80,80,'udp','192.168.1.0/8')
53
+ #
54
+ # Describe the available images:
55
+ # images = @ec2.describe_images
56
+ #
57
+ # Launch an instance:
58
+ # ec2.run_instances('ami-9a9e7bf3', 1, 1, ['default'], @key, 'SomeImportantUserData', 'public')
59
+ #
60
+ #
61
+ # Describe running instances:
62
+ # @ec2.describe_instances
63
+ #
64
+ # Error handling: all operations raise an RightAws::AwsError in case
65
+ # of problems. Note that transient errors are automatically retried.
66
+
67
+ class Ec2 < RightAwsBase
68
+ include RightAwsBaseInterface
69
+
70
+ # Amazon EC2 API version being used
71
+ API_VERSION = "2009-10-31"
72
+ DEFAULT_HOST = "ec2.amazonaws.com"
73
+ DEFAULT_PATH = '/'
74
+ DEFAULT_PROTOCOL = 'https'
75
+ DEFAULT_PORT = 443
76
+
77
+ # Default addressing type (public=NAT, direct=no-NAT) used when launching instances.
78
+ DEFAULT_ADDRESSING_TYPE = 'public'
79
+ DNS_ADDRESSING_SET = ['public','direct']
80
+
81
+ # Amazon EC2 Instance Types : http://www.amazon.com/b?ie=UTF8&node=370375011
82
+ # Default EC2 instance type (platform)
83
+ DEFAULT_INSTANCE_TYPE = 'm1.small'
84
+ INSTANCE_TYPES = ['m1.small','c1.medium','m1.large','m1.xlarge','c1.xlarge', 'm2.2xlarge', 'm2.4xlarge']
85
+
86
+ @@bench = AwsBenchmarkingBlock.new
87
+ def self.bench_xml
88
+ @@bench.xml
89
+ end
90
+ def self.bench_ec2
91
+ @@bench.service
92
+ end
93
+
94
+ # Current API version (sometimes we have to check it outside the GEM).
95
+ @@api = ENV['EC2_API_VERSION'] || API_VERSION
96
+ def self.api
97
+ @@api
98
+ end
99
+
100
+ # Create a new handle to an EC2 account. All handles share the same per process or per thread
101
+ # HTTP connection to Amazon EC2. Each handle is for a specific account. The params have the
102
+ # following options:
103
+ # * <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/'
104
+ # * <tt>:server</tt>: EC2 service host, default: DEFAULT_HOST
105
+ # * <tt>:region</tt>: EC2 region (North America by default)
106
+ # * <tt>:port</tt>: EC2 service port, default: DEFAULT_PORT
107
+ # * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
108
+ # * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
109
+ # * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
110
+ # * <tt>:signature_version</tt>: The signature version : '0','1' or '2'(default)
111
+ # * <tt>:cache</tt>: true/false: caching for: ec2_describe_images, describe_instances,
112
+ # describe_images_by_owner, describe_images_by_executable_by, describe_availability_zones,
113
+ # describe_security_groups, describe_key_pairs, describe_addresses,
114
+ # describe_volumes, describe_snapshots methods, default: false.
115
+ #
116
+ def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
117
+ init({ :name => 'EC2',
118
+ :default_host => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).host : DEFAULT_HOST,
119
+ :default_port => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).port : DEFAULT_PORT,
120
+ :default_service => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).path : DEFAULT_PATH,
121
+ :default_protocol => ENV['EC2_URL'] ? URI.parse(ENV['EC2_URL']).scheme : DEFAULT_PROTOCOL,
122
+ :default_api_version => @@api },
123
+ aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'] ,
124
+ aws_secret_access_key|| ENV['AWS_SECRET_ACCESS_KEY'],
125
+ params)
126
+ end
127
+
128
+ def generate_request(action, params={}) #:nodoc:
129
+ generate_request_impl(:get, action, params )
130
+ end
131
+
132
+ # Sends request to Amazon and parses the response
133
+ # Raises AwsError if any banana happened
134
+ def request_info(request, parser) #:nodoc:
135
+ request_info_impl(:ec2_connection, @@bench, request, parser)
136
+ end
137
+
138
+ #-----------------------------------------------------------------
139
+ # Security groups
140
+ #-----------------------------------------------------------------
141
+
142
+ # Retrieve Security Group information. If +list+ is omitted the returns the whole list of groups.
143
+ #
144
+ # ec2.describe_security_groups #=>
145
+ # [{:aws_group_name => "default-1",
146
+ # :aws_owner => "000000000888",
147
+ # :aws_description => "Default allowing SSH, HTTP, and HTTPS ingress",
148
+ # :aws_perms =>
149
+ # [{:owner => "000000000888", :group => "default"},
150
+ # {:owner => "000000000888", :group => "default-1"},
151
+ # {:to_port => "-1", :protocol => "icmp", :from_port => "-1", :cidr_ips => "0.0.0.0/0"},
152
+ # {:to_port => "22", :protocol => "tcp", :from_port => "22", :cidr_ips => "0.0.0.0/0"},
153
+ # {:to_port => "80", :protocol => "tcp", :from_port => "80", :cidr_ips => "0.0.0.0/0"},
154
+ # {:to_port => "443", :protocol => "tcp", :from_port => "443", :cidr_ips => "0.0.0.0/0"}]},
155
+ # ..., {...}]
156
+ #
157
+ def describe_security_groups(list=[])
158
+ link = generate_request("DescribeSecurityGroups", amazonize_list('GroupName',list.to_a))
159
+ request_cache_or_info( :describe_security_groups, link, QEc2DescribeSecurityGroupsParser, @@bench, list.blank?) do |parser|
160
+ result = []
161
+ parser.result.each do |item|
162
+ perms = []
163
+ item.ipPermissions.each do |perm|
164
+ perm.groups.each do |ngroup|
165
+ perms << {:group => ngroup.groupName,
166
+ :owner => ngroup.userId}
167
+ end
168
+ perm.ipRanges.each do |cidr_ip|
169
+ perms << {:from_port => perm.fromPort,
170
+ :to_port => perm.toPort,
171
+ :protocol => perm.ipProtocol,
172
+ :cidr_ips => cidr_ip}
173
+ end
174
+ end
175
+
176
+ # delete duplication
177
+ perms.each_index do |i|
178
+ (0...i).each do |j|
179
+ if perms[i] == perms[j] then perms[i] = nil; break; end
180
+ end
181
+ end
182
+ perms.compact!
183
+
184
+ result << {:aws_owner => item.ownerId,
185
+ :aws_group_name => item.groupName,
186
+ :aws_description => item.groupDescription,
187
+ :aws_perms => perms}
188
+
189
+ end
190
+ result
191
+ end
192
+ rescue Exception
193
+ on_exception
194
+ end
195
+
196
+ # Create new Security Group. Returns +true+ or an exception.
197
+ #
198
+ # ec2.create_security_group('default-1',"Default allowing SSH, HTTP, and HTTPS ingress") #=> true
199
+ #
200
+ def create_security_group(name, description)
201
+ # EC2 doesn't like an empty description...
202
+ description = " " if description.blank?
203
+ link = generate_request("CreateSecurityGroup",
204
+ 'GroupName' => name.to_s,
205
+ 'GroupDescription' => description.to_s)
206
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
207
+ rescue Exception
208
+ on_exception
209
+ end
210
+
211
+ # Remove Security Group. Returns +true+ or an exception.
212
+ #
213
+ # ec2.delete_security_group('default-1') #=> true
214
+ #
215
+ def delete_security_group(name)
216
+ link = generate_request("DeleteSecurityGroup",
217
+ 'GroupName' => name.to_s)
218
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
219
+ rescue Exception
220
+ on_exception
221
+ end
222
+
223
+ # Authorize named ingress for security group. Allows instances that are member of someone
224
+ # else's security group to open connections to instances in my group.
225
+ #
226
+ # ec2.authorize_security_group_named_ingress('my_awesome_group', '7011-0219-8268', 'their_group_name') #=> true
227
+ #
228
+ def authorize_security_group_named_ingress(name, owner, group)
229
+ link = generate_request("AuthorizeSecurityGroupIngress",
230
+ 'GroupName' => name.to_s,
231
+ 'SourceSecurityGroupName' => group.to_s,
232
+ 'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
233
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
234
+ rescue Exception
235
+ on_exception
236
+ end
237
+
238
+ # Revoke named ingress for security group.
239
+ #
240
+ # ec2.revoke_security_group_named_ingress('my_awesome_group', aws_user_id, 'another_group_name') #=> true
241
+ #
242
+ def revoke_security_group_named_ingress(name, owner, group)
243
+ link = generate_request("RevokeSecurityGroupIngress",
244
+ 'GroupName' => name.to_s,
245
+ 'SourceSecurityGroupName' => group.to_s,
246
+ 'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
247
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
248
+ rescue Exception
249
+ on_exception
250
+ end
251
+
252
+ # Add permission to a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp'.
253
+ #
254
+ # ec2.authorize_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
255
+ # ec2.authorize_security_group_IP_ingress('my_awesome_group', -1, -1, 'icmp') #=> true
256
+ #
257
+ def authorize_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
258
+ link = generate_request("AuthorizeSecurityGroupIngress",
259
+ 'GroupName' => name.to_s,
260
+ 'IpProtocol' => protocol.to_s,
261
+ 'FromPort' => from_port.to_s,
262
+ 'ToPort' => to_port.to_s,
263
+ 'CidrIp' => cidr_ip.to_s)
264
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
265
+ rescue Exception
266
+ on_exception
267
+ end
268
+
269
+ # Remove permission from a security group. Returns +true+ or an exception. +protocol+ is one of :'tcp'|'udp'|'icmp' ('tcp' is default).
270
+ #
271
+ # ec2.revoke_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
272
+ #
273
+ def revoke_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
274
+ link = generate_request("RevokeSecurityGroupIngress",
275
+ 'GroupName' => name.to_s,
276
+ 'IpProtocol' => protocol.to_s,
277
+ 'FromPort' => from_port.to_s,
278
+ 'ToPort' => to_port.to_s,
279
+ 'CidrIp' => cidr_ip.to_s)
280
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
281
+ rescue Exception
282
+ on_exception
283
+ end
284
+
285
+ #-----------------------------------------------------------------
286
+ # Keys
287
+ #-----------------------------------------------------------------
288
+
289
+ # Retrieve a list of SSH keys. Returns an array of keys or an exception. Each key is
290
+ # represented as a two-element hash.
291
+ #
292
+ # ec2.describe_key_pairs #=>
293
+ # [{: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"},
294
+ # {: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"},
295
+ # ..., {...} ]
296
+ #
297
+ def describe_key_pairs(list=[])
298
+ link = generate_request("DescribeKeyPairs", amazonize_list('KeyName',list.to_a))
299
+ request_cache_or_info :describe_key_pairs, link, QEc2DescribeKeyPairParser, @@bench, list.blank?
300
+ rescue Exception
301
+ on_exception
302
+ end
303
+
304
+ # Create new SSH key. Returns a hash of the key's data or an exception.
305
+ #
306
+ # ec2.create_key_pair('my_awesome_key') #=>
307
+ # {:aws_key_name => "my_awesome_key",
308
+ # :aws_fingerprint => "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03",
309
+ # :aws_material => "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAK...Q8MDrCbuQ=\n-----END RSA PRIVATE KEY-----"}
310
+ #
311
+ def create_key_pair(name)
312
+ link = generate_request("CreateKeyPair",
313
+ 'KeyName' => name.to_s)
314
+ request_info(link, QEc2CreateKeyPairParser.new(:logger => @logger))
315
+ rescue Exception
316
+ on_exception
317
+ end
318
+
319
+ # Delete a key pair. Returns +true+ or an exception.
320
+ #
321
+ # ec2.delete_key_pair('my_awesome_key') #=> true
322
+ #
323
+ def delete_key_pair(name)
324
+ link = generate_request("DeleteKeyPair",
325
+ 'KeyName' => name.to_s)
326
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
327
+ rescue Exception
328
+ on_exception
329
+ end
330
+
331
+ #-----------------------------------------------------------------
332
+ # Elastic IPs
333
+ #-----------------------------------------------------------------
334
+
335
+ # Acquire a new elastic IP address for use with your account.
336
+ # Returns allocated IP address or an exception.
337
+ #
338
+ # ec2.allocate_address #=> '75.101.154.140'
339
+ #
340
+ def allocate_address
341
+ link = generate_request("AllocateAddress")
342
+ request_info(link, QEc2AllocateAddressParser.new(:logger => @logger))
343
+ rescue Exception
344
+ on_exception
345
+ end
346
+
347
+ # Associate an elastic IP address with an instance.
348
+ # Returns +true+ or an exception.
349
+ #
350
+ # ec2.associate_address('i-d630cbbf', '75.101.154.140') #=> true
351
+ #
352
+ def associate_address(instance_id, public_ip)
353
+ link = generate_request("AssociateAddress",
354
+ "InstanceId" => instance_id.to_s,
355
+ "PublicIp" => public_ip.to_s)
356
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
357
+ rescue Exception
358
+ on_exception
359
+ end
360
+
361
+ # List elastic IP addresses assigned to your account.
362
+ # Returns an array of 2 keys (:instance_id and :public_ip) hashes:
363
+ #
364
+ # ec2.describe_addresses #=> [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.154.140"},
365
+ # {:instance_id=>nil, :public_ip=>"75.101.154.141"}]
366
+ #
367
+ # ec2.describe_addresses('75.101.154.140') #=> [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.154.140"}]
368
+ #
369
+ def describe_addresses(list=[])
370
+ link = generate_request("DescribeAddresses",
371
+ amazonize_list('PublicIp',list.to_a))
372
+ request_cache_or_info :describe_addresses, link, QEc2DescribeAddressesParser, @@bench, list.blank?
373
+ rescue Exception
374
+ on_exception
375
+ end
376
+
377
+ # Disassociate the specified elastic IP address from the instance to which it is assigned.
378
+ # Returns +true+ or an exception.
379
+ #
380
+ # ec2.disassociate_address('75.101.154.140') #=> true
381
+ #
382
+ def disassociate_address(public_ip)
383
+ link = generate_request("DisassociateAddress",
384
+ "PublicIp" => public_ip.to_s)
385
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
386
+ rescue Exception
387
+ on_exception
388
+ end
389
+
390
+ # Release an elastic IP address associated with your account.
391
+ # Returns +true+ or an exception.
392
+ #
393
+ # ec2.release_address('75.101.154.140') #=> true
394
+ #
395
+ def release_address(public_ip)
396
+ link = generate_request("ReleaseAddress",
397
+ "PublicIp" => public_ip.to_s)
398
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
399
+ rescue Exception
400
+ on_exception
401
+ end
402
+
403
+ #-----------------------------------------------------------------
404
+ # Availability zones
405
+ #-----------------------------------------------------------------
406
+
407
+ # Describes availability zones that are currently available to the account and their states.
408
+ # Returns an array of 2 keys (:zone_name and :zone_state) hashes:
409
+ #
410
+ # ec2.describe_availability_zones #=> [{:region_name=>"us-east-1",
411
+ # :zone_name=>"us-east-1a",
412
+ # :zone_state=>"available"}, ... ]
413
+ #
414
+ # ec2.describe_availability_zones('us-east-1c') #=> [{:region_name=>"us-east-1",
415
+ # :zone_state=>"available",
416
+ # :zone_name=>"us-east-1c"}]
417
+ #
418
+ def describe_availability_zones(list=[])
419
+ link = generate_request("DescribeAvailabilityZones",
420
+ amazonize_list('ZoneName',list.to_a))
421
+ request_cache_or_info :describe_availability_zones, link, QEc2DescribeAvailabilityZonesParser, @@bench, list.blank?
422
+ rescue Exception
423
+ on_exception
424
+ end
425
+
426
+ #-----------------------------------------------------------------
427
+ # Regions
428
+ #-----------------------------------------------------------------
429
+
430
+ # Describe regions.
431
+ #
432
+ # ec2.describe_regions #=> ["eu-west-1", "us-east-1"]
433
+ #
434
+ def describe_regions(list=[])
435
+ link = generate_request("DescribeRegions",
436
+ amazonize_list('RegionName',list.to_a))
437
+ request_cache_or_info :describe_regions, link, QEc2DescribeRegionsParser, @@bench, list.blank?
438
+ rescue Exception
439
+ on_exception
440
+ end
441
+
442
+ #-----------------------------------------------------------------
443
+ # PARSERS: Boolean Response Parser
444
+ #-----------------------------------------------------------------
445
+
446
+ class RightBoolResponseParser < RightAWSParser #:nodoc:
447
+ def tagend(name)
448
+ @result = @text=='true' ? true : false if name == 'return'
449
+ end
450
+ end
451
+
452
+ #-----------------------------------------------------------------
453
+ # PARSERS: Key Pair
454
+ #-----------------------------------------------------------------
455
+
456
+ class QEc2DescribeKeyPairParser < RightAWSParser #:nodoc:
457
+ def tagstart(name, attributes)
458
+ @item = {} if name == 'item'
459
+ end
460
+ def tagend(name)
461
+ case name
462
+ when 'keyName' then @item[:aws_key_name] = @text
463
+ when 'keyFingerprint' then @item[:aws_fingerprint] = @text
464
+ when 'item' then @result << @item
465
+ end
466
+ end
467
+ def reset
468
+ @result = [];
469
+ end
470
+ end
471
+
472
+ class QEc2CreateKeyPairParser < RightAWSParser #:nodoc:
473
+ def tagstart(name, attributes)
474
+ @result = {} if name == 'CreateKeyPairResponse'
475
+ end
476
+ def tagend(name)
477
+ case name
478
+ when 'keyName' then @result[:aws_key_name] = @text
479
+ when 'keyFingerprint' then @result[:aws_fingerprint] = @text
480
+ when 'keyMaterial' then @result[:aws_material] = @text
481
+ end
482
+ end
483
+ end
484
+
485
+ #-----------------------------------------------------------------
486
+ # PARSERS: Security Groups
487
+ #-----------------------------------------------------------------
488
+
489
+ class QEc2UserIdGroupPairType #:nodoc:
490
+ attr_accessor :userId
491
+ attr_accessor :groupName
492
+ end
493
+
494
+ class QEc2IpPermissionType #:nodoc:
495
+ attr_accessor :ipProtocol
496
+ attr_accessor :fromPort
497
+ attr_accessor :toPort
498
+ attr_accessor :groups
499
+ attr_accessor :ipRanges
500
+ end
501
+
502
+ class QEc2SecurityGroupItemType #:nodoc:
503
+ attr_accessor :groupName
504
+ attr_accessor :groupDescription
505
+ attr_accessor :ownerId
506
+ attr_accessor :ipPermissions
507
+ end
508
+
509
+ class QEc2DescribeSecurityGroupsParser < RightAWSParser #:nodoc:
510
+ def tagstart(name, attributes)
511
+ case name
512
+ when 'item'
513
+ if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo'
514
+ @group = QEc2SecurityGroupItemType.new
515
+ @group.ipPermissions = []
516
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions'
517
+ @perm = QEc2IpPermissionType.new
518
+ @perm.ipRanges = []
519
+ @perm.groups = []
520
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups'
521
+ @sgroup = QEc2UserIdGroupPairType.new
522
+ end
523
+ end
524
+ end
525
+ def tagend(name)
526
+ case name
527
+ when 'ownerId' then @group.ownerId = @text
528
+ when 'groupDescription' then @group.groupDescription = @text
529
+ when 'groupName'
530
+ if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item'
531
+ @group.groupName = @text
532
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups/item'
533
+ @sgroup.groupName = @text
534
+ end
535
+ when 'ipProtocol' then @perm.ipProtocol = @text
536
+ when 'fromPort' then @perm.fromPort = @text
537
+ when 'toPort' then @perm.toPort = @text
538
+ when 'userId' then @sgroup.userId = @text
539
+ when 'cidrIp' then @perm.ipRanges << @text
540
+ when 'item'
541
+ if @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions/item/groups'
542
+ @perm.groups << @sgroup
543
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo/item/ipPermissions'
544
+ @group.ipPermissions << @perm
545
+ elsif @xmlpath=='DescribeSecurityGroupsResponse/securityGroupInfo'
546
+ @result << @group
547
+ end
548
+ end
549
+ end
550
+ def reset
551
+ @result = []
552
+ end
553
+ end
554
+
555
+ #-----------------------------------------------------------------
556
+ # PARSERS: Elastic IPs
557
+ #-----------------------------------------------------------------
558
+
559
+ class QEc2AllocateAddressParser < RightAWSParser #:nodoc:
560
+ def tagend(name)
561
+ @result = @text if name == 'publicIp'
562
+ end
563
+ end
564
+
565
+ class QEc2DescribeAddressesParser < RightAWSParser #:nodoc:
566
+ def tagstart(name, attributes)
567
+ @address = {} if name == 'item'
568
+ end
569
+ def tagend(name)
570
+ case name
571
+ when 'instanceId' then @address[:instance_id] = @text.blank? ? nil : @text
572
+ when 'publicIp' then @address[:public_ip] = @text
573
+ when 'item' then @result << @address
574
+ end
575
+ end
576
+ def reset
577
+ @result = []
578
+ end
579
+ end
580
+
581
+ #-----------------------------------------------------------------
582
+ # PARSERS: AvailabilityZones
583
+ #-----------------------------------------------------------------
584
+
585
+ class QEc2DescribeAvailabilityZonesParser < RightAWSParser #:nodoc:
586
+ def tagstart(name, attributes)
587
+ @zone = {} if name == 'item'
588
+ end
589
+ def tagend(name)
590
+ case name
591
+ when 'regionName' then @zone[:region_name] = @text
592
+ when 'zoneName' then @zone[:zone_name] = @text
593
+ when 'zoneState' then @zone[:zone_state] = @text
594
+ when 'item' then @result << @zone
595
+ end
596
+ end
597
+ def reset
598
+ @result = []
599
+ end
600
+ end
601
+
602
+ #-----------------------------------------------------------------
603
+ # PARSERS: Regions
604
+ #-----------------------------------------------------------------
605
+
606
+ class QEc2DescribeRegionsParser < RightAWSParser #:nodoc:
607
+ def tagend(name)
608
+ @result << @text if name == 'regionName'
609
+ end
610
+ def reset
611
+ @result = []
612
+ end
613
+ end
614
+
615
+ end
616
+
617
+ end