kerryb-amazon-ec2 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +265 -0
- data/LICENSE +66 -0
- data/README.rdoc +322 -0
- data/Rakefile +35 -0
- data/bin/ec2-gem-example.rb +67 -0
- data/bin/ec2sh +62 -0
- data/bin/setup.rb +25 -0
- data/lib/EC2/availability_zones.rb +41 -0
- data/lib/EC2/console.rb +44 -0
- data/lib/EC2/elastic_ips.rb +153 -0
- data/lib/EC2/exceptions.rb +147 -0
- data/lib/EC2/image_attributes.rb +166 -0
- data/lib/EC2/images.rb +134 -0
- data/lib/EC2/instances.rb +213 -0
- data/lib/EC2/keypairs.rb +94 -0
- data/lib/EC2/products.rb +43 -0
- data/lib/EC2/responses.rb +64 -0
- data/lib/EC2/security_groups.rb +232 -0
- data/lib/EC2/snapshots.rb +94 -0
- data/lib/EC2/volumes.rb +170 -0
- data/lib/EC2.rb +270 -0
- data/test/test_EC2.rb +68 -0
- data/test/test_EC2_availability_zones.rb +49 -0
- data/test/test_EC2_console.rb +54 -0
- data/test/test_EC2_elastic_ips.rb +144 -0
- data/test/test_EC2_image_attributes.rb +238 -0
- data/test/test_EC2_images.rb +197 -0
- data/test/test_EC2_instances.rb +336 -0
- data/test/test_EC2_keypairs.rb +123 -0
- data/test/test_EC2_products.rb +48 -0
- data/test/test_EC2_responses.rb +52 -0
- data/test/test_EC2_s3_xmlsimple.rb +80 -0
- data/test/test_EC2_security_groups.rb +205 -0
- data/test/test_EC2_snapshots.rb +83 -0
- data/test/test_EC2_volumes.rb +142 -0
- data/test/test_helper.rb +19 -0
- metadata +120 -0
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
|