Class AWS::Base
In: lib/AWS.rb
Parent: Object
Error InvalidClientTokenId InsufficientAddressCapacity InternalError InvalidVolumeIDDuplicate InvalidReservedInstancesOfferingId InvalidReservationIDNotFound InvalidParameterValue InvalidInstanceIDMalformed InvalidInstance SnapshotLimitExceeded InvalidReservationIDMalformed InvalidInstanceIDNotFound InvalidAttachmentNotFound ArgumentError SignatureDoesNotMatch InvalidPermissionMalformed InvalidGroupNotFound IncorrectState TooManyLoadBalancers LoadBalancerNotFound ReservedInstancesLimitExceeded InsufficientReservedInstancesCapacity InvalidAMIIDMalformed AuthFailure AttachmentLimitExceeded AddressLimitExceeded InvalidConfigurationRequest Unavailable InvalidGroupReserved InvalidGroupDuplicate InstanceLimitExceeded ValidationError InsufficientReservedInstanceCapacity InvalidVolumeIDMalformed InvalidVolumeIDNotFound InvalidPermissionDuplicate InvalidAMIIDNotFound PendingSnapshotLimitExceeded NonEBSInstance InvalidVolumeIDZoneMismatch InvalidReservedInstancesId InvalidManifest InvalidGroupInUse InvalidKeyPairNotFound InvalidAMIIDUnavailable DuplicateLoadBalancerName InsufficientInstanceCapacity VolumeLimitExceeded UnknownParameter InvalidZoneNotFound InvalidSnapshotIDNotFound InvalidSnapshotIDMalformed InvalidParameterCombination InvalidKeyPairDuplicate InvalidUserIDMalformed InvalidDeviceInUse InvalidAMIAttributeItemValue RuntimeError Base Base\n[lib/AWS/RDS.rb\nlib/AWS/RDS/rds.rb] Base\n[lib/AWS/Cloudwatch.rb\nlib/AWS/Cloudwatch/monitoring.rb] Base\n[lib/AWS/ELB.rb\nlib/AWS/ELB/load_balancers.rb] Base\n[lib/AWS/Autoscaling.rb\nlib/AWS/Autoscaling/autoscaling.rb] Base\n[lib/AWS/EC2.rb\nlib/AWS/EC2/availability_zones.rb\nlib/AWS/EC2/console.rb\nlib/AWS/EC2/devpay.rb\nlib/AWS/EC2/elastic_ips.rb\nlib/AWS/EC2/image_attributes.rb\nlib/AWS/EC2/images.rb\nlib/AWS/EC2/instances.rb\nlib/AWS/EC2/keypairs.rb\nlib/AWS/EC2/products.rb\nlib/AWS/EC2/security_groups.rb\nlib/AWS/EC2/snapshots.rb\nlib/AWS/EC2/spot_instance_requests.rb\nlib/AWS/EC2/spot_prices.rb\nlib/AWS/EC2/subnets.rb\nlib/AWS/EC2/volumes.rb] Response lib/AWS.rb lib/AWS/responses.rb lib/AWS/exceptions.rb lib/AWS/RDS/rds.rb RDS lib/AWS/Cloudwatch/monitoring.rb Cloudwatch lib/AWS/ELB/load_balancers.rb ELB lib/AWS/Autoscaling/autoscaling.rb Autoscaling lib/AWS/EC2/volumes.rb Instance EC2 AWS dot/m_26_0.png

This class provides all the methods for using the EC2 or ELB service including the handling of header signing and other security concerns. This class uses the Net::HTTP library to interface with the AWS Query API interface. You should not instantiate this directly, instead you should setup an instance of ‘AWS::EC2::Base’ or ‘AWS::ELB::Base’.

Methods

Attributes

port  [R] 
proxy_server  [R] 
server  [R] 
use_ssl  [R] 

Public Class methods

@option options [String] :access_key_id ("") The user‘s AWS Access Key ID @option options [String] :secret_access_key ("") The user‘s AWS Secret Access Key @option options [Boolean] :use_ssl (true) Connect using SSL? @option options [String] :server ("ec2.amazonaws.com") The server API endpoint host @option options [String] :proxy_server (nil) An HTTP proxy server FQDN @return [Object] the object.

[Source]

     # File lib/AWS.rb, line 123
123:     def initialize( options = {} )
124: 
125:       options = { :access_key_id => "",
126:                   :secret_access_key => "",
127:                   :use_ssl => true,
128:                   :server => default_host,
129:                   :proxy_server => nil
130:                   }.merge(options)
131: 
132:       @server = options[:server]
133:       @proxy_server = options[:proxy_server]
134:       @use_ssl = options[:use_ssl]
135: 
136:       raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
137:       raise ArgumentError, "No :secret_access_key provided" if options[:secret_access_key].nil? || options[:secret_access_key].empty?
138:       raise ArgumentError, "No :use_ssl value provided" if options[:use_ssl].nil?
139:       raise ArgumentError, "Invalid :use_ssl value provided, only 'true' or 'false' allowed" unless options[:use_ssl] == true || options[:use_ssl] == false
140:       raise ArgumentError, "No :server provided" if options[:server].nil? || options[:server].empty?
141: 
142:       if options[:port]
143:         # user-specified port
144:         @port = options[:port]
145:       elsif @use_ssl
146:         # https
147:         @port = 443
148:       else
149:         # http
150:         @port = 80
151:       end
152: 
153:       @access_key_id = options[:access_key_id]
154:       @secret_access_key = options[:secret_access_key]
155: 
156:       # Use proxy server if defined
157:       # Based on patch by Mathias Dalheimer.  20070217
158:       proxy = @proxy_server ? URI.parse(@proxy_server) : OpenStruct.new
159:       @http = Net::HTTP::Proxy( proxy.host,
160:                                 proxy.port,
161:                                 proxy.user,
162:                                 proxy.password).new(options[:server], @port)
163: 
164:       @http.use_ssl = @use_ssl
165: 
166:       # Don't verify the SSL certificates.  Avoids SSL Cert warning in log on every GET.
167:       @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
168: 
169:     end

Public Instance methods

If :user_data is passed in then URL escape and Base64 encode it as needed. Need for URL Escape + Base64 encoding is determined by :base64_encoded param.

[Source]

     # File lib/AWS.rb, line 174
174:     def extract_user_data( options = {} )
175:       return unless options[:user_data]
176:       if options[:user_data]
177:         if options[:base64_encoded]
178:           Base64.encode64(options[:user_data]).gsub(/\n/, "").strip()
179:         else
180:           options[:user_data]
181:         end
182:       end
183:     end

Protected Instance methods

Raises the appropriate error if the specified Net::HTTPResponse object contains an AWS error; returns false otherwise.

[Source]

     # File lib/AWS.rb, line 290
290:       def aws_error?(response)
291: 
292:         # return false if we got a HTTP 200 code,
293:         # otherwise there is some type of error (40x,50x) and
294:         # we should try to raise an appropriate exception
295:         # from one of our exception classes defined in
296:         # exceptions.rb
297:         return false if response.is_a?(Net::HTTPSuccess)
298: 
299:         # parse the XML document so we can walk through it
300:         doc = REXML::Document.new(response.body)
301: 
302:         # Check that the Error element is in the place we would expect.
303:         # and if not raise a generic error exception
304:         unless doc.root.elements['Errors'].elements['Error'].name == 'Error'
305:           raise Error, "Unexpected error format. response.body is: #{response.body}"
306:         end
307: 
308:         # An valid error response looks like this:
309:         # <?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>
310:         # AWS throws some exception codes that look like Error.SubError.  Since we can't name classes this way
311:         # we need to strip out the '.' in the error 'Code' and we name the error exceptions with this
312:         # non '.' name as well.
313:         error_code    = doc.root.elements['Errors'].elements['Error'].elements['Code'].text.gsub('.', '')
314:         error_message = doc.root.elements['Errors'].elements['Error'].elements['Message'].text
315: 
316:         # Raise one of our specific error classes if it exists.
317:         # otherwise, throw a generic EC2 Error with a few details.
318:         if AWS.const_defined?(error_code)
319:           raise AWS.const_get(error_code), error_message
320:         else
321:           raise AWS::Error, error_message
322:         end
323: 
324:       end

Set the Authorization header using AWS signed header authentication

[Source]

     # File lib/AWS.rb, line 267
267:       def get_aws_auth_param(params, secret_access_key, server)
268:         canonical_string =  AWS.canonical_string(params, server)
269:         encoded_canonical = AWS.encode(secret_access_key, canonical_string)
270:       end

Make the connection to AWS EC2 passing in our request. This is generally called from within a ‘Response’ class object or one of its sub-classes so the response is interpreted in its proper context. See lib/EC2/responses.rb

[Source]

     # File lib/AWS.rb, line 231
231:       def make_request(action, params, data='')
232: 
233:         @http.start do
234: 
235:           # remove any keys that have nil or empty values
236:           params.reject! { |key, value| value.nil? or value.empty?}
237: 
238:           params.merge!( {"Action" => action,
239:                           "SignatureVersion" => "2",
240:                           "SignatureMethod" => 'HmacSHA1',
241:                           "AWSAccessKeyId" => @access_key_id,
242:                           "Version" => api_version,
243:                           "Timestamp"=>Time.now.getutc.iso8601} )
244: 
245:           sig = get_aws_auth_param(params, @secret_access_key, @server)
246: 
247:           query = params.sort.collect do |param|
248:             CGI::escape(param[0]) + "=" + CGI::escape(param[1])
249:           end.join("&") + "&Signature=" + sig
250: 
251:           req = Net::HTTP::Post.new("/")
252:           req.content_type = 'application/x-www-form-urlencoded'
253:           req['User-Agent'] = "github-amazon-ec2-ruby-gem"
254: 
255:           response = @http.request(req, query)
256: 
257:           # Make a call to see if we need to throw an error based on the response given by EC2
258:           # All error classes are defined in EC2/exceptions.rb
259:           aws_error?(response)
260:           return response
261: 
262:         end
263: 
264:       end

Same as pathlist except it deals with arrays of hashes. So if you pass in args ("People", [{:name=>’jon’, :age=>’22’}, {:name=>’chris’}], {:name => ‘Name’, :age => ‘Age’}) you should get {"People.1.Name"=>"jon", "People.1.Age"=>’22’, ‘People.2.Name’=>’chris’}

[Source]

     # File lib/AWS.rb, line 214
214:       def pathhashlist(key, arr_of_hashes, mappings)
215:         raise ArgumentError, "expected a key that is a String" unless key.is_a? String
216:         raise ArgumentError, "expected a arr_of_hashes that is an Array" unless arr_of_hashes.is_a? Array
217:         arr_of_hashes.each{|h| raise ArgumentError, "expected each element of arr_of_hashes to be a Hash" unless h.is_a?(Hash)}
218:         raise ArgumentError, "expected a mappings that is an Hash" unless mappings.is_a? Hash
219:         params = {}
220:         arr_of_hashes.each_with_index do |hash, i|
221:           hash.each do |attribute, value|
222:             params["#{key}.#{i+1}.#{mappings[attribute]}"] = value.to_s
223:           end
224:         end
225:         params
226:       end

pathlist is a utility method which takes a key string and and array as input. It converts the array into a Hash with the hash key being ‘Key.n’ where ‘n’ increments by 1 for each iteration. So if you pass in args ("ImageId", ["123", "456"]) you should get {"ImageId.1"=>"123", "ImageId.2"=>"456"} returned.

[Source]

     # File lib/AWS.rb, line 193
193:       def pathlist(key, arr)
194:         params = {}
195: 
196:         # ruby 1.9 will barf if we pass in a string instead of the array expected.
197:         # it will fail on each_with_index below since string is not enumerable.
198:         if arr.is_a? String
199:           new_arr = []
200:           new_arr << arr
201:           arr = new_arr
202:         end
203: 
204:         arr.each_with_index do |value, i|
205:           params["#{key}.#{i+1}"] = value
206:         end
207:         params
208:       end

allow us to have a one line call in each method which will do all of the work in making the actual request to AWS.

[Source]

     # File lib/AWS.rb, line 274
274:       def response_generator( options = {} )
275: 
276:         options = {
277:           :action => "",
278:           :params => {}
279:         }.merge(options)
280: 
281:         raise ArgumentError, ":action must be provided to response_generator" if options[:action].nil? || options[:action].empty?
282: 
283:         http_response = make_request(options[:action], options[:params])
284:         http_xml = http_response.body
285:         return Response.parse(:xml => http_xml)
286:       end

[Validate]