ijin-right_aws 1.11.0

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