grempe-amazon-ec2 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/History.txt +230 -0
  2. data/License.txt +66 -0
  3. data/Manifest.txt +46 -0
  4. data/README.txt +154 -0
  5. data/Rakefile +4 -0
  6. data/bin/ec2-gem-example.rb +61 -0
  7. data/bin/ec2sh +73 -0
  8. data/bin/setup.rb +19 -0
  9. data/config/hoe.rb +76 -0
  10. data/config/requirements.rb +17 -0
  11. data/lib/EC2.rb +254 -0
  12. data/lib/EC2/console.rb +44 -0
  13. data/lib/EC2/elastic_ips.rb +153 -0
  14. data/lib/EC2/exceptions.rb +136 -0
  15. data/lib/EC2/image_attributes.rb +166 -0
  16. data/lib/EC2/images.rb +134 -0
  17. data/lib/EC2/instances.rb +206 -0
  18. data/lib/EC2/keypairs.rb +94 -0
  19. data/lib/EC2/products.rb +43 -0
  20. data/lib/EC2/responses.rb +175 -0
  21. data/lib/EC2/security_groups.rb +232 -0
  22. data/lib/EC2/version.rb +18 -0
  23. data/script/destroy +14 -0
  24. data/script/generate +14 -0
  25. data/script/txt2html +74 -0
  26. data/setup.rb +1585 -0
  27. data/tasks/deployment.rake +27 -0
  28. data/tasks/environment.rake +7 -0
  29. data/tasks/website.rake +17 -0
  30. data/test/test_EC2.rb +52 -0
  31. data/test/test_EC2_console.rb +54 -0
  32. data/test/test_EC2_elastic_ips.rb +144 -0
  33. data/test/test_EC2_image_attributes.rb +238 -0
  34. data/test/test_EC2_images.rb +197 -0
  35. data/test/test_EC2_instances.rb +325 -0
  36. data/test/test_EC2_keypairs.rb +123 -0
  37. data/test/test_EC2_products.rb +48 -0
  38. data/test/test_EC2_responses.rb +102 -0
  39. data/test/test_EC2_security_groups.rb +205 -0
  40. data/test/test_EC2_version.rb +44 -0
  41. data/test/test_helper.rb +20 -0
  42. data/website/index.txt +427 -0
  43. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  44. data/website/stylesheets/screen.css +138 -0
  45. data/website/template.rhtml +55 -0
  46. metadata +174 -0
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Amazon Web Services EC2 Query API Ruby library
4
+ #
5
+ # Ruby Gem Name:: amazon-ec2
6
+ # Author:: Glenn Rempe (mailto:grempe@rubyforge.org)
7
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
8
+ # License:: Distributes under the same terms as Ruby
9
+ # Home:: http://amazon-ec2.rubyforge.org
10
+ #++
11
+
12
+ require 'rubygems'
13
+ require File.dirname(__FILE__) + '/../lib/EC2'
14
+
15
+ # pull these from the local shell environment variables set in ~/.bash_login
16
+ # or using appropriate methods specific to your login shell.
17
+ #
18
+ # e.g. in ~/.bash_login
19
+ #
20
+ # # For amazon-ec2 and amazon s3 ruby gems
21
+ # export AMAZON_ACCESS_KEY_ID="FOO"
22
+ # export AMAZON_SECRET_ACCESS_KEY="BAR"
23
+
24
+ ACCESS_KEY_ID = ENV['AMAZON_ACCESS_KEY_ID']
25
+ SECRET_ACCESS_KEY = ENV['AMAZON_SECRET_ACCESS_KEY']
26
+
27
+ if ACCESS_KEY_ID.nil? || ACCESS_KEY_ID.empty?
28
+ puts "Error : You must add the shell environment variables AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY before calling #{$0}!"
29
+ exit
30
+ end
31
+
32
+ ec2 = EC2::Base.new( :access_key_id => ACCESS_KEY_ID, :secret_access_key => SECRET_ACCESS_KEY )
33
+
34
+ puts "----- GEM Version -----"
35
+ puts EC2::VERSION::STRING
36
+
37
+ puts "----- ec2.methods.sort -----"
38
+ p ec2.methods.sort
39
+
40
+ puts "----- listing images owned by 'amazon' -----"
41
+ ec2.describe_images(:owner_id => "amazon").imagesSet.item.each do |image|
42
+ image.members.each do |member|
43
+ puts "#{member} => #{image[member]}"
44
+ end
45
+ end
46
+
47
+ puts "----- listing all running instances -----"
48
+ puts ec2.describe_instances()
49
+
50
+ puts "----- creating a security group -----"
51
+ puts ec2.create_security_group(:group_name => "ec2-example-rb-test-group", :group_description => "ec-example.rb test group description.")
52
+
53
+ puts "----- listing security groups -----"
54
+ puts ec2.describe_security_groups()
55
+
56
+ puts "----- deleting a security group -----"
57
+ puts ec2.delete_security_group(:group_name => "ec2-example-rb-test-group")
58
+
59
+ puts "----- listing my keypairs (verbose mode) -----"
60
+ puts ec2.describe_keypairs()
61
+
data/bin/ec2sh ADDED
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Amazon Web Services EC2 Query API Ruby library
4
+ #
5
+ # Ruby Gem Name:: amazon-ec2
6
+ # Author:: Glenn Rempe (mailto:grempe@rubyforge.org)
7
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
8
+ # License:: Distributes under the same terms as Ruby
9
+ # Home:: http://amazon-ec2.rubyforge.org
10
+ #++
11
+
12
+ # CREDITS : Credit for this bit of shameful ripoff coolness
13
+ # goes to Marcel Molina and his AWS::S3 gem. Thanks!
14
+
15
+ # Usage : running this starts up an irb session and
16
+ # sets up the connection to EC2 as a class variable called
17
+ # '@ec2'. So just do something like the following on the
18
+ # shell command line:
19
+
20
+ # macbook-pro:~ glenn$ ec2sh
21
+ # >> @ec2.describe_images
22
+ # => [#<EC2::Item image_location...
23
+
24
+ ec2_lib = File.dirname(__FILE__) + '/../lib/EC2'
25
+ setup = File.dirname(__FILE__) + '/setup'
26
+ irb_name = RUBY_PLATFORM =~ /mswin32/ ? 'irb.bat' : 'irb'
27
+
28
+ if ( ENV['AMAZON_ACCESS_KEY_ID'] && ENV['AMAZON_SECRET_ACCESS_KEY'] )
29
+
30
+ welcome_message = <<-MESSAGE
31
+
32
+ 'ec2sh' usage :
33
+ This is an interactive 'irb' command shell that allows you to use all
34
+ commands available to the amazon-ec2 gem. You'll find this to be a
35
+ great tool to help you debug issues and practice running commands
36
+ against the live EC2 servers prior to putting them in your code.
37
+
38
+ The EC2 connection is wired to the class instance '@ec2'. Make method calls
39
+ on this to execute commands on EC2. Adding a #to_s
40
+ at the end of any command should give you a full String representation of the
41
+ response. The #xml data is available for each response
42
+ which allows you to view the full and complete XML response returned by
43
+ EC2 without any parsing applied. This is useful for viewing the
44
+ hierarchy of an entire response in a friendly way (if XML is friendly
45
+ to you!). Understanding the hierarchy of the XML response is critical
46
+ to making effective use of this library.
47
+
48
+ Examples to try:
49
+
50
+ returns : all ec2 public methods
51
+ >> @ec2.methods.sort
52
+
53
+ returns : a string representation of ALL images
54
+ >> @ec2.describe_images.to_s
55
+
56
+ returns : an Array of EC2::Response objects, each an EC2 image and its data
57
+ >> @ec2.describe_images.imagesSet.item
58
+ >> @ec2.describe_images.imagesSet.item[0] (an OpenStruct of a single item in that array)
59
+ >> @ec2.describe_images.imagesSet.item[0].to_s (a String representation of that OpenStruct item)
60
+
61
+ returns : an XML representation of all images
62
+ >> puts @ec2.describe_images.xml
63
+
64
+ returns : an XML representation of all images owned by Amazon
65
+ >> puts @ec2.describe_images(:owner_id => 'amazon').xml
66
+
67
+ MESSAGE
68
+
69
+ puts welcome_message
70
+ exec "#{irb_name} -r #{ec2_lib} -r #{setup} --simple-prompt"
71
+ else
72
+ puts "You must define AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY as shell environment variables before running #{$0}!"
73
+ end
data/bin/setup.rb ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Amazon Web Services EC2 Query API Ruby library
4
+ #
5
+ # Ruby Gem Name:: amazon-ec2
6
+ # Author:: Glenn Rempe (mailto:grempe@rubyforge.org)
7
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
8
+ # License:: Distributes under the same terms as Ruby
9
+ # Home:: http://amazon-ec2.rubyforge.org
10
+ #++
11
+
12
+ if ENV['AMAZON_ACCESS_KEY_ID'] && ENV['AMAZON_SECRET_ACCESS_KEY']
13
+ @ec2 = EC2::Base.new(
14
+ :access_key_id => ENV['AMAZON_ACCESS_KEY_ID'],
15
+ :secret_access_key => ENV['AMAZON_SECRET_ACCESS_KEY']
16
+ )
17
+ end
18
+
19
+ include EC2
data/config/hoe.rb ADDED
@@ -0,0 +1,76 @@
1
+ require 'EC2/version'
2
+
3
+ AUTHOR = 'Glenn Rempe' # can also be an array of Authors
4
+ EMAIL = "grempe@rubyforge.org"
5
+ DESCRIPTION = "An interface library that allows Ruby or Ruby on Rails applications to easily connect to the HTTP 'Query API' for the Amazon Web Services Elastic Compute Cloud (EC2) and manipulate server instances."
6
+ GEM_NAME = 'amazon-ec2' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'amazon-ec2' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "grempe"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = EC2::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'amazon-ec2 documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README.txt",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.author = AUTHOR
52
+ p.description = DESCRIPTION
53
+ p.email = EMAIL
54
+ p.summary = DESCRIPTION
55
+ p.url = HOMEPATH
56
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
57
+ p.test_globs = ["test/**/test_*.rb"]
58
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
59
+
60
+ # == Optional
61
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\\n\\n")
62
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
63
+ p.extra_deps = [['xml-simple', '>= 1.0.11'], ['mocha', '>= 0.4.0'], ['test-spec', '>= 0.3.0'], ['rcov', '>= 0.8.0.2'], ['syntax', '>= 1.0.0'], ['RedCloth', '>= 3.0.4']]
64
+
65
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
66
+ p.spec_extras = {
67
+ :extra_rdoc_files => ["README.txt", "History.txt", "License.txt"],
68
+ :rdoc_options => RDOC_OPTS,
69
+ :autorequire => "EC2"
70
+ }
71
+
72
+ end
73
+
74
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
75
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
76
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
+
17
+ require 'EC2'
data/lib/EC2.rb ADDED
@@ -0,0 +1,254 @@
1
+ #--
2
+ # Amazon Web Services EC2 Query API Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-ec2
5
+ # Author:: Glenn Rempe (mailto:grempe@rubyforge.org)
6
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://amazon-ec2.rubyforge.org
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
+ DEFAULT_HOST = 'ec2.amazonaws.com'
23
+
24
+ # This is the version of the API as defined by Amazon Web Services
25
+ API_VERSION = '2008-02-01'
26
+
27
+ # This release version is passed in with each request as part
28
+ # of the HTTP 'User-Agent' header. Set this be the same value
29
+ # as what is stored in the lib/EC2/version.rb module constant instead.
30
+ # This way we keep it nice and DRY and only have to define the
31
+ # version number in a single place.
32
+ RELEASE_VERSION = EC2::VERSION::STRING
33
+
34
+ # Builds the canonical string for signing. This strips out all '&', '?', and '='
35
+ # from the query string to be signed.
36
+ # Note: The parameters in the path passed in must already be sorted in
37
+ # case-insensitive alphabetical order and must not be url encoded.
38
+ def EC2.canonical_string(path)
39
+ buf = ""
40
+ path.split('&').each { |field|
41
+ buf << field.gsub(/\&|\?/,"").sub(/=/,"")
42
+ }
43
+ return buf
44
+ end
45
+
46
+ # Encodes the given string with the secret_access_key, by taking the
47
+ # hmac-sha1 sum, and then base64 encoding it. Optionally, it will also
48
+ # url encode the result of that to protect the string if it's going to
49
+ # be used as a query string parameter.
50
+ def EC2.encode(secret_access_key, str, urlencode=true)
51
+ digest = OpenSSL::Digest::Digest.new('sha1')
52
+ b64_hmac =
53
+ Base64.encode64(
54
+ OpenSSL::HMAC.digest(digest, secret_access_key, str)).strip
55
+
56
+ if urlencode
57
+ return CGI::escape(b64_hmac)
58
+ else
59
+ return b64_hmac
60
+ end
61
+ end
62
+
63
+
64
+ #Introduction:
65
+ #
66
+ # The library exposes one main interface class, 'EC2::Base'.
67
+ # This class provides all the methods for using the EC2 service
68
+ # including the handling of header signing and other security issues .
69
+ # This class uses Net::HTTP to interface with the EC2 Query API interface.
70
+ #
71
+ #Required Arguments:
72
+ #
73
+ # :access_key_id => String (default : "")
74
+ # :secret_access_key => String (default : "")
75
+ #
76
+ #Optional Arguments:
77
+ #
78
+ # :use_ssl => Boolean (default : true)
79
+ # :server => String (default : 'ec2.amazonaws.com')
80
+ # :proxy_server => String (default : nil)
81
+ #
82
+ class Base
83
+
84
+ attr_reader :use_ssl, :server, :proxy_server, :port
85
+
86
+ def initialize( options = {} )
87
+
88
+ options = { :access_key_id => "",
89
+ :secret_access_key => "",
90
+ :use_ssl => true,
91
+ :server => DEFAULT_HOST,
92
+ :proxy_server => nil
93
+ }.merge(options)
94
+
95
+ @server = options[:server]
96
+ @proxy_server = options[:proxy_server]
97
+ @use_ssl = options[:use_ssl]
98
+
99
+ raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
100
+ raise ArgumentError, "No :secret_access_key provided" if options[:secret_access_key].nil? || options[:secret_access_key].empty?
101
+ raise ArgumentError, "No :use_ssl value provided" if options[:use_ssl].nil?
102
+ raise ArgumentError, "Invalid :use_ssl value provided, only 'true' or 'false' allowed" unless options[:use_ssl] == true || options[:use_ssl] == false
103
+ raise ArgumentError, "No :server provided" if options[:server].nil? || options[:server].empty?
104
+
105
+
106
+ # based on the :use_ssl boolean, determine which port we should connect to
107
+ case @use_ssl
108
+ when true
109
+ # https
110
+ @port = 443
111
+ when false
112
+ # http
113
+ @port = 80
114
+ end
115
+
116
+ @access_key_id = options[:access_key_id]
117
+ @secret_access_key = options[:secret_access_key]
118
+
119
+ # Use proxy server if defined
120
+ # Based on patch by Mathias Dalheimer. 20070217
121
+ proxy = @proxy_server ? URI.parse(@proxy_server) : OpenStruct.new
122
+ @http = Net::HTTP::Proxy( proxy.host,
123
+ proxy.port,
124
+ proxy.user,
125
+ proxy.password).new(options[:server], @port)
126
+
127
+ @http.use_ssl = @use_ssl
128
+
129
+ # Don't verify the SSL certificates. Avoids SSL Cert warning in log on every GET.
130
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
131
+
132
+ end
133
+
134
+
135
+ private
136
+
137
+ # pathlist is a utility method which takes a key string and and array as input.
138
+ # It converts the array into a Hash with the hash key being 'Key.n' where
139
+ # 'n' increments by 1 for each iteration. So if you pass in args
140
+ # ("ImageId", ["123", "456"]) you should get
141
+ # {"ImageId.1"=>"123", "ImageId.2"=>"456"} returned.
142
+ def pathlist(key, arr)
143
+ params = {}
144
+ arr.each_with_index do |value, i|
145
+ params["#{key}.#{i+1}"] = value
146
+ end
147
+ params
148
+ end
149
+
150
+
151
+ # Make the connection to AWS EC2 passing in our request. This is generally called from
152
+ # within a 'Response' class object or one of its sub-classes so the response is interpreted
153
+ # in its proper context. See lib/EC2/responses.rb
154
+ def make_request(action, params, data='')
155
+
156
+ @http.start do
157
+
158
+ # remove any keys that have nil or empty values
159
+ params.reject! { |key, value| value.nil? or value.empty?}
160
+
161
+ params.merge!( {"Action" => action,
162
+ "SignatureVersion" => "1",
163
+ "AWSAccessKeyId" => @access_key_id,
164
+ "Version" => API_VERSION,
165
+ "Timestamp"=>Time.now.getutc.iso8601} )
166
+
167
+ sigquery = params.sort_by { |param| param[0].downcase }.collect { |param| param.join("=") }.join("&")
168
+
169
+ sig = get_aws_auth_param(sigquery, @secret_access_key)
170
+
171
+ query = params.sort.collect do |param|
172
+ CGI::escape(param[0]) + "=" + CGI::escape(param[1])
173
+ end.join("&") + "&Signature=" + sig
174
+
175
+ req = Net::HTTP::Post.new("/")
176
+ req.content_type = 'application/x-www-form-urlencoded'
177
+ req['User-Agent'] = "rubyforge-amazon-ec2-ruby-gem-query-api v-#{RELEASE_VERSION}"
178
+
179
+ response = @http.request(req, query)
180
+
181
+ # Make a call to see if we need to throw an error based on the response given by EC2
182
+ # All error classes are defined in EC2/exceptions.rb
183
+ ec2_error?(response)
184
+
185
+ return response
186
+
187
+ end
188
+
189
+ end
190
+
191
+ # Set the Authorization header using AWS signed header authentication
192
+ def get_aws_auth_param(path, secret_access_key)
193
+ canonical_string = EC2.canonical_string(path)
194
+ encoded_canonical = EC2.encode(secret_access_key, canonical_string)
195
+ end
196
+
197
+ # allow us to have a one line call in each method which will do all of the work
198
+ # in making the actual request to AWS.
199
+ def response_generator( options = {} )
200
+
201
+ options = {
202
+ :action => "",
203
+ :params => {}
204
+ }.merge(options)
205
+
206
+ raise ArgumentError, ":action must be provided to response_generator" if options[:action].nil? || options[:action].empty?
207
+
208
+ http_response = make_request(options[:action], options[:params])
209
+ http_xml = http_response.body
210
+ return Response.parse(:xml => http_xml)
211
+
212
+ end
213
+
214
+ # Raises the appropriate error if the specified Net::HTTPResponse object
215
+ # contains an Amazon EC2 error; returns +false+ otherwise.
216
+ def ec2_error?(response)
217
+
218
+ # return false if we got a HTTP 200 code,
219
+ # otherwise there is some type of error (40x,50x) and
220
+ # we should try to raise an appropriate exception
221
+ # from one of our exception classes defined in
222
+ # exceptions.rb
223
+ return false if response.is_a?(Net::HTTPSuccess)
224
+
225
+ # parse the XML document so we can walk through it
226
+ doc = REXML::Document.new(response.body)
227
+
228
+ # Check that the Error element is in the place we would expect.
229
+ # and if not raise a generic error exception
230
+ unless doc.root.elements['Errors'].elements['Error'].name == 'Error'
231
+ raise Error, "Unexpected error format. response.body is: #{response.body}"
232
+ end
233
+
234
+ # An valid error response looks like this:
235
+ # <?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>
236
+ # AWS EC2 throws some exception codes that look like Error.SubError. Since we can't name classes this way
237
+ # we need to strip out the '.' in the error 'Code' and we name the error exceptions with this
238
+ # non '.' name as well.
239
+ error_code = doc.root.elements['Errors'].elements['Error'].elements['Code'].text.gsub('.', '')
240
+ error_message = doc.root.elements['Errors'].elements['Error'].elements['Message'].text
241
+
242
+ # Raise one of our specific error classes if it exists.
243
+ # otherwise, throw a generic EC2 Error with a few details.
244
+ if EC2.const_defined?(error_code)
245
+ raise EC2.const_get(error_code), error_message
246
+ else
247
+ raise Error, "This is an undefined error code which needs to be added to exceptions.rb : error_code => #{error_code} : error_message => #{error_message}"
248
+ end
249
+
250
+ end
251
+
252
+ end
253
+
254
+ end