grempe-amazon-ec2 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +230 -0
- data/License.txt +66 -0
- data/Manifest.txt +46 -0
- data/README.txt +154 -0
- data/Rakefile +4 -0
- data/bin/ec2-gem-example.rb +61 -0
- data/bin/ec2sh +73 -0
- data/bin/setup.rb +19 -0
- data/config/hoe.rb +76 -0
- data/config/requirements.rb +17 -0
- data/lib/EC2.rb +254 -0
- data/lib/EC2/console.rb +44 -0
- data/lib/EC2/elastic_ips.rb +153 -0
- data/lib/EC2/exceptions.rb +136 -0
- data/lib/EC2/image_attributes.rb +166 -0
- data/lib/EC2/images.rb +134 -0
- data/lib/EC2/instances.rb +206 -0
- data/lib/EC2/keypairs.rb +94 -0
- data/lib/EC2/products.rb +43 -0
- data/lib/EC2/responses.rb +175 -0
- data/lib/EC2/security_groups.rb +232 -0
- data/lib/EC2/version.rb +18 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +27 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_EC2.rb +52 -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 +325 -0
- data/test/test_EC2_keypairs.rb +123 -0
- data/test/test_EC2_products.rb +48 -0
- data/test/test_EC2_responses.rb +102 -0
- data/test/test_EC2_security_groups.rb +205 -0
- data/test/test_EC2_version.rb +44 -0
- data/test/test_helper.rb +20 -0
- data/website/index.txt +427 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +55 -0
- metadata +174 -0
data/Rakefile
ADDED
@@ -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
|