kerryb-amazon-ec2 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/EC2.rb ADDED
@@ -0,0 +1,270 @@
1
+ #--
2
+ # Amazon Web Services EC2 Query API Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-ec2
5
+ # Author:: Glenn Rempe (mailto:glenn@rempe.us)
6
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://github.com/grempe/amazon-ec2/tree/master
9
+ #++
10
+
11
+ %w[ base64 cgi openssl digest/sha1 net/https rexml/document time ostruct ].each { |f| require f }
12
+
13
+ # Require any lib files that we have bundled with this Ruby Gem in the lib/EC2 directory.
14
+ # Parts of the EC2 module and Base class are broken out into separate
15
+ # files for maintainability and are organized by the functional groupings defined
16
+ # in the EC2 API developers guide.
17
+ Dir[File.join(File.dirname(__FILE__), 'EC2/**/*.rb')].sort.each { |lib| require lib }
18
+
19
+ module EC2
20
+
21
+ # Which host FQDN will we connect to for all API calls to AWS?
22
+ # If EC2_URL is defined in the users ENV we can use that. It is
23
+ # expected that this var is set with something like:
24
+ # export EC2_URL='https://ec2.amazonaws.com'
25
+ #
26
+ if ENV['EC2_URL']
27
+ EC2_URL = ENV['EC2_URL']
28
+ VALID_HOSTS = ['https://ec2.amazonaws.com', 'https://us-east-1.ec2.amazonaws.com', 'https://eu-west-1.ec2.amazonaws.com']
29
+ raise ArgumentError, "Invalid EC2_URL environment variable : #{EC2_URL}" unless VALID_HOSTS.include?(EC2_URL)
30
+ DEFAULT_HOST = URI.parse(EC2_URL).host
31
+ else
32
+ # default US host
33
+ DEFAULT_HOST = 'ec2.amazonaws.com'
34
+ end
35
+
36
+ # This is the version of the API as defined by Amazon Web Services
37
+ API_VERSION = '2008-12-01'
38
+
39
+ # Builds the canonical string for signing. This strips out all '&', '?', and '='
40
+ # from the query string to be signed.
41
+ # Note: The parameters in the path passed in must already be sorted in
42
+ # case-insensitive alphabetical order and must not be url encoded.
43
+ def EC2.canonical_string(params, host = DEFAULT_HOST, method="POST", base="/")
44
+ # Sort, and encode parameters into a canonical string.
45
+ sorted_params = params.sort {|x,y| x[0] <=> y[0]}
46
+ encoded_params = sorted_params.collect do |p|
47
+ encoded = (CGI::escape(p[0].to_s) +
48
+ "=" + CGI::escape(p[1].to_s))
49
+ # Ensure spaces are encoded as '%20', not '+'
50
+ encoded.gsub('+', '%20')
51
+ end
52
+ sigquery = encoded_params.join("&")
53
+
54
+ # Generate the request description string
55
+ req_desc =
56
+ method + "\n" +
57
+ host + "\n" +
58
+ base + "\n" +
59
+ sigquery
60
+
61
+ end
62
+
63
+ # Encodes the given string with the secret_access_key, by taking the
64
+ # hmac-sha1 sum, and then base64 encoding it. Optionally, it will also
65
+ # url encode the result of that to protect the string if it's going to
66
+ # be used as a query string parameter.
67
+ def EC2.encode(secret_access_key, str, urlencode=true)
68
+ digest = OpenSSL::Digest::Digest.new('sha1')
69
+ b64_hmac =
70
+ Base64.encode64(
71
+ OpenSSL::HMAC.digest(digest, secret_access_key, str)).gsub("\n","")
72
+
73
+ if urlencode
74
+ return CGI::escape(b64_hmac)
75
+ else
76
+ return b64_hmac
77
+ end
78
+ end
79
+
80
+
81
+ #Introduction:
82
+ #
83
+ # The library exposes one main interface class, 'EC2::Base'.
84
+ # This class provides all the methods for using the EC2 service
85
+ # including the handling of header signing and other security issues .
86
+ # This class uses Net::HTTP to interface with the EC2 Query API interface.
87
+ #
88
+ #Required Arguments:
89
+ #
90
+ # :access_key_id => String (default : "")
91
+ # :secret_access_key => String (default : "")
92
+ #
93
+ #Optional Arguments:
94
+ #
95
+ # :use_ssl => Boolean (default : true)
96
+ # :server => String (default : 'ec2.amazonaws.com')
97
+ # :proxy_server => String (default : nil)
98
+ #
99
+ class Base
100
+
101
+ attr_reader :use_ssl, :server, :proxy_server, :port
102
+
103
+ def initialize( options = {} )
104
+
105
+ options = { :access_key_id => "",
106
+ :secret_access_key => "",
107
+ :use_ssl => true,
108
+ :server => DEFAULT_HOST,
109
+ :proxy_server => nil
110
+ }.merge(options)
111
+
112
+ @server = options[:server]
113
+ @proxy_server = options[:proxy_server]
114
+ @use_ssl = options[:use_ssl]
115
+
116
+ raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
117
+ raise ArgumentError, "No :secret_access_key provided" if options[:secret_access_key].nil? || options[:secret_access_key].empty?
118
+ raise ArgumentError, "No :use_ssl value provided" if options[:use_ssl].nil?
119
+ raise ArgumentError, "Invalid :use_ssl value provided, only 'true' or 'false' allowed" unless options[:use_ssl] == true || options[:use_ssl] == false
120
+ raise ArgumentError, "No :server provided" if options[:server].nil? || options[:server].empty?
121
+
122
+ if options[:port]
123
+ # user-specified port
124
+ @port = options[:port]
125
+ elsif @use_ssl
126
+ # https
127
+ @port = 443
128
+ else
129
+ # http
130
+ @port = 80
131
+ end
132
+
133
+ @access_key_id = options[:access_key_id]
134
+ @secret_access_key = options[:secret_access_key]
135
+
136
+ # Use proxy server if defined
137
+ # Based on patch by Mathias Dalheimer. 20070217
138
+ proxy = @proxy_server ? URI.parse(@proxy_server) : OpenStruct.new
139
+ @http = Net::HTTP::Proxy( proxy.host,
140
+ proxy.port,
141
+ proxy.user,
142
+ proxy.password).new(options[:server], @port)
143
+
144
+ @http.use_ssl = @use_ssl
145
+
146
+ # Don't verify the SSL certificates. Avoids SSL Cert warning in log on every GET.
147
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
148
+
149
+ end
150
+
151
+
152
+ private
153
+
154
+ # pathlist is a utility method which takes a key string and and array as input.
155
+ # It converts the array into a Hash with the hash key being 'Key.n' where
156
+ # 'n' increments by 1 for each iteration. So if you pass in args
157
+ # ("ImageId", ["123", "456"]) you should get
158
+ # {"ImageId.1"=>"123", "ImageId.2"=>"456"} returned.
159
+ def pathlist(key, arr)
160
+ params = {}
161
+ arr.each_with_index do |value, i|
162
+ params["#{key}.#{i+1}"] = value
163
+ end
164
+ params
165
+ end
166
+
167
+
168
+ # Make the connection to AWS EC2 passing in our request. This is generally called from
169
+ # within a 'Response' class object or one of its sub-classes so the response is interpreted
170
+ # in its proper context. See lib/EC2/responses.rb
171
+ def make_request(action, params, data='')
172
+
173
+ @http.start do
174
+
175
+ # remove any keys that have nil or empty values
176
+ params.reject! { |key, value| value.nil? or value.empty?}
177
+
178
+ params.merge!( {"Action" => action,
179
+ "SignatureVersion" => "2",
180
+ "SignatureMethod" => 'HmacSHA1',
181
+ "AWSAccessKeyId" => @access_key_id,
182
+ "Version" => API_VERSION,
183
+ "Timestamp"=>Time.now.getutc.iso8601} )
184
+
185
+ sig = get_aws_auth_param(params, @secret_access_key)
186
+
187
+ query = params.sort.collect do |param|
188
+ CGI::escape(param[0]) + "=" + CGI::escape(param[1])
189
+ end.join("&") + "&Signature=" + sig
190
+
191
+ req = Net::HTTP::Post.new("/")
192
+ req.content_type = 'application/x-www-form-urlencoded'
193
+ req['User-Agent'] = "github-amazon-ec2-ruby-gem"
194
+
195
+ response = @http.request(req, query)
196
+
197
+ # Make a call to see if we need to throw an error based on the response given by EC2
198
+ # All error classes are defined in EC2/exceptions.rb
199
+ ec2_error?(response)
200
+
201
+ return response
202
+
203
+ end
204
+
205
+ end
206
+
207
+ # Set the Authorization header using AWS signed header authentication
208
+ def get_aws_auth_param(params, secret_access_key)
209
+ canonical_string = EC2.canonical_string(params)
210
+ encoded_canonical = EC2.encode(secret_access_key, canonical_string)
211
+ end
212
+
213
+ # allow us to have a one line call in each method which will do all of the work
214
+ # in making the actual request to AWS.
215
+ def response_generator( options = {} )
216
+
217
+ options = {
218
+ :action => "",
219
+ :params => {}
220
+ }.merge(options)
221
+
222
+ raise ArgumentError, ":action must be provided to response_generator" if options[:action].nil? || options[:action].empty?
223
+
224
+ http_response = make_request(options[:action], options[:params])
225
+ http_xml = http_response.body
226
+ return Response.parse(:xml => http_xml)
227
+
228
+ end
229
+
230
+ # Raises the appropriate error if the specified Net::HTTPResponse object
231
+ # contains an Amazon EC2 error; returns +false+ otherwise.
232
+ def ec2_error?(response)
233
+
234
+ # return false if we got a HTTP 200 code,
235
+ # otherwise there is some type of error (40x,50x) and
236
+ # we should try to raise an appropriate exception
237
+ # from one of our exception classes defined in
238
+ # exceptions.rb
239
+ return false if response.is_a?(Net::HTTPSuccess)
240
+
241
+ # parse the XML document so we can walk through it
242
+ doc = REXML::Document.new(response.body)
243
+
244
+ # Check that the Error element is in the place we would expect.
245
+ # and if not raise a generic error exception
246
+ unless doc.root.elements['Errors'].elements['Error'].name == 'Error'
247
+ raise Error, "Unexpected error format. response.body is: #{response.body}"
248
+ end
249
+
250
+ # An valid error response looks like this:
251
+ # <?xml version="1.0"?><Response><Errors><Error><Code>InvalidParameterCombination</Code><Message>Unknown parameter: foo</Message></Error></Errors><RequestID>291cef62-3e86-414b-900e-17246eccfae8</RequestID></Response>
252
+ # AWS EC2 throws some exception codes that look like Error.SubError. Since we can't name classes this way
253
+ # we need to strip out the '.' in the error 'Code' and we name the error exceptions with this
254
+ # non '.' name as well.
255
+ error_code = doc.root.elements['Errors'].elements['Error'].elements['Code'].text.gsub('.', '')
256
+ error_message = doc.root.elements['Errors'].elements['Error'].elements['Message'].text
257
+
258
+ # Raise one of our specific error classes if it exists.
259
+ # otherwise, throw a generic EC2 Error with a few details.
260
+ if EC2.const_defined?(error_code)
261
+ raise EC2.const_get(error_code), error_message
262
+ else
263
+ raise EC2::Error, error_message
264
+ end
265
+
266
+ end
267
+
268
+ end
269
+
270
+ end
data/test/test_EC2.rb ADDED
@@ -0,0 +1,68 @@
1
+ #--
2
+ # Amazon Web Services EC2 Query API Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-ec2
5
+ # Author:: Glenn Rempe (mailto:glenn@rempe.us)
6
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://github.com/grempe/amazon-ec2/tree/master
9
+ #++
10
+
11
+ require File.dirname(__FILE__) + '/test_helper.rb'
12
+
13
+ context "The EC2 method " do
14
+
15
+ setup do
16
+ end
17
+
18
+ specify "EC2::Base attribute readers should be available" do
19
+ @ec2 = EC2::Base.new( :access_key_id => "not a key",
20
+ :secret_access_key => "not a secret",
21
+ :use_ssl => true,
22
+ :server => "foo.example.com" )
23
+
24
+ @ec2.use_ssl.should.equal true
25
+ @ec2.port.should.equal 443
26
+ @ec2.server.should.equal "foo.example.com"
27
+ end
28
+
29
+ specify "EC2::Base should work with insecure connections as well" do
30
+ @ec2 = EC2::Base.new( :access_key_id => "not a key",
31
+ :secret_access_key => "not a secret",
32
+ :use_ssl => false,
33
+ :server => "foo.example.com" )
34
+
35
+ @ec2.use_ssl.should.equal false
36
+ @ec2.port.should.equal 80
37
+ @ec2.server.should.equal "foo.example.com"
38
+ end
39
+
40
+ specify "EC2::Base should allow specification of port" do
41
+ @ec2 = EC2::Base.new( :access_key_id => "not a key",
42
+ :secret_access_key => "not a secret",
43
+ :use_ssl => true,
44
+ :server => "foo.example.com",
45
+ :port => 8443 )
46
+
47
+ @ec2.use_ssl.should.equal true
48
+ @ec2.port.should.equal 8443
49
+ @ec2.server.should.equal "foo.example.com"
50
+ end
51
+
52
+ specify "EC2.canonical_string(path) should conform to Amazon's requirements " do
53
+ path = {"name1" => "value1", "name2" => "value2", "name3" => "value3"}
54
+ if ENV['EC2_URL'].nil? || ENV['EC2_URL'] == 'https://ec2.amazonaws.com'
55
+ EC2.canonical_string(path).should.equal "POST\nec2.amazonaws.com\n/\nname1=value1&name2=value2&name3=value3"
56
+ elsif ENV['EC2_URL'] == 'https://us-east-1.ec2.amazonaws.com'
57
+ EC2.canonical_string(path).should.equal "POST\nus-east-1.ec2.amazonaws.com\n/\nname1=value1&name2=value2&name3=value3"
58
+ elsif ENV['EC2_URL'] == 'https://eu-west-1.ec2.amazonaws.com'
59
+ EC2.canonical_string(path).should.equal "POST\neu-west-1.ec2.amazonaws.com\n/\nname1=value1&name2=value2&name3=value3"
60
+ end
61
+ end
62
+
63
+ specify "EC2.encode should return the expected string" do
64
+ EC2.encode("secretaccesskey", "foobar123", urlencode=true).should.equal "e3jeuDc3DIX2mW8cVqWiByj4j5g%3D"
65
+ EC2.encode("secretaccesskey", "foobar123", urlencode=false).should.equal "e3jeuDc3DIX2mW8cVqWiByj4j5g="
66
+ end
67
+
68
+ end
@@ -0,0 +1,49 @@
1
+ #--
2
+ # Amazon Web Services EC2 Query API Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-ec2
5
+ # Author:: Glenn Rempe (mailto:glenn@rempe.us)
6
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://github.com/grempe/amazon-ec2/tree/master
9
+ #++
10
+
11
+ require File.dirname(__FILE__) + '/test_helper.rb'
12
+
13
+ context "EC2 availability zones" do
14
+
15
+ setup do
16
+ @ec2 = EC2::Base.new( :access_key_id => "not a key", :secret_access_key => "not a secret" )
17
+
18
+ @describe_availability_zones_response_body = <<-RESPONSE
19
+ <DescribeAvailabilityZonesResponse xmlns="http://ec2.amazonaws.com/doc/2008-02-01/">
20
+ <availabilityZoneInfo>
21
+ <item>
22
+ <zoneName>us-east-1a</zoneName>
23
+ <zoneState>available</zoneState>
24
+ </item>
25
+ <item>
26
+ <zoneName>us-east-1b</zoneName>
27
+ <zoneState>available</zoneState>
28
+ </item>
29
+ </availabilityZoneInfo>
30
+ </DescribeAvailabilityZonesResponse>
31
+ RESPONSE
32
+
33
+ end
34
+
35
+ specify "should be able to be described with describe_availability_zones" do
36
+ @ec2.stubs(:make_request).with('DescribeAvailabilityZones', { "ZoneName.1" => "us-east-1a", "ZoneName.2" => "us-east-1b" }).
37
+ returns stub(:body => @describe_availability_zones_response_body, :is_a? => true)
38
+ @ec2.describe_availability_zones( :zone_name => ["us-east-1a", "us-east-1b"] ).should.be.an.instance_of Hash
39
+
40
+ response = @ec2.describe_availability_zones( :zone_name => ["us-east-1a", "us-east-1b"] )
41
+
42
+ response.availabilityZoneInfo.item[0].zoneName.should.equal "us-east-1a"
43
+ response.availabilityZoneInfo.item[0].zoneState.should.equal "available"
44
+
45
+ response.availabilityZoneInfo.item[1].zoneName.should.equal "us-east-1b"
46
+ response.availabilityZoneInfo.item[1].zoneState.should.equal "available"
47
+ end
48
+
49
+ end
@@ -0,0 +1,54 @@
1
+ #--
2
+ # Amazon Web Services EC2 Query API Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-ec2
5
+ # Author:: Glenn Rempe (mailto:glenn@rempe.us)
6
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://github.com/grempe/amazon-ec2/tree/master
9
+ #++
10
+
11
+ require File.dirname(__FILE__) + '/test_helper.rb'
12
+
13
+ context "The EC2 console " do
14
+
15
+ setup do
16
+ @ec2 = EC2::Base.new( :access_key_id => "not a key", :secret_access_key => "not a secret" )
17
+
18
+ @get_console_output_response_body = <<-RESPONSE
19
+ <GetConsoleOutputResponse xmlns="http://ec2.amazonaws.com/doc/2007-03-01">
20
+ <instanceId>i-28a64341</instanceId>
21
+ <timestamp>2007-01-03 15:00:00</timestamp>
22
+ <output>
23
+ YyB2ZXJzaW9uIDQuMC4xIDIwMDUwNzI3IChSZWQgSGF0IDQuMC4xLTUpKSAjMSBTTVAgVGh1IE9j
24
+ dCAyNiAwODo0MToyNiBTQVNUIDIwMDYKQklPUy1wcm92aWRlZCBwaHlzaWNhbCBSQU0gbWFwOgpY
25
+ ZW46IDAwMDAwMDAwMDAwMDAwMDAgLSAwMDAwMDAwMDZhNDAwMDAwICh1c2FibGUpCjk4ME1CIEhJ
26
+ R0hNRU0gYXZhaWxhYmxlLgo3MjdNQiBMT1dNRU0gYXZhaWxhYmxlLgpOWCAoRXhlY3V0ZSBEaXNh
27
+ YmxlKSBwcm90ZWN0aW9uOiBhY3RpdmUKSVJRIGxvY2t1cCBkZXRlY3Rpb24gZGlzYWJsZWQKQnVp
28
+ bHQgMSB6b25lbGlzdHMKS2VybmVsIGNvbW1hbmQgbGluZTogcm9vdD0vZGV2L3NkYTEgcm8gNApF
29
+ bmFibGluZyBmYXN0IEZQVSBzYXZlIGFuZCByZXN0b3JlLi4uIGRvbmUuCg==
30
+ </output>
31
+ </GetConsoleOutputResponse>
32
+ RESPONSE
33
+
34
+ end
35
+
36
+
37
+ specify "should return info written to a specific instances console" do
38
+ @ec2.stubs(:make_request).with('GetConsoleOutput', {"InstanceId"=>"i-2ea64347"}).
39
+ returns stub(:body => @get_console_output_response_body, :is_a? => true)
40
+ @ec2.get_console_output( :instance_id => "i-2ea64347" ).should.be.an.instance_of Hash
41
+ response = @ec2.get_console_output( :instance_id => "i-2ea64347" )
42
+ response.instanceId.should.equal "i-28a64341"
43
+ response.timestamp.should.equal "2007-01-03 15:00:00"
44
+ end
45
+
46
+
47
+ specify "method get_console_output should raise an exception when called without nil/empty string arguments" do
48
+ lambda { @ec2.get_console_output() }.should.raise(EC2::ArgumentError)
49
+ lambda { @ec2.get_console_output(:instance_id => nil) }.should.raise(EC2::ArgumentError)
50
+ lambda { @ec2.get_console_output(:instance_id => "") }.should.raise(EC2::ArgumentError)
51
+ end
52
+
53
+
54
+ end
@@ -0,0 +1,144 @@
1
+ #--
2
+ # Amazon Web Services EC2 Query API Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-ec2
5
+ # Author:: Glenn Rempe (mailto:glenn@rempe.us)
6
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://github.com/grempe/amazon-ec2/tree/master
9
+ #++
10
+
11
+ require File.dirname(__FILE__) + '/test_helper.rb'
12
+
13
+ context "EC2 elastic IP addresses " do
14
+
15
+ setup do
16
+ @ec2 = EC2::Base.new( :access_key_id => "not a key", :secret_access_key => "not a secret" )
17
+
18
+ @allocate_address_body = <<-RESPONSE
19
+ <AllocateAddressResponse xmlns="http://ec2.amazonaws.com/doc/2008-02-01">
20
+ <publicIp>67.202.55.255</publicIp>
21
+ </AllocateAddressResponse>
22
+ RESPONSE
23
+
24
+ @describe_addresses_response_body = <<-RESPONSE
25
+ <DescribeAddressesResponse xmlns="http://ec2.amazonaws.com/doc/2008-02-01">
26
+ <addressesSet>
27
+ <item>
28
+ <instanceId>i-28a64341</instanceId>
29
+ <publicIp>67.202.55.255</publicIp>
30
+ </item>
31
+ </addressesSet>
32
+ </DescribeAddressesResponse>
33
+ RESPONSE
34
+
35
+ @release_address_response_body = <<-RESPONSE
36
+ <ReleaseAddressResponse xmlns="http://ec2.amazonaws.com/doc/2008-02-01">
37
+ <return>true</return>
38
+ </ReleaseAddressResponse>
39
+ RESPONSE
40
+
41
+ @associate_address_response_body = <<-RESPONSE
42
+ <AssociateAddressResponse xmlns="http://ec2.amazonaws.com/doc/2008-02-01">
43
+ <return>true</return>
44
+ </AssociateAddressResponse>
45
+ RESPONSE
46
+
47
+ @disassociate_address_response_body = <<-RESPONSE
48
+ <DisassociateAddressResponse xmlns="http://ec2.amazonaws.com/doc/2008-02-01">
49
+ <return>true</return>
50
+ </DisassociateAddressResponse>
51
+ RESPONSE
52
+
53
+ end
54
+
55
+
56
+ specify "should be able to be created" do
57
+ @ec2.stubs(:make_request).with('AllocateAddress', {}).
58
+ returns stub(:body => @allocate_address_body, :is_a? => true)
59
+
60
+ @ec2.allocate_address.should.be.an.instance_of Hash
61
+
62
+ response = @ec2.allocate_address
63
+ response.publicIp.should.equal "67.202.55.255"
64
+ end
65
+
66
+
67
+ #specify "method create_keypair should reject bad arguments" do
68
+ # @ec2.stubs(:make_request).with('CreateKeyPair', {"KeyName"=>"example-key-name"}).
69
+ # returns stub(:body => @create_keypair_response_body, :is_a? => true)
70
+ #
71
+ # lambda { @ec2.create_keypair( :key_name => "example-key-name" ) }.should.not.raise(EC2::ArgumentError)
72
+ # lambda { @ec2.create_keypair() }.should.raise(EC2::ArgumentError)
73
+ # lambda { @ec2.create_keypair( :key_name => nil ) }.should.raise(EC2::ArgumentError)
74
+ # lambda { @ec2.create_keypair( :key_name => "" ) }.should.raise(EC2::ArgumentError)
75
+ #end
76
+
77
+
78
+ specify "should be able to be described with describe_addresses" do
79
+ @ec2.stubs(:make_request).with('DescribeAddresses', {"PublicIp.1"=>"67.202.55.255"}).
80
+ returns stub(:body => @describe_addresses_response_body, :is_a? => true)
81
+
82
+ @ec2.describe_addresses( :public_ip => "67.202.55.255" ).should.be.an.instance_of Hash
83
+
84
+ response = @ec2.describe_addresses( :public_ip => "67.202.55.255" )
85
+ response.addressesSet.item[0].instanceId.should.equal "i-28a64341"
86
+ response.addressesSet.item[0].publicIp.should.equal "67.202.55.255"
87
+ end
88
+
89
+
90
+ specify "should be able to be released with release_address" do
91
+ @ec2.stubs(:make_request).with('ReleaseAddress', {"PublicIp" => "67.202.55.255"}).
92
+ returns stub(:body => @release_address_response_body, :is_a? => true)
93
+
94
+ @ec2.release_address( :public_ip => "67.202.55.255" ).should.be.an.instance_of Hash
95
+
96
+ response = @ec2.release_address( :public_ip => "67.202.55.255" )
97
+ response.return.should.equal "true"
98
+ end
99
+
100
+
101
+ specify "should be able to be associated with an instance with associate_address" do
102
+ @ec2.stubs(:make_request).with('AssociateAddress', {"InstanceId" => "i-2ea64347", "PublicIp"=>"67.202.55.255"}).
103
+ returns stub(:body => @associate_address_response_body, :is_a? => true)
104
+
105
+ @ec2.associate_address( :instance_id => "i-2ea64347", :public_ip => "67.202.55.255" ).should.be.an.instance_of Hash
106
+
107
+ response = @ec2.associate_address( :instance_id => "i-2ea64347", :public_ip => "67.202.55.255" )
108
+ response.return.should.equal "true"
109
+ end
110
+
111
+
112
+ specify "method associate_address should reject bad arguments" do
113
+ @ec2.stubs(:make_request).with('AssociateAddress', {"InstanceId" => "i-2ea64347", "PublicIp"=>"67.202.55.255"}).
114
+ returns stub(:body => @associate_address_response_body, :is_a? => true)
115
+
116
+ lambda { @ec2.associate_address( :instance_id => "i-2ea64347", :public_ip => "67.202.55.255" ) }.should.not.raise(EC2::ArgumentError)
117
+ lambda { @ec2.associate_address() }.should.raise(EC2::ArgumentError)
118
+ lambda { @ec2.associate_address( :instance_id => nil ) }.should.raise(EC2::ArgumentError)
119
+ lambda { @ec2.associate_address( :public_ip => "" ) }.should.raise(EC2::ArgumentError)
120
+ end
121
+
122
+
123
+ specify "should be able to be disassociated with an instance with disassociate_address" do
124
+ @ec2.stubs(:make_request).with('DisassociateAddress', {'PublicIp' => '67.202.55.255'}).
125
+ returns stub(:body => @disassociate_address_response_body, :is_a? => true)
126
+
127
+ @ec2.disassociate_address( :public_ip => "67.202.55.255" ).should.be.an.instance_of Hash
128
+
129
+ response = @ec2.disassociate_address( :public_ip => "67.202.55.255" )
130
+ response.return.should.equal "true"
131
+ end
132
+
133
+
134
+ specify "method disassociate_address should reject bad arguments" do
135
+ @ec2.stubs(:make_request).with('DisassociateAddress', {'PublicIp' => '67.202.55.255'}).
136
+ returns stub(:body => @disassociate_address_response_body, :is_a? => true)
137
+
138
+ lambda { @ec2.disassociate_address( :public_ip => "67.202.55.255" ) }.should.not.raise(EC2::ArgumentError)
139
+ lambda { @ec2.disassociate_address() }.should.raise(EC2::ArgumentError)
140
+ lambda { @ec2.disassociate_address( :public_ip => "" ) }.should.raise(EC2::ArgumentError)
141
+ end
142
+
143
+
144
+ end