krisr-amazon-ec2 0.5.0

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.
Files changed (55) hide show
  1. data/.gitignore +6 -0
  2. data/ChangeLog +284 -0
  3. data/LICENSE +66 -0
  4. data/README.rdoc +329 -0
  5. data/Rakefile +101 -0
  6. data/VERSION +1 -0
  7. data/amazon-ec2.gemspec +123 -0
  8. data/bin/ec2-gem-example.rb +66 -0
  9. data/bin/ec2-gem-profile.rb +10 -0
  10. data/bin/ec2sh +62 -0
  11. data/bin/setup.rb +26 -0
  12. data/deps.rip +1 -0
  13. data/lib/AWS.rb +239 -0
  14. data/lib/AWS/EC2.rb +67 -0
  15. data/lib/AWS/EC2/availability_zones.rb +43 -0
  16. data/lib/AWS/EC2/console.rb +46 -0
  17. data/lib/AWS/EC2/elastic_ips.rb +154 -0
  18. data/lib/AWS/EC2/image_attributes.rb +168 -0
  19. data/lib/AWS/EC2/images.rb +136 -0
  20. data/lib/AWS/EC2/instances.rb +218 -0
  21. data/lib/AWS/EC2/keypairs.rb +96 -0
  22. data/lib/AWS/EC2/products.rb +45 -0
  23. data/lib/AWS/EC2/security_groups.rb +234 -0
  24. data/lib/AWS/EC2/snapshots.rb +96 -0
  25. data/lib/AWS/EC2/volumes.rb +172 -0
  26. data/lib/AWS/ELB.rb +57 -0
  27. data/lib/AWS/ELB/load_balancers.rb +201 -0
  28. data/lib/AWS/exceptions.rb +169 -0
  29. data/lib/AWS/responses.rb +61 -0
  30. data/lib/EC2.rb +31 -0
  31. data/perftools/ec2prof +0 -0
  32. data/perftools/ec2prof-results.dot +193 -0
  33. data/perftools/ec2prof-results.txt +126 -0
  34. data/perftools/ec2prof.symbols +129 -0
  35. data/test/test_EC2.rb +68 -0
  36. data/test/test_EC2_availability_zones.rb +49 -0
  37. data/test/test_EC2_console.rb +54 -0
  38. data/test/test_EC2_elastic_ips.rb +144 -0
  39. data/test/test_EC2_image_attributes.rb +238 -0
  40. data/test/test_EC2_images.rb +197 -0
  41. data/test/test_EC2_instances.rb +348 -0
  42. data/test/test_EC2_keypairs.rb +123 -0
  43. data/test/test_EC2_products.rb +48 -0
  44. data/test/test_EC2_responses.rb +52 -0
  45. data/test/test_EC2_s3_xmlsimple.rb +80 -0
  46. data/test/test_EC2_security_groups.rb +205 -0
  47. data/test/test_EC2_snapshots.rb +83 -0
  48. data/test/test_EC2_volumes.rb +142 -0
  49. data/test/test_ELB_load_balancers.rb +238 -0
  50. data/test/test_helper.rb +19 -0
  51. data/wsdl/2007-08-29.ec2.wsdl +1269 -0
  52. data/wsdl/2008-02-01.ec2.wsdl +1614 -0
  53. data/wsdl/2008-05-05.ec2.wsdl +2052 -0
  54. data/wsdl/2008-12-01.ec2.wsdl +2354 -0
  55. metadata +184 -0
@@ -0,0 +1,101 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "amazon-ec2"
8
+ gem.summary = %Q{Amazon EC2 Ruby Gem}
9
+ gem.description = %Q{An interface library that allows Ruby applications to easily connect to the HTTP 'Query API' for the Amazon Web Services Elastic Compute Cloud (EC2) and manipulate cloud servers.}
10
+ gem.email = "glenn@rempe.us"
11
+ gem.homepage = "http://github.com/grempe/amazon-ec2"
12
+ gem.authors = ["Glenn Rempe"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+
15
+ # gem.autorequire = 'EC2'
16
+ gem.rdoc_options = ["--quiet", "--title", "amazon-ec2 documentation", "--opname", "index.html", "--line-numbers", "--main", "README.rdoc", "--inline-source"]
17
+
18
+ gem.rubyforge_project = 'amazon-ec2'
19
+
20
+ gem.add_dependency('xml-simple', '>= 1.0.12')
21
+ gem.add_development_dependency('mocha', '>= 0.9.5')
22
+ gem.add_development_dependency('test-spec', '>= 0.10.0')
23
+ gem.add_development_dependency('rcov', '>= 0.8.1.2.0')
24
+ gem.add_development_dependency('perftools.rb', '= 0.1.6')
25
+
26
+ end
27
+
28
+ rescue LoadError
29
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
30
+ end
31
+
32
+ require 'rake/testtask'
33
+ Rake::TestTask.new(:test) do |test|
34
+ test.libs << 'lib' << 'test'
35
+ test.pattern = 'test/**/test_*.rb'
36
+ test.verbose = true
37
+ end
38
+
39
+ begin
40
+ require 'rcov/rcovtask'
41
+ Rcov::RcovTask.new do |test|
42
+ test.libs << 'test'
43
+ test.pattern = 'test/**/test_*.rb'
44
+ test.verbose = true
45
+ end
46
+ rescue LoadError
47
+ task :rcov do
48
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
49
+ end
50
+ end
51
+
52
+
53
+ task :default => :test
54
+
55
+ require 'rake/rdoctask'
56
+ Rake::RDocTask.new do |rdoc|
57
+ if File.exist?('VERSION.yml')
58
+ config = YAML.load(File.read('VERSION.yml'))
59
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
60
+ else
61
+ version = ""
62
+ end
63
+
64
+ rdoc.rdoc_dir = 'rdoc'
65
+ rdoc.title = "amazon-ec2 #{version}"
66
+ rdoc.rdoc_files.include('README*')
67
+ rdoc.rdoc_files.include('lib/**/*.rb')
68
+ end
69
+
70
+ begin
71
+ require 'rake/contrib/sshpublisher'
72
+ namespace :rubyforge do
73
+
74
+ desc "Release gem and RDoc documentation to RubyForge"
75
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
76
+
77
+ namespace :release do
78
+ desc "Publish RDoc to RubyForge."
79
+ task :docs => [:rdoc] do
80
+ config = YAML.load(
81
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
82
+ )
83
+
84
+ host = "#{config['username']}@rubyforge.org"
85
+ remote_dir = "/var/www/gforge-projects/amazon-ec2/"
86
+ local_dir = 'rdoc'
87
+
88
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
89
+ end
90
+ end
91
+ end
92
+ rescue LoadError
93
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
94
+ end
95
+
96
+ desc "Generate a perftools.rb profile"
97
+ task :profile do
98
+ system("CPUPROFILE=perftools/ec2prof RUBYOPT='-r/usr/local/lib/ruby/gems/1.8/gems/perftools.rb-0.1.6/lib/perftools.bundle' ruby -r'rubygems' bin/ec2-gem-profile.rb")
99
+ system("pprof.rb --text --ignore=Gem perftools/ec2prof > perftools/ec2prof-results.txt")
100
+ system("pprof.rb --dot --ignore=Gem perftools/ec2prof > perftools/ec2prof-results.dot")
101
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0
@@ -0,0 +1,123 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{amazon-ec2}
5
+ s.version = "0.5.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Glenn Rempe"]
9
+ s.date = %q{2009-08-04}
10
+ s.description = %q{An interface library that allows Ruby applications to easily connect to the HTTP 'Query API' for the Amazon Web Services Elastic Compute Cloud (EC2) and manipulate cloud servers.}
11
+ s.email = %q{glenn@rempe.us}
12
+ s.executables = ["ec2-gem-example.rb", "ec2-gem-profile.rb", "ec2sh", "setup.rb"]
13
+ s.extra_rdoc_files = [
14
+ "ChangeLog",
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "ChangeLog",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "amazon-ec2.gemspec",
26
+ "bin/ec2-gem-example.rb",
27
+ "bin/ec2-gem-profile.rb",
28
+ "bin/ec2sh",
29
+ "bin/setup.rb",
30
+ "deps.rip",
31
+ "lib/AWS.rb",
32
+ "lib/AWS/EC2.rb",
33
+ "lib/AWS/EC2/availability_zones.rb",
34
+ "lib/AWS/EC2/console.rb",
35
+ "lib/AWS/EC2/elastic_ips.rb",
36
+ "lib/AWS/EC2/image_attributes.rb",
37
+ "lib/AWS/EC2/images.rb",
38
+ "lib/AWS/EC2/instances.rb",
39
+ "lib/AWS/EC2/keypairs.rb",
40
+ "lib/AWS/EC2/products.rb",
41
+ "lib/AWS/EC2/security_groups.rb",
42
+ "lib/AWS/EC2/snapshots.rb",
43
+ "lib/AWS/EC2/volumes.rb",
44
+ "lib/AWS/ELB.rb",
45
+ "lib/AWS/ELB/load_balancers.rb",
46
+ "lib/AWS/exceptions.rb",
47
+ "lib/AWS/responses.rb",
48
+ "lib/EC2.rb",
49
+ "perftools/ec2prof",
50
+ "perftools/ec2prof-results.dot",
51
+ "perftools/ec2prof-results.txt",
52
+ "perftools/ec2prof.symbols",
53
+ "test/test_EC2.rb",
54
+ "test/test_EC2_availability_zones.rb",
55
+ "test/test_EC2_console.rb",
56
+ "test/test_EC2_elastic_ips.rb",
57
+ "test/test_EC2_image_attributes.rb",
58
+ "test/test_EC2_images.rb",
59
+ "test/test_EC2_instances.rb",
60
+ "test/test_EC2_keypairs.rb",
61
+ "test/test_EC2_products.rb",
62
+ "test/test_EC2_responses.rb",
63
+ "test/test_EC2_s3_xmlsimple.rb",
64
+ "test/test_EC2_security_groups.rb",
65
+ "test/test_EC2_snapshots.rb",
66
+ "test/test_EC2_volumes.rb",
67
+ "test/test_ELB_load_balancers.rb",
68
+ "test/test_helper.rb",
69
+ "wsdl/2007-08-29.ec2.wsdl",
70
+ "wsdl/2008-02-01.ec2.wsdl",
71
+ "wsdl/2008-05-05.ec2.wsdl",
72
+ "wsdl/2008-12-01.ec2.wsdl"
73
+ ]
74
+ s.homepage = %q{http://github.com/grempe/amazon-ec2}
75
+ s.rdoc_options = ["--quiet", "--title", "amazon-ec2 documentation", "--opname", "index.html", "--line-numbers", "--main", "README.rdoc", "--inline-source"]
76
+ s.require_paths = ["lib"]
77
+ s.rubyforge_project = %q{amazon-ec2}
78
+ s.rubygems_version = %q{1.3.4}
79
+ s.summary = %q{Amazon EC2 Ruby Gem}
80
+ s.test_files = [
81
+ "test/test_EC2.rb",
82
+ "test/test_EC2_availability_zones.rb",
83
+ "test/test_EC2_console.rb",
84
+ "test/test_EC2_elastic_ips.rb",
85
+ "test/test_EC2_image_attributes.rb",
86
+ "test/test_EC2_images.rb",
87
+ "test/test_EC2_instances.rb",
88
+ "test/test_EC2_keypairs.rb",
89
+ "test/test_EC2_products.rb",
90
+ "test/test_EC2_responses.rb",
91
+ "test/test_EC2_s3_xmlsimple.rb",
92
+ "test/test_EC2_security_groups.rb",
93
+ "test/test_EC2_snapshots.rb",
94
+ "test/test_EC2_volumes.rb",
95
+ "test/test_ELB_load_balancers.rb",
96
+ "test/test_helper.rb"
97
+ ]
98
+
99
+ if s.respond_to? :specification_version then
100
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
101
+ s.specification_version = 3
102
+
103
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
104
+ s.add_runtime_dependency(%q<xml-simple>, [">= 1.0.12"])
105
+ s.add_development_dependency(%q<mocha>, [">= 0.9.5"])
106
+ s.add_development_dependency(%q<test-spec>, [">= 0.10.0"])
107
+ s.add_development_dependency(%q<rcov>, [">= 0.8.1.2.0"])
108
+ s.add_development_dependency(%q<perftools.rb>, ["= 0.1.6"])
109
+ else
110
+ s.add_dependency(%q<xml-simple>, [">= 1.0.12"])
111
+ s.add_dependency(%q<mocha>, [">= 0.9.5"])
112
+ s.add_dependency(%q<test-spec>, [">= 0.10.0"])
113
+ s.add_dependency(%q<rcov>, [">= 0.8.1.2.0"])
114
+ s.add_dependency(%q<perftools.rb>, ["= 0.1.6"])
115
+ end
116
+ else
117
+ s.add_dependency(%q<xml-simple>, [">= 1.0.12"])
118
+ s.add_dependency(%q<mocha>, [">= 0.9.5"])
119
+ s.add_dependency(%q<test-spec>, [">= 0.10.0"])
120
+ s.add_dependency(%q<rcov>, [">= 0.8.1.2.0"])
121
+ s.add_dependency(%q<perftools.rb>, ["= 0.1.6"])
122
+ end
123
+ end
@@ -0,0 +1,66 @@
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:glenn@rempe.us)
7
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
8
+ # License:: Distributes under the same terms as Ruby
9
+ # Home:: http://github.com/grempe/amazon-ec2/tree/master
10
+ #++
11
+
12
+ require File.dirname(__FILE__) + '/../lib/AWS'
13
+ require 'pp'
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
+ # us-east-1.ec2.amazonaws.com == ec2.amazonaws.com
33
+ # eu-west-1.ec2.amazonaws.com for the european region
34
+ # test different servers by running something like:
35
+ # export EC2_URL='https://ec2.amazonaws.com';./bin/ec2-gem-example.rb
36
+ if ENV['EC2_URL']
37
+ ec2 = AWS::EC2::Base.new( :access_key_id => ACCESS_KEY_ID, :secret_access_key => SECRET_ACCESS_KEY, :server => URI.parse(ENV['EC2_URL']).host )
38
+ else
39
+ # default server is US ec2.amazonaws.com
40
+ ec2 = AWS::EC2::Base.new( :access_key_id => ACCESS_KEY_ID, :secret_access_key => SECRET_ACCESS_KEY )
41
+ end
42
+
43
+ puts "----- ec2.methods.sort -----"
44
+ p ec2.methods.sort
45
+
46
+ puts "----- listing images owned by 'amazon' -----"
47
+ ec2.describe_images(:owner_id => "amazon").imagesSet.item.each do |image|
48
+ image.keys.each do |key|
49
+ puts "#{key} => #{image[key]}"
50
+ end
51
+ end
52
+
53
+ puts "----- listing all running instances -----"
54
+ pp ec2.describe_instances()
55
+
56
+ puts "----- creating a security group -----"
57
+ pp ec2.create_security_group(:group_name => "ec2-example-rb-test-group", :group_description => "ec-example.rb test group description.")
58
+
59
+ puts "----- listing security groups -----"
60
+ pp ec2.describe_security_groups()
61
+
62
+ puts "----- deleting a security group -----"
63
+ pp ec2.delete_security_group(:group_name => "ec2-example-rb-test-group")
64
+
65
+ puts "----- listing my keypairs (verbose mode) -----"
66
+ pp ec2.describe_keypairs()
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Basic single command application that we can call with perftools.rb to get consistent results.
4
+
5
+ require File.dirname(__FILE__) + '/../lib/AWS'
6
+ ACCESS_KEY_ID = ENV['AMAZON_ACCESS_KEY_ID']
7
+ SECRET_ACCESS_KEY = ENV['AMAZON_SECRET_ACCESS_KEY']
8
+ ec2 = AWS::EC2::Base.new( :access_key_id => ACCESS_KEY_ID, :secret_access_key => SECRET_ACCESS_KEY )
9
+ @images = ec2.describe_images
10
+
@@ -0,0 +1,62 @@
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:glenn@rempe.us)
7
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
8
+ # License:: Distributes under the same terms as Ruby
9
+ # Home:: http://github.com/grempe/amazon-ec2/tree/master
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
+ # => [#<AWS::EC2::Item image_location...
23
+
24
+ aws_lib = File.dirname(__FILE__) + '/../lib/AWS'
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.
42
+
43
+ Examples to try:
44
+
45
+ returns : all ec2 public methods
46
+ >> @ec2.methods.sort
47
+
48
+ returns : a string representation of ALL images
49
+ >> @ec2.describe_images.to_s
50
+
51
+ returns : an Array of AWS::Response objects, each an EC2 image and its data
52
+ >> @ec2.describe_images.imagesSet.item
53
+ >> @ec2.describe_images.imagesSet.item[0] (a hash representing a single item in that array)
54
+ >> @ec2.describe_images.imagesSet.item[0].to_s (a String representation of that item)
55
+
56
+ MESSAGE
57
+
58
+ puts welcome_message
59
+ exec "#{irb_name} -r #{aws_lib} -r #{setup} --simple-prompt"
60
+ else
61
+ puts "You must define AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY as shell environment variables before running #{$0}!"
62
+ end
@@ -0,0 +1,26 @@
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:glenn@rempe.us)
7
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
8
+ # License:: Distributes under the same terms as Ruby
9
+ # Home:: http://github.com/grempe/amazon-ec2/tree/master
10
+ #++
11
+
12
+ if ENV['AMAZON_ACCESS_KEY_ID'] && ENV['AMAZON_SECRET_ACCESS_KEY']
13
+ opts = {
14
+ :access_key_id => ENV['AMAZON_ACCESS_KEY_ID'],
15
+ :secret_access_key => ENV['AMAZON_SECRET_ACCESS_KEY']
16
+ }
17
+ if ENV['EC2_URL']
18
+ opts[:server] = URI.parse(ENV['EC2_URL']).host
19
+ end
20
+ @ec2 = AWS::EC2::Base.new(opts)
21
+ @elb = AWS::ELB::Base.new(opts)
22
+ end
23
+
24
+ puts "EC2 Server: #{opts[:server]}"
25
+
26
+ include AWS
@@ -0,0 +1 @@
1
+ xml-simple 1.0.12
@@ -0,0 +1,239 @@
1
+ # Require any lib files that we have bundled with this Ruby Gem in the lib/AWS directory.
2
+ # Parts of the AWS module and Base class are broken out into separate
3
+ # files for maintainability and are organized by the functional groupings defined
4
+ # in the AWS API developers guide.
5
+
6
+
7
+ %w[ base64 cgi openssl digest/sha1 net/https rexml/document time ostruct ].each { |f| require f }
8
+
9
+ module AWS
10
+ # Builds the canonical string for signing. This strips out all '&', '?', and '='
11
+ # from the query string to be signed.
12
+ # Note: The parameters in the path passed in must already be sorted in
13
+ # case-insensitive alphabetical order and must not be url encoded.
14
+ def AWS.canonical_string(params, host, method="POST", base="/")
15
+ # Sort, and encode parameters into a canonical string.
16
+ sorted_params = params.sort {|x,y| x[0] <=> y[0]}
17
+ encoded_params = sorted_params.collect do |p|
18
+ encoded = (CGI::escape(p[0].to_s) +
19
+ "=" + CGI::escape(p[1].to_s))
20
+ # Ensure spaces are encoded as '%20', not '+'
21
+ encoded.gsub('+', '%20')
22
+ end
23
+ sigquery = encoded_params.join("&")
24
+
25
+ # Generate the request description string
26
+ req_desc =
27
+ method + "\n" +
28
+ host + "\n" +
29
+ base + "\n" +
30
+ sigquery
31
+
32
+ end
33
+
34
+ # Encodes the given string with the secret_access_key, by taking the
35
+ # hmac-sha1 sum, and then base64 encoding it. Optionally, it will also
36
+ # url encode the result of that to protect the string if it's going to
37
+ # be used as a query string parameter.
38
+ def AWS.encode(secret_access_key, str, urlencode=true)
39
+ digest = OpenSSL::Digest::Digest.new('sha1')
40
+ b64_hmac =
41
+ Base64.encode64(
42
+ OpenSSL::HMAC.digest(digest, secret_access_key, str)).gsub("\n","")
43
+
44
+ if urlencode
45
+ return CGI::escape(b64_hmac)
46
+ else
47
+ return b64_hmac
48
+ end
49
+ end
50
+
51
+ class Base
52
+
53
+ attr_reader :use_ssl, :server, :proxy_server, :port
54
+
55
+ def initialize( options = {} )
56
+
57
+ options = { :access_key_id => "",
58
+ :secret_access_key => "",
59
+ :use_ssl => true,
60
+ :server => default_host,
61
+ :proxy_server => nil
62
+ }.merge(options)
63
+
64
+ @server = options[:server]
65
+ @proxy_server = options[:proxy_server]
66
+ @use_ssl = options[:use_ssl]
67
+
68
+ raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
69
+ raise ArgumentError, "No :secret_access_key provided" if options[:secret_access_key].nil? || options[:secret_access_key].empty?
70
+ raise ArgumentError, "No :use_ssl value provided" if options[:use_ssl].nil?
71
+ raise ArgumentError, "Invalid :use_ssl value provided, only 'true' or 'false' allowed" unless options[:use_ssl] == true || options[:use_ssl] == false
72
+ raise ArgumentError, "No :server provided" if options[:server].nil? || options[:server].empty?
73
+
74
+ if options[:port]
75
+ # user-specified port
76
+ @port = options[:port]
77
+ elsif @use_ssl
78
+ # https
79
+ @port = 443
80
+ else
81
+ # http
82
+ @port = 80
83
+ end
84
+
85
+ @access_key_id = options[:access_key_id]
86
+ @secret_access_key = options[:secret_access_key]
87
+
88
+ # Use proxy server if defined
89
+ # Based on patch by Mathias Dalheimer. 20070217
90
+ proxy = @proxy_server ? URI.parse(@proxy_server) : OpenStruct.new
91
+ @http = Net::HTTP::Proxy( proxy.host,
92
+ proxy.port,
93
+ proxy.user,
94
+ proxy.password).new(options[:server], @port)
95
+
96
+ @http.use_ssl = @use_ssl
97
+
98
+ # Don't verify the SSL certificates. Avoids SSL Cert warning in log on every GET.
99
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
100
+
101
+ end
102
+
103
+
104
+ protected
105
+
106
+ # pathlist is a utility method which takes a key string and and array as input.
107
+ # It converts the array into a Hash with the hash key being 'Key.n' where
108
+ # 'n' increments by 1 for each iteration. So if you pass in args
109
+ # ("ImageId", ["123", "456"]) you should get
110
+ # {"ImageId.1"=>"123", "ImageId.2"=>"456"} returned.
111
+ def pathlist(key, arr)
112
+ params = {}
113
+ arr.each_with_index do |value, i|
114
+ params["#{key}.#{i+1}"] = value
115
+ end
116
+ params
117
+ end
118
+
119
+ # Same as _pathlist_ except it deals with arrays of hashes.
120
+ # So if you pass in args
121
+ # ("People", [{:name=>'jon', :age=>'22'}, {:name=>'chris'}], {:name => 'Name', :age => 'Age'}) you should get
122
+ # {"People.1.Name"=>"jon", "People.1.Age"=>'22', 'People.2.Name'=>'chris'}
123
+ def pathhashlist(key, arr_of_hashes, mappings)
124
+ params ={}
125
+ arr_of_hashes.each_with_index do |hash, i|
126
+ hash.each do |attribute, value|
127
+ params["#{key}.#{i+1}.#{mappings[attribute]}"] = value
128
+ end
129
+ end
130
+ params
131
+ end
132
+
133
+ # Make the connection to AWS EC2 passing in our request. This is generally called from
134
+ # within a 'Response' class object or one of its sub-classes so the response is interpreted
135
+ # in its proper context. See lib/EC2/responses.rb
136
+ def make_request(action, params, data='')
137
+
138
+ @http.start do
139
+
140
+ # remove any keys that have nil or empty values
141
+ params.reject! { |key, value| value.nil? or value.empty?}
142
+
143
+ params.merge!( {"Action" => action,
144
+ "SignatureVersion" => "2",
145
+ "SignatureMethod" => 'HmacSHA1',
146
+ "AWSAccessKeyId" => @access_key_id,
147
+ "Version" => api_version,
148
+ "Timestamp"=>Time.now.getutc.iso8601} )
149
+
150
+ sig = get_aws_auth_param(params, @secret_access_key, @server)
151
+
152
+ query = params.sort.collect do |param|
153
+ CGI::escape(param[0]) + "=" + CGI::escape(param[1])
154
+ end.join("&") + "&Signature=" + sig
155
+
156
+ req = Net::HTTP::Post.new("/")
157
+ req.content_type = 'application/x-www-form-urlencoded'
158
+ req['User-Agent'] = "github-amazon-ec2-ruby-gem"
159
+ response = @http.request(req, query)
160
+
161
+ # Make a call to see if we need to throw an error based on the response given by EC2
162
+ # All error classes are defined in EC2/exceptions.rb
163
+ aws_error?(response)
164
+
165
+ return response
166
+
167
+ end
168
+
169
+ end
170
+
171
+ # Set the Authorization header using AWS signed header authentication
172
+ def get_aws_auth_param(params, secret_access_key, server)
173
+ canonical_string = AWS.canonical_string(params, server)
174
+ encoded_canonical = AWS.encode(secret_access_key, canonical_string)
175
+ end
176
+
177
+ # allow us to have a one line call in each method which will do all of the work
178
+ # in making the actual request to AWS.
179
+ def response_generator( options = {} )
180
+
181
+ options = {
182
+ :action => "",
183
+ :params => {}
184
+ }.merge(options)
185
+
186
+ raise ArgumentError, ":action must be provided to response_generator" if options[:action].nil? || options[:action].empty?
187
+
188
+ http_response = make_request(options[:action], options[:params])
189
+ http_xml = http_response.body
190
+ return Response.parse(:xml => http_xml)
191
+
192
+ end
193
+
194
+ # Raises the appropriate error if the specified Net::HTTPResponse object
195
+ # contains an Amazon EC2 error; returns +false+ otherwise.
196
+ def aws_error?(response)
197
+
198
+ # return false if we got a HTTP 200 code,
199
+ # otherwise there is some type of error (40x,50x) and
200
+ # we should try to raise an appropriate exception
201
+ # from one of our exception classes defined in
202
+ # exceptions.rb
203
+ return false if response.is_a?(Net::HTTPSuccess)
204
+
205
+ # parse the XML document so we can walk through it
206
+ doc = REXML::Document.new(response.body)
207
+
208
+ # Check that the Error element is in the place we would expect.
209
+ # and if not raise a generic error exception
210
+ if doc.root.elements['Error']
211
+ error_element = doc.root.elements['Error']
212
+ elsif doc.root.elements['Errors'] && doc.root.elements['Errors'].elements['Error'] && doc.root.elements['Errors'].elements['Error'].name == 'Error'
213
+ error_element = doc.root.elements['Errors'].elements['Error']
214
+ else
215
+ raise Error, "Unexpected error format. response.body is: #{response.body}"
216
+ end
217
+
218
+ # An valid error response looks like this:
219
+ # <?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>
220
+ # AWS EC2 throws some exception codes that look like Error.SubError. Since we can't name classes this way
221
+ # we need to strip out the '.' in the error 'Code' and we name the error exceptions with this
222
+ # non '.' name as well.
223
+ error_code = error_element.elements['Code'].text.gsub('.', '')
224
+ error_message = error_element.elements['Message'].text
225
+
226
+ # Raise one of our specific error classes if it exists.
227
+ # otherwise, throw a generic EC2 Error with a few details.
228
+ if AWS.const_defined?(error_code)
229
+ raise AWS.const_get(error_code), error_message
230
+ else
231
+ raise AWS::Error, error_message
232
+ end
233
+
234
+ end
235
+
236
+ end
237
+ end
238
+
239
+ Dir[File.join(File.dirname(__FILE__), 'AWS/*.rb')].sort.each { |lib| require lib }