Skip to content
This repository has been archived by the owner on Jan 20, 2019. It is now read-only.

Commit

Permalink
Updated to support EC2 API version 2007-08-29 released on 2007-10-16
Browse files Browse the repository at this point in the history
* Supports new instances type feature.  Specify an instance type to launch
  (m1.small, m1.large, m1.xlarge) when you call the 'run_instances' method.
  e.g. add to the params hash ':instance_type => "m1.small"'
* RunInstances and DescribeInstances now return the time when the Amazon EC2 instance was launched.
* Updated tests.
* Code Tidyup : Removed trailing spaces in code docs.


git-svn-id: svn+ssh://rubyforge.org/var/svn/amazon-ec2/trunk@103 2e111c3a-5438-44ef-9c14-21a960333853
  • Loading branch information
grempe committed Oct 17, 2007
1 parent 83c2e7f commit deb7d06
Show file tree
Hide file tree
Showing 28 changed files with 827 additions and 937 deletions.
9 changes: 9 additions & 0 deletions amazon-ec2/History.txt
@@ -1,3 +1,12 @@
=== 0.2.6 2007-10-16
* Updated to support EC2 API version 2007-08-29 released on 2007-10-16
* Supports new instances type feature. Specify an instance type to launch
(m1.small, m1.large, m1.xlarge) when you call the 'run_instances' method.

e.g. add to the params hash ':instance_type => "m1.small"'
* RunInstances and DescribeInstances now return the time when the Amazon EC2 instance was launched.
* Code Tidyup : Removed trailing spaces in code docs.

=== 0.2.5 2007-09-26
* Updated using Dr. Nic's newgem v. 0.13.5
* Updated email address.
Expand Down
2 changes: 0 additions & 2 deletions amazon-ec2/Manifest.txt
Expand Up @@ -37,8 +37,6 @@ test/test_EC2_responses.rb
test/test_EC2_security_groups.rb
test/test_EC2_version.rb
test/test_helper.rb
website/announce.html
website/announce.txt
website/index.html
website/index.txt
website/javascripts/rounded_corners_lite.inc.js
Expand Down
2 changes: 1 addition & 1 deletion amazon-ec2/README.txt
Expand Up @@ -137,7 +137,7 @@ Try out the following bit of code. This should walk through each image returned

=== Related Projects

* Capazon : http://capazon.rubyforge.org
* Capsize : http://capsize.rubyforge.org

== Credits

Expand Down
120 changes: 60 additions & 60 deletions amazon-ec2/lib/EC2.rb
Expand Up @@ -12,25 +12,25 @@

# Require any lib files that we have bundled with this Ruby Gem in the lib/EC2 directory.
# Parts of the EC2 module and Base class are broken out into separate
# files for maintainability and are organized by the functional groupings defined
# files for maintainability and are organized by the functional groupings defined
# in the EC2 API developers guide.
Dir[File.join(File.dirname(__FILE__), 'EC2/**/*.rb')].sort.each { |lib| require lib }

module EC2

# Which host FQDN will we connect to for all API calls to AWS?
DEFAULT_HOST = 'ec2.amazonaws.com'

# This is the version of the API as defined by Amazon Web Services
API_VERSION = '2007-03-01'
API_VERSION = '2007-08-29'

# This release version is passed in with each request as part
# of the HTTP 'User-Agent' header. Set this be the same value
# of the HTTP 'User-Agent' header. Set this be the same value
# as what is stored in the lib/EC2/version.rb module constant instead.
# This way we keep it nice and DRY and only have to define the
# version number in a single place.
# This way we keep it nice and DRY and only have to define the
# version number in a single place.
RELEASE_VERSION = EC2::VERSION::STRING

# Builds the canonical string for signing. This strips out all '&', '?', and '='
# from the query string to be signed.
# Note: The parameters in the path passed in must already be sorted in
Expand All @@ -42,7 +42,7 @@ def EC2.canonical_string(path)
}
return buf
end

# Encodes the given string with the secret_access_key, by taking the
# hmac-sha1 sum, and then base64 encoding it. Optionally, it will also
# url encode the result of that to protect the string if it's going to
Expand All @@ -52,20 +52,20 @@ def EC2.encode(secret_access_key, str, urlencode=true)
b64_hmac =
Base64.encode64(
OpenSSL::HMAC.digest(digest, secret_access_key, str)).strip

if urlencode
return CGI::escape(b64_hmac)
else
return b64_hmac
end
end


#Introduction:
#
# The library exposes one main interface class, 'EC2::Base'.
# This class provides all the methods for using the EC2 service
# including the handling of header signing and other security issues .
# This class provides all the methods for using the EC2 service
# including the handling of header signing and other security issues .
# This class uses Net::HTTP to interface with the EC2 Query API interface.
#
#Required Arguments:
Expand All @@ -79,27 +79,27 @@ def EC2.encode(secret_access_key, str, urlencode=true)
# :server => String (default : 'ec2.amazonaws.com')
#
class Base

attr_reader :use_ssl, :server, :port

def initialize( options = {} )

options = { :access_key_id => "",
:secret_access_key => "",
:use_ssl => true,
:server => DEFAULT_HOST
}.merge(options)

@server = options[:server]
@use_ssl = options[:use_ssl]

raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
raise ArgumentError, "No :secret_access_key provided" if options[:secret_access_key].nil? || options[:secret_access_key].empty?
raise ArgumentError, "No :use_ssl value provided" if options[:use_ssl].nil?
raise ArgumentError, "Invalid :use_ssl value provided, only 'true' or 'false' allowed" unless options[:use_ssl] == true || options[:use_ssl] == false
raise ArgumentError, "No :server provided" if options[:server].nil? || options[:server].empty?


# based on the :use_ssl boolean, determine which port we should connect to
case @use_ssl
when true
Expand All @@ -109,24 +109,24 @@ def initialize( options = {} )
# http
@port = 80
end

@access_key_id = options[:access_key_id]
@secret_access_key = options[:secret_access_key]
@http = Net::HTTP.new(options[:server], @port)
@http.use_ssl = @use_ssl

# Don't verify the SSL certificates. Avoids SSL Cert warning in log on every GET.
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE

end


private

# 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
# '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.
def pathlist(key, arr)
params = {}
Expand All @@ -135,81 +135,81 @@ def pathlist(key, arr)
end
params
end
# Make the connection to AWS EC2 passing in our request. This is generally called from


# 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
def make_request(action, params, data='')

@http.start do

# remove any keys that have nil or empty values
params.reject! { |key, value| value.nil? or value.empty?}

params.merge!( {"Action" => action,
"SignatureVersion" => "1",
"AWSAccessKeyId" => @access_key_id,
"Version" => API_VERSION,
"Timestamp"=>Time.now.getutc.iso8601} )

sigpath = "?" + params.sort_by { |param| param[0].downcase }.collect { |param| param.join("=") }.join("&")

sig = get_aws_auth_param(sigpath, @secret_access_key)

path = "?" + params.sort.collect do |param|
CGI::escape(param[0]) + "=" + CGI::escape(param[1])
end.join("&") + "&Signature=" + sig

req = Net::HTTP::Get.new("/#{path}")

# Ruby will automatically add a random content-type on some verbs, so
# here we add a dummy one to 'supress' it. Change this logic if having
# an empty content-type header becomes semantically meaningful for any
# other verb.
req['Content-Type'] ||= ''
req['User-Agent'] = "rubyforge-amazon-ec2-ruby-gem-query-api v-#{RELEASE_VERSION}"

#data = nil unless req.request_body_permitted?
response = @http.request(req, nil)

# Make a call to see if we need to throw an error based on the response given by EC2
# All error classes are defined in EC2/exceptions.rb
ec2_error?(response)

return response

end

end

# Set the Authorization header using AWS signed header authentication
def get_aws_auth_param(path, secret_access_key)
canonical_string = EC2.canonical_string(path)
encoded_canonical = EC2.encode(secret_access_key, canonical_string)
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.
def response_generator( options = {} )

options = {
:action => "",
:params => {}
}.merge(options)

raise ArgumentError, ":action must be provided to response_generator" if options[:action].nil? || options[:action].empty?

http_response = make_request(options[:action], options[:params])
http_xml = http_response.body
return Response.parse(:xml => http_xml)

end

# Raises the appropriate error if the specified Net::HTTPResponse object
# contains an Amazon EC2 error; returns +false+ otherwise.
def ec2_error?(response)

# return false if we got a HTTP 200 code,
# otherwise there is some type of error (40x,50x) and
# we should try to raise an appropriate exception
Expand All @@ -219,31 +219,31 @@ def ec2_error?(response)

# parse the XML document so we can walk through it
doc = REXML::Document.new(response.body)

# Check that the Error element is in the place we would expect.
# and if not raise a generic error exception
unless doc.root.elements['Errors'].elements['Error'].name == 'Error'
raise Error, "Unexpected error format. response.body is: #{response.body}"
end

# An valid error response looks like this:
# <?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>
# AWS EC2 throws some exception codes that look like Error.SubError. Since we can't name classes this way
# we need to strip out the '.' in the error 'Code' and we name the error exceptions with this
# non '.' name as well.
error_code = doc.root.elements['Errors'].elements['Error'].elements['Code'].text.gsub('.', '')
error_message = doc.root.elements['Errors'].elements['Error'].elements['Message'].text

# Raise one of our specific error classes if it exists.
# otherwise, throw a generic EC2 Error with a few details.
if EC2.const_defined?(error_code)
raise EC2.const_get(error_code), error_message
else
raise Error, "This is an undefined error code which needs to be added to exceptions.rb : error_code => #{error_code} : error_message => #{error_message}"
end

end

end

end
22 changes: 11 additions & 11 deletions amazon-ec2/lib/EC2/console.rb
Expand Up @@ -9,15 +9,15 @@
#++

module EC2

class Base

#Amazon Developer Guide Docs:
#
#
# The GetConsoleOutput operation retrieves console output that has been posted for the specified instance.
#
# Instance console output is buffered and posted shortly after instance boot, reboot and once the instance
# is terminated. Only the most recent 64 KB of posted output is available. Console output is available for
# Instance console output is buffered and posted shortly after instance boot, reboot and once the instance
# is terminated. Only the most recent 64 KB of posted output is available. Console output is available for
# at least 1 hour after the most recent post.
#
#Required Arguments:
Expand All @@ -29,16 +29,16 @@ class Base
# none
#
def get_console_output( options ={} )

options = {:instance_id => ""}.merge(options)

raise ArgumentError, "No instance ID provided" if options[:instance_id].nil? || options[:instance_id].empty?

params = { "InstanceId" => options[:instance_id] }

return response_generator(:action => "GetConsoleOutput", :params => params)

end
end

end

0 comments on commit deb7d06

Please sign in to comment.