awsum 0.5

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 (127) hide show
  1. data/.autotest +1 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +15 -0
  5. data/Gemfile.lock +44 -0
  6. data/LICENSE +19 -0
  7. data/README.rdoc +42 -0
  8. data/Rakefile +75 -0
  9. data/awsum.gemspec +199 -0
  10. data/lib/awsum.rb +20 -0
  11. data/lib/awsum/ec2.rb +741 -0
  12. data/lib/awsum/ec2/address.rb +67 -0
  13. data/lib/awsum/ec2/availability_zone.rb +16 -0
  14. data/lib/awsum/ec2/image.rb +62 -0
  15. data/lib/awsum/ec2/instance.rb +57 -0
  16. data/lib/awsum/ec2/keypair.rb +16 -0
  17. data/lib/awsum/ec2/parsers/address_parser.rb +61 -0
  18. data/lib/awsum/ec2/parsers/availability_zone_parser.rb +57 -0
  19. data/lib/awsum/ec2/parsers/image_parser.rb +74 -0
  20. data/lib/awsum/ec2/parsers/instance_parser.rb +90 -0
  21. data/lib/awsum/ec2/parsers/keypair_parser.rb +64 -0
  22. data/lib/awsum/ec2/parsers/purchase_reserved_instances_offering_parser.rb +34 -0
  23. data/lib/awsum/ec2/parsers/region_parser.rb +56 -0
  24. data/lib/awsum/ec2/parsers/register_image_parser.rb +34 -0
  25. data/lib/awsum/ec2/parsers/reserved_instance_parser.rb +64 -0
  26. data/lib/awsum/ec2/parsers/reserved_instances_offering_parser.rb +63 -0
  27. data/lib/awsum/ec2/parsers/security_group_parser.rb +106 -0
  28. data/lib/awsum/ec2/parsers/snapshot_parser.rb +64 -0
  29. data/lib/awsum/ec2/parsers/volume_parser.rb +77 -0
  30. data/lib/awsum/ec2/region.rb +54 -0
  31. data/lib/awsum/ec2/reserved_instance.rb +24 -0
  32. data/lib/awsum/ec2/reserved_instances_offering.rb +20 -0
  33. data/lib/awsum/ec2/security_group.rb +74 -0
  34. data/lib/awsum/ec2/snapshot.rb +23 -0
  35. data/lib/awsum/ec2/volume.rb +65 -0
  36. data/lib/awsum/error.rb +53 -0
  37. data/lib/awsum/net_fix.rb +100 -0
  38. data/lib/awsum/parser.rb +18 -0
  39. data/lib/awsum/requestable.rb +216 -0
  40. data/lib/awsum/s3.rb +220 -0
  41. data/lib/awsum/s3/bucket.rb +28 -0
  42. data/lib/awsum/s3/headers.rb +24 -0
  43. data/lib/awsum/s3/object.rb +138 -0
  44. data/lib/awsum/s3/parsers/bucket_parser.rb +43 -0
  45. data/lib/awsum/support.rb +94 -0
  46. data/spec/fixtures/ec2/addresses.xml +10 -0
  47. data/spec/fixtures/ec2/allocate_address.xml +5 -0
  48. data/spec/fixtures/ec2/associate_address.xml +5 -0
  49. data/spec/fixtures/ec2/attach_volume.xml +9 -0
  50. data/spec/fixtures/ec2/authorize_ip_access.xml +5 -0
  51. data/spec/fixtures/ec2/authorize_owner_group_access.xml +5 -0
  52. data/spec/fixtures/ec2/authorize_owner_group_access_error.xml +2 -0
  53. data/spec/fixtures/ec2/availability_zones.xml +16 -0
  54. data/spec/fixtures/ec2/available_volume.xml +14 -0
  55. data/spec/fixtures/ec2/create_key_pair.xml +29 -0
  56. data/spec/fixtures/ec2/create_security_group.xml +5 -0
  57. data/spec/fixtures/ec2/create_snapshot.xml +9 -0
  58. data/spec/fixtures/ec2/create_volume.xml +10 -0
  59. data/spec/fixtures/ec2/delete_key_pair.xml +5 -0
  60. data/spec/fixtures/ec2/delete_security_group.xml +5 -0
  61. data/spec/fixtures/ec2/delete_snapshot.xml +5 -0
  62. data/spec/fixtures/ec2/delete_volume.xml +5 -0
  63. data/spec/fixtures/ec2/deregister_image.xml +5 -0
  64. data/spec/fixtures/ec2/detach_volume.xml +9 -0
  65. data/spec/fixtures/ec2/disassociate_address.xml +5 -0
  66. data/spec/fixtures/ec2/image.xml +15 -0
  67. data/spec/fixtures/ec2/images.xml +77 -0
  68. data/spec/fixtures/ec2/instance.xml +36 -0
  69. data/spec/fixtures/ec2/instances.xml +88 -0
  70. data/spec/fixtures/ec2/internal_error.xml +2 -0
  71. data/spec/fixtures/ec2/invalid_amiid_error.xml +2 -0
  72. data/spec/fixtures/ec2/invalid_request_error.xml +2 -0
  73. data/spec/fixtures/ec2/key_pairs.xml +10 -0
  74. data/spec/fixtures/ec2/purchase_reserved_instances_offering.xml +5 -0
  75. data/spec/fixtures/ec2/purchase_reserved_instances_offerings.xml +6 -0
  76. data/spec/fixtures/ec2/regions.xml +14 -0
  77. data/spec/fixtures/ec2/register_image.xml +5 -0
  78. data/spec/fixtures/ec2/release_address.xml +5 -0
  79. data/spec/fixtures/ec2/reserved_instances.xml +18 -0
  80. data/spec/fixtures/ec2/reserved_instances_offering.xml +15 -0
  81. data/spec/fixtures/ec2/reserved_instances_offerings.xml +276 -0
  82. data/spec/fixtures/ec2/revoke_ip_access.xml +5 -0
  83. data/spec/fixtures/ec2/revoke_owner_group_access.xml +5 -0
  84. data/spec/fixtures/ec2/run_instances.xml +30 -0
  85. data/spec/fixtures/ec2/security_groups.xml +159 -0
  86. data/spec/fixtures/ec2/snapshots.xml +13 -0
  87. data/spec/fixtures/ec2/terminate_instances.xml +17 -0
  88. data/spec/fixtures/ec2/unassociated_address.xml +10 -0
  89. data/spec/fixtures/ec2/volumes.xml +23 -0
  90. data/spec/fixtures/errors/invalid_parameter_value.xml +2 -0
  91. data/spec/fixtures/s3/buckets.xml +2 -0
  92. data/spec/fixtures/s3/copy_failure.xml +23 -0
  93. data/spec/fixtures/s3/invalid_request_signature.xml +5 -0
  94. data/spec/fixtures/s3/keys.xml +2 -0
  95. data/spec/lib/awsum/ec2/address_spec.rb +149 -0
  96. data/spec/lib/awsum/ec2/availability_zones_spec.rb +21 -0
  97. data/spec/lib/awsum/ec2/image_spec.rb +92 -0
  98. data/spec/lib/awsum/ec2/instance_spec.rb +125 -0
  99. data/spec/lib/awsum/ec2/keypair_spec.rb +55 -0
  100. data/spec/lib/awsum/ec2/parsers/address_parser_spec.rb +51 -0
  101. data/spec/lib/awsum/ec2/parsers/availability_zone_parser_spec.rb +28 -0
  102. data/spec/lib/awsum/ec2/parsers/image_parser_spec.rb +66 -0
  103. data/spec/lib/awsum/ec2/parsers/instance_parser_spec.rb +75 -0
  104. data/spec/lib/awsum/ec2/parsers/keypair_parser_spec.rb +74 -0
  105. data/spec/lib/awsum/ec2/parsers/purchase_reserved_instances_offering_parser_spec.rb +14 -0
  106. data/spec/lib/awsum/ec2/parsers/region_parser_spec.rb +27 -0
  107. data/spec/lib/awsum/ec2/parsers/register_image_parser_spec.rb +15 -0
  108. data/spec/lib/awsum/ec2/parsers/reserved_instance_parser_spec.rb +35 -0
  109. data/spec/lib/awsum/ec2/parsers/reserved_instances_offering_parser_spec.rb +32 -0
  110. data/spec/lib/awsum/ec2/parsers/security_group_parser_spec.rb +78 -0
  111. data/spec/lib/awsum/ec2/parsers/snapshot_parser_spec.rb +30 -0
  112. data/spec/lib/awsum/ec2/parsers/volume_parser_spec.rb +35 -0
  113. data/spec/lib/awsum/ec2/region_spec.rb +73 -0
  114. data/spec/lib/awsum/ec2/reserved_instance_spec.rb +61 -0
  115. data/spec/lib/awsum/ec2/reserved_instances_offering_spec.rb +33 -0
  116. data/spec/lib/awsum/ec2/security_group_spec.rb +179 -0
  117. data/spec/lib/awsum/ec2/snapshots_spec.rb +69 -0
  118. data/spec/lib/awsum/ec2/volume_spec.rb +107 -0
  119. data/spec/lib/awsum/ec2_spec.rb +6 -0
  120. data/spec/lib/awsum/error_spec.rb +31 -0
  121. data/spec/lib/awsum/requestable_spec.rb +126 -0
  122. data/spec/lib/awsum/s3/bucket_spec.rb +95 -0
  123. data/spec/lib/awsum/s3/object_spec.rb +128 -0
  124. data/spec/lib/awsum/s3/parsers/bucket_parser_spec.rb +41 -0
  125. data/spec/lib/awsum/s3/parsers/object_parser_spec.rb +41 -0
  126. data/spec/spec_helper.rb +16 -0
  127. metadata +240 -0
@@ -0,0 +1 @@
1
+ require 'autotest/redgreen'
@@ -0,0 +1,5 @@
1
+ doc
2
+ *.swp
3
+ coverage
4
+ .bundle/
5
+ pkg/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rake"
4
+ gem "bundler", "~> 1.0.0"
5
+
6
+ group :development do
7
+ gem "jeweler"
8
+ gem "rspec", ">= 2.0.0.beta.22"
9
+ gem "fakeweb"
10
+
11
+ gem "shoulda"
12
+ gem "mocha"
13
+ gem "rcov"
14
+ gem "timecop"
15
+ end
@@ -0,0 +1,44 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ fakeweb (1.2.8)
6
+ gemcutter (0.6.1)
7
+ git (1.2.5)
8
+ jeweler (1.4.0)
9
+ gemcutter (>= 0.1.0)
10
+ git (>= 1.2.5)
11
+ rubyforge (>= 2.0.0)
12
+ json_pure (1.4.6)
13
+ mocha (0.9.8)
14
+ rake
15
+ rake (0.8.7)
16
+ rcov (0.9.9)
17
+ rspec (2.0.0.beta.22)
18
+ rspec-core (= 2.0.0.beta.22)
19
+ rspec-expectations (= 2.0.0.beta.22)
20
+ rspec-mocks (= 2.0.0.beta.22)
21
+ rspec-core (2.0.0.beta.22)
22
+ rspec-expectations (2.0.0.beta.22)
23
+ diff-lcs (>= 1.1.2)
24
+ rspec-mocks (2.0.0.beta.22)
25
+ rspec-core (= 2.0.0.beta.22)
26
+ rspec-expectations (= 2.0.0.beta.22)
27
+ rubyforge (2.0.4)
28
+ json_pure (>= 1.1.7)
29
+ shoulda (2.11.3)
30
+ timecop (0.3.5)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ bundler (~> 1.0.0)
37
+ fakeweb
38
+ jeweler
39
+ mocha
40
+ rake
41
+ rcov
42
+ rspec (>= 2.0.0.beta.22)
43
+ shoulda
44
+ timecop
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 Internuity Ltd, Andrew Timberlake <andrew@andrewtimberlake.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,42 @@
1
+ =Awsum
2
+
3
+ Awsum (Pronounced Awesome) is a library for working with Amazon web services.
4
+ The concept of Awsum is to expose the AWS library is the most ruby way possible
5
+ allowing you to work with objects in a very natural way.
6
+
7
+ ==Quick Start
8
+
9
+ #Create a snapshot for every volume of every instance you own
10
+ ec2 = Awsum::Ec2.new(<access key>, <secret key>)
11
+ ec2.instances.each do |instance|
12
+ instance.volumes.each do |volume|
13
+ volume.create_snapshot
14
+ end
15
+ end
16
+
17
+ ==Working with different Regions
18
+ You can use blocks to wrap your calls for a specific Region
19
+ ec2.region('eu-west-1').use do
20
+ #Run an instance in the eu-west-1 region
21
+ run_instance(...)
22
+ end
23
+
24
+ ==Using the library on an EC2 instance
25
+
26
+ There are two methods specifically for using a library on an EC2 instance
27
+ Awsum::Ec2#me
28
+ Awsum::Ec2#user_data
29
+
30
+ To extend the quick start example, you could do
31
+
32
+ #Create a snapshot of every volume of the currently running instance
33
+ ec2 = Awsum::Ec2.new(<access key>, <secret key>)
34
+ ec2.me.volumes.each do |volume|
35
+ volume.create_snapshot
36
+ end
37
+
38
+ ==Note:
39
+
40
+ Awsum is currently under active development and only supports EC2 at the moment.
41
+
42
+ Once EC2 is complete, I will focus on S3, SQS, CloudSpace and then others
@@ -0,0 +1,75 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup(:default, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+
10
+ require 'rake/rdoctask'
11
+ require 'rake/testtask'
12
+
13
+ $LOAD_PATH.unshift('lib')
14
+ require 'awsum'
15
+
16
+ begin
17
+ require 'jeweler'
18
+
19
+ Jeweler::Tasks.new do |gem|
20
+ gem.name = 'awsum'
21
+ gem.summary = 'A library for working with Amazon Web Services in the most natural rubyish way'
22
+ gem.email = 'andrew@andrewtimberlake.com'
23
+ gem.homepage = 'http://andrewtimberlake.com/projects/awsum'
24
+ gem.authors = ['Andrew Timberlake']
25
+ gem.version = Awsum::VERSION
26
+
27
+ #gem.add_dependency
28
+ gem.add_development_dependency('rspec', '>= 2.0.0.beta.22')
29
+ end
30
+
31
+ Jeweler::GemcutterTasks.new
32
+
33
+ task :default => :spec
34
+ rescue LoadError
35
+ puts "Jeweler not available. Install it with: gem install jeweler"
36
+ end
37
+
38
+ desc 'Run code coverage'
39
+ task :coverage do |t|
40
+ puts `rcov -T #{Dir.glob('test/**/test_*.rb').join(' ')}`
41
+ end
42
+
43
+ desc 'Start an IRB session with all necessary files required.'
44
+ task :shell do |t|
45
+ chdir File.dirname(__FILE__)
46
+ exec 'irb -I lib/ -I lib/awsum -r rubygems -r awsum'
47
+ end
48
+
49
+ desc 'Generate documentation.'
50
+ Rake::RDocTask.new(:rdoc) do |rdoc|
51
+ rdoc.rdoc_dir = 'doc'
52
+ rdoc.title = 'AWSum'
53
+ rdoc.options << '--line-numbers' << '--inline-source'
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
57
+
58
+ desc 'Clean up files.'
59
+ task :clean do |t|
60
+ FileUtils.rm_rf "doc"
61
+ FileUtils.rm_rf "tmp"
62
+ FileUtils.rm_rf "pkg"
63
+ end
64
+
65
+ require 'rspec/core/rake_task'
66
+ RSpec::Core::RakeTask.new do |t|
67
+ t.pattern = "./spec/lib/**/*_spec.rb"
68
+ end
69
+
70
+ namespace :spec do
71
+ desc "Run RSpec integration code examples (LIVE runs against Amazon AWS)"
72
+ RSpec::Core::RakeTask.new(:integration) do |t|
73
+ t.pattern = "./spec/functional/**/*_spec.rb"
74
+ end
75
+ end
@@ -0,0 +1,199 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{awsum}
8
+ s.version = "0.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andrew Timberlake"]
12
+ s.date = %q{2010-09-19}
13
+ s.email = %q{andrew@andrewtimberlake.com}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".autotest",
20
+ ".gitignore",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "awsum.gemspec",
28
+ "lib/awsum.rb",
29
+ "lib/awsum/ec2.rb",
30
+ "lib/awsum/ec2/address.rb",
31
+ "lib/awsum/ec2/availability_zone.rb",
32
+ "lib/awsum/ec2/image.rb",
33
+ "lib/awsum/ec2/instance.rb",
34
+ "lib/awsum/ec2/keypair.rb",
35
+ "lib/awsum/ec2/parsers/address_parser.rb",
36
+ "lib/awsum/ec2/parsers/availability_zone_parser.rb",
37
+ "lib/awsum/ec2/parsers/image_parser.rb",
38
+ "lib/awsum/ec2/parsers/instance_parser.rb",
39
+ "lib/awsum/ec2/parsers/keypair_parser.rb",
40
+ "lib/awsum/ec2/parsers/purchase_reserved_instances_offering_parser.rb",
41
+ "lib/awsum/ec2/parsers/region_parser.rb",
42
+ "lib/awsum/ec2/parsers/register_image_parser.rb",
43
+ "lib/awsum/ec2/parsers/reserved_instance_parser.rb",
44
+ "lib/awsum/ec2/parsers/reserved_instances_offering_parser.rb",
45
+ "lib/awsum/ec2/parsers/security_group_parser.rb",
46
+ "lib/awsum/ec2/parsers/snapshot_parser.rb",
47
+ "lib/awsum/ec2/parsers/volume_parser.rb",
48
+ "lib/awsum/ec2/region.rb",
49
+ "lib/awsum/ec2/reserved_instance.rb",
50
+ "lib/awsum/ec2/reserved_instances_offering.rb",
51
+ "lib/awsum/ec2/security_group.rb",
52
+ "lib/awsum/ec2/snapshot.rb",
53
+ "lib/awsum/ec2/volume.rb",
54
+ "lib/awsum/error.rb",
55
+ "lib/awsum/net_fix.rb",
56
+ "lib/awsum/parser.rb",
57
+ "lib/awsum/requestable.rb",
58
+ "lib/awsum/s3.rb",
59
+ "lib/awsum/s3/bucket.rb",
60
+ "lib/awsum/s3/headers.rb",
61
+ "lib/awsum/s3/object.rb",
62
+ "lib/awsum/s3/parsers/bucket_parser.rb",
63
+ "lib/awsum/support.rb",
64
+ "spec/fixtures/ec2/addresses.xml",
65
+ "spec/fixtures/ec2/allocate_address.xml",
66
+ "spec/fixtures/ec2/associate_address.xml",
67
+ "spec/fixtures/ec2/attach_volume.xml",
68
+ "spec/fixtures/ec2/authorize_ip_access.xml",
69
+ "spec/fixtures/ec2/authorize_owner_group_access.xml",
70
+ "spec/fixtures/ec2/authorize_owner_group_access_error.xml",
71
+ "spec/fixtures/ec2/availability_zones.xml",
72
+ "spec/fixtures/ec2/available_volume.xml",
73
+ "spec/fixtures/ec2/create_key_pair.xml",
74
+ "spec/fixtures/ec2/create_security_group.xml",
75
+ "spec/fixtures/ec2/create_snapshot.xml",
76
+ "spec/fixtures/ec2/create_volume.xml",
77
+ "spec/fixtures/ec2/delete_key_pair.xml",
78
+ "spec/fixtures/ec2/delete_security_group.xml",
79
+ "spec/fixtures/ec2/delete_snapshot.xml",
80
+ "spec/fixtures/ec2/delete_volume.xml",
81
+ "spec/fixtures/ec2/deregister_image.xml",
82
+ "spec/fixtures/ec2/detach_volume.xml",
83
+ "spec/fixtures/ec2/disassociate_address.xml",
84
+ "spec/fixtures/ec2/image.xml",
85
+ "spec/fixtures/ec2/images.xml",
86
+ "spec/fixtures/ec2/instance.xml",
87
+ "spec/fixtures/ec2/instances.xml",
88
+ "spec/fixtures/ec2/internal_error.xml",
89
+ "spec/fixtures/ec2/invalid_amiid_error.xml",
90
+ "spec/fixtures/ec2/invalid_request_error.xml",
91
+ "spec/fixtures/ec2/key_pairs.xml",
92
+ "spec/fixtures/ec2/purchase_reserved_instances_offering.xml",
93
+ "spec/fixtures/ec2/purchase_reserved_instances_offerings.xml",
94
+ "spec/fixtures/ec2/regions.xml",
95
+ "spec/fixtures/ec2/register_image.xml",
96
+ "spec/fixtures/ec2/release_address.xml",
97
+ "spec/fixtures/ec2/reserved_instances.xml",
98
+ "spec/fixtures/ec2/reserved_instances_offering.xml",
99
+ "spec/fixtures/ec2/reserved_instances_offerings.xml",
100
+ "spec/fixtures/ec2/revoke_ip_access.xml",
101
+ "spec/fixtures/ec2/revoke_owner_group_access.xml",
102
+ "spec/fixtures/ec2/run_instances.xml",
103
+ "spec/fixtures/ec2/security_groups.xml",
104
+ "spec/fixtures/ec2/snapshots.xml",
105
+ "spec/fixtures/ec2/terminate_instances.xml",
106
+ "spec/fixtures/ec2/unassociated_address.xml",
107
+ "spec/fixtures/ec2/volumes.xml",
108
+ "spec/fixtures/errors/invalid_parameter_value.xml",
109
+ "spec/fixtures/s3/buckets.xml",
110
+ "spec/fixtures/s3/copy_failure.xml",
111
+ "spec/fixtures/s3/invalid_request_signature.xml",
112
+ "spec/fixtures/s3/keys.xml",
113
+ "spec/lib/awsum/ec2/address_spec.rb",
114
+ "spec/lib/awsum/ec2/availability_zones_spec.rb",
115
+ "spec/lib/awsum/ec2/image_spec.rb",
116
+ "spec/lib/awsum/ec2/instance_spec.rb",
117
+ "spec/lib/awsum/ec2/keypair_spec.rb",
118
+ "spec/lib/awsum/ec2/parsers/address_parser_spec.rb",
119
+ "spec/lib/awsum/ec2/parsers/availability_zone_parser_spec.rb",
120
+ "spec/lib/awsum/ec2/parsers/image_parser_spec.rb",
121
+ "spec/lib/awsum/ec2/parsers/instance_parser_spec.rb",
122
+ "spec/lib/awsum/ec2/parsers/keypair_parser_spec.rb",
123
+ "spec/lib/awsum/ec2/parsers/purchase_reserved_instances_offering_parser_spec.rb",
124
+ "spec/lib/awsum/ec2/parsers/region_parser_spec.rb",
125
+ "spec/lib/awsum/ec2/parsers/register_image_parser_spec.rb",
126
+ "spec/lib/awsum/ec2/parsers/reserved_instance_parser_spec.rb",
127
+ "spec/lib/awsum/ec2/parsers/reserved_instances_offering_parser_spec.rb",
128
+ "spec/lib/awsum/ec2/parsers/security_group_parser_spec.rb",
129
+ "spec/lib/awsum/ec2/parsers/snapshot_parser_spec.rb",
130
+ "spec/lib/awsum/ec2/parsers/volume_parser_spec.rb",
131
+ "spec/lib/awsum/ec2/region_spec.rb",
132
+ "spec/lib/awsum/ec2/reserved_instance_spec.rb",
133
+ "spec/lib/awsum/ec2/reserved_instances_offering_spec.rb",
134
+ "spec/lib/awsum/ec2/security_group_spec.rb",
135
+ "spec/lib/awsum/ec2/snapshots_spec.rb",
136
+ "spec/lib/awsum/ec2/volume_spec.rb",
137
+ "spec/lib/awsum/ec2_spec.rb",
138
+ "spec/lib/awsum/error_spec.rb",
139
+ "spec/lib/awsum/requestable_spec.rb",
140
+ "spec/lib/awsum/s3/bucket_spec.rb",
141
+ "spec/lib/awsum/s3/object_spec.rb",
142
+ "spec/lib/awsum/s3/parsers/bucket_parser_spec.rb",
143
+ "spec/lib/awsum/s3/parsers/object_parser_spec.rb",
144
+ "spec/spec_helper.rb"
145
+ ]
146
+ s.homepage = %q{http://andrewtimberlake.com/projects/awsum}
147
+ s.rdoc_options = ["--charset=UTF-8"]
148
+ s.require_paths = ["lib"]
149
+ s.rubygems_version = %q{1.3.7}
150
+ s.summary = %q{A library for working with Amazon Web Services in the most natural rubyish way}
151
+ s.test_files = [
152
+ "spec/lib/awsum/s3/parsers/object_parser_spec.rb",
153
+ "spec/lib/awsum/s3/parsers/bucket_parser_spec.rb",
154
+ "spec/lib/awsum/s3/object_spec.rb",
155
+ "spec/lib/awsum/s3/bucket_spec.rb",
156
+ "spec/lib/awsum/ec2/reserved_instance_spec.rb",
157
+ "spec/lib/awsum/ec2/region_spec.rb",
158
+ "spec/lib/awsum/ec2/availability_zones_spec.rb",
159
+ "spec/lib/awsum/ec2/parsers/register_image_parser_spec.rb",
160
+ "spec/lib/awsum/ec2/parsers/security_group_parser_spec.rb",
161
+ "spec/lib/awsum/ec2/parsers/image_parser_spec.rb",
162
+ "spec/lib/awsum/ec2/parsers/snapshot_parser_spec.rb",
163
+ "spec/lib/awsum/ec2/parsers/region_parser_spec.rb",
164
+ "spec/lib/awsum/ec2/parsers/availability_zone_parser_spec.rb",
165
+ "spec/lib/awsum/ec2/parsers/reserved_instance_parser_spec.rb",
166
+ "spec/lib/awsum/ec2/parsers/address_parser_spec.rb",
167
+ "spec/lib/awsum/ec2/parsers/purchase_reserved_instances_offering_parser_spec.rb",
168
+ "spec/lib/awsum/ec2/parsers/volume_parser_spec.rb",
169
+ "spec/lib/awsum/ec2/parsers/reserved_instances_offering_parser_spec.rb",
170
+ "spec/lib/awsum/ec2/parsers/keypair_parser_spec.rb",
171
+ "spec/lib/awsum/ec2/parsers/instance_parser_spec.rb",
172
+ "spec/lib/awsum/ec2/image_spec.rb",
173
+ "spec/lib/awsum/ec2/address_spec.rb",
174
+ "spec/lib/awsum/ec2/keypair_spec.rb",
175
+ "spec/lib/awsum/ec2/snapshots_spec.rb",
176
+ "spec/lib/awsum/ec2/volume_spec.rb",
177
+ "spec/lib/awsum/ec2/instance_spec.rb",
178
+ "spec/lib/awsum/ec2/security_group_spec.rb",
179
+ "spec/lib/awsum/ec2/reserved_instances_offering_spec.rb",
180
+ "spec/lib/awsum/ec2_spec.rb",
181
+ "spec/lib/awsum/error_spec.rb",
182
+ "spec/lib/awsum/requestable_spec.rb",
183
+ "spec/spec_helper.rb"
184
+ ]
185
+
186
+ if s.respond_to? :specification_version then
187
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
188
+ s.specification_version = 3
189
+
190
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
191
+ s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
192
+ else
193
+ s.add_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
194
+ end
195
+ else
196
+ s.add_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
197
+ end
198
+ end
199
+
@@ -0,0 +1,20 @@
1
+ # AWSum is a library facilitating access to Amazon's web services in (hopefully)
2
+ # a very object-oriented, ruby way.
3
+ #
4
+ # Author:: Andrew Timberlake
5
+ # Copyright:: Copyright (c) 2009 Internuity Ltd
6
+ # Licence:: MIT License (http://www.opensource.org/licenses/mit-license.php)
7
+ #
8
+
9
+ require 'awsum/parser'
10
+ require 'awsum/requestable'
11
+ require 'awsum/support'
12
+
13
+ module Awsum
14
+ VERSION = "0.5"
15
+
16
+ API_VERSION = '2010-06-15'
17
+ SIGNATURE_VERSION = 2
18
+ end
19
+
20
+
@@ -0,0 +1,741 @@
1
+ require 'awsum'
2
+ require 'awsum/ec2/address'
3
+ require 'awsum/ec2/availability_zone'
4
+ require 'awsum/ec2/image'
5
+ require 'awsum/ec2/instance'
6
+ require 'awsum/ec2/keypair'
7
+ require 'awsum/ec2/region'
8
+ require 'awsum/ec2/reserved_instance'
9
+ require 'awsum/ec2/reserved_instances_offering'
10
+ require 'awsum/ec2/security_group'
11
+ require 'awsum/ec2/snapshot'
12
+ require 'awsum/ec2/volume'
13
+
14
+ module Awsum
15
+ # Handles all interaction with Amazon EC2
16
+ #
17
+ # ==Getting Started
18
+ # Create an Awsum::Ec2 object and begin calling methods on it.
19
+ # require 'rubygems'
20
+ # require 'awsum'
21
+ # ec2 = Awsum::Ec2.new('your access id', 'your secret key')
22
+ # images = ec2.my_images
23
+ # ...
24
+ #
25
+ # All calls to EC2 can be done directly in this class, or through a more object oriented way through the various returned classes
26
+ #
27
+ # ==Examples
28
+ # ec2.image('ami-ABCDEF').run
29
+ #
30
+ # ec2.instance('i-123456789').volumes.each do |vol|
31
+ # vol.create_snapsot
32
+ # end
33
+ #
34
+ # ec2.regions.each do |region|
35
+ # region.use
36
+ # images.each do |img|
37
+ # puts "#{img.id} - #{region.name}"
38
+ # end
39
+ # end
40
+ # end
41
+ #
42
+ # ==Errors
43
+ # All methods will raise an Awsum::Error if an error is returned from Amazon
44
+ #
45
+ # ==Missing Methods
46
+ # * ConfirmProductInstance
47
+ # * ModifyImageAttribute
48
+ # * DescribeImageAttribute
49
+ # * ResetImageAttribute
50
+ # If you need any of this functionality, please consider getting involved and help complete this library.
51
+ class Ec2
52
+ include Awsum::Requestable
53
+
54
+ # Create an new ec2 instance
55
+ #
56
+ # The access_key and secret_key are both required to do any meaningful work.
57
+ #
58
+ # If you want to get these keys from environment variables, you can do that in your code as follows:
59
+ # ec2 = Awsum::Ec2.new(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'])
60
+ def initialize(access_key = nil, secret_key = nil)
61
+ @access_key = access_key
62
+ @secret_key = secret_key
63
+ end
64
+
65
+ # Retrieve a list of available Images
66
+ #
67
+ # ===Options:
68
+ # * <tt>:image_ids</tt> - array of Image id's, default: []
69
+ # * <tt>:owners</tt> - array of owner id's, default: []
70
+ # * <tt>:executable_by</tt> - array of user id's who have executable permission, default: []
71
+ def images(options = {})
72
+ options = {:image_ids => [], :owners => [], :executable_by => []}.merge(options)
73
+ action = 'DescribeImages'
74
+ params = {
75
+ 'Action' => action
76
+ }
77
+ #Add options
78
+ params.merge!(array_to_params(options[:image_ids], "ImageId"))
79
+ params.merge!(array_to_params(options[:owners], "Owner"))
80
+ params.merge!(array_to_params(options[:executable_by], "ExecutableBy"))
81
+
82
+ response = send_query_request(params)
83
+ parser = Awsum::Ec2::ImageParser.new(self)
84
+ parser.parse(response.body)
85
+ end
86
+
87
+ # Retrieve all Image(s) owned by you
88
+ def my_images
89
+ images :owners => 'self'
90
+ end
91
+
92
+ # Retrieve a single Image
93
+ def image(image_id)
94
+ images(:image_ids => [image_id])[0]
95
+ end
96
+
97
+ # Register an Image
98
+ def register_image(image_location)
99
+ action = 'RegisterImage'
100
+ params = {
101
+ 'Action' => action,
102
+ 'ImageLocation' => image_location
103
+ }
104
+
105
+ response = send_query_request(params)
106
+ parser = Awsum::Ec2::RegisterImageParser.new(self)
107
+ parser.parse(response.body)
108
+ end
109
+
110
+ # Deregister an Image. Once deregistered, you can no longer launch the Image
111
+ def deregister_image(image_id)
112
+ action = 'DeregisterImage'
113
+ params = {
114
+ 'Action' => action,
115
+ 'ImageId' => image_id
116
+ }
117
+
118
+ response = send_query_request(params)
119
+ response.is_a?(Net::HTTPSuccess)
120
+ end
121
+
122
+ # Launch an ec2 Instance
123
+ #
124
+ # ===Options:
125
+ # * <tt>:min</tt> - The minimum number of instances to launch. Default: 1
126
+ # * <tt>:max</tt> - The maximum number of instances to launch. Default: 1
127
+ # * <tt>:key_name</tt> - The name of the key pair with which to launch instances
128
+ # * <tt>:security_groups</tt> - The names of security groups to associate launched instances with
129
+ # * <tt>:user_data</tt> - User data made available to instances (Note: Must be 16K or less, will be base64 encoded by Awsum)
130
+ # * <tt>:instance_type</tt> - The size of the instances to launch, can be one of [m1.small, m1.large, m1.xlarge, c1.medium, c1.xlarge], default is m1.small
131
+ # * <tt>:availability_zone</tt> - The name of the availability zone to launch this Instance in
132
+ # * <tt>:kernel_id</tt> - The ID of the kernel with which to launch instances
133
+ # * <tt>:ramdisk_id</tt> - The ID of the RAM disk with which to launch instances
134
+ # * <tt>:block_device_map</tt> - A 'hash' of mappings. E.g. {'instancestore0' => 'sdb'}
135
+ def run_instances(image_id, options = {})
136
+ options = {:min => 1, :max => 1}.merge(options)
137
+ action = 'RunInstances'
138
+ params = {
139
+ 'Action' => action,
140
+ 'ImageId' => image_id,
141
+ 'MinCount' => options[:min],
142
+ 'MaxCount' => options[:max],
143
+ 'KeyName' => options[:key_name],
144
+ 'UserData' => options[:user_data].nil? ? nil : Base64::encode64(options[:user_data]).gsub(/\n/, ''),
145
+ 'InstanceType' => options[:instance_type],
146
+ 'Placement.AvailabilityZone' => options[:availability_zone],
147
+ 'KernelId' => options[:kernel_id],
148
+ 'RamdiskId' => options[:ramdisk_id]
149
+ }
150
+ if options[:block_device_map].respond_to?(:keys)
151
+ map = options[:block_device_map]
152
+ map.keys.each_with_index do |key, i|
153
+ params["BlockDeviceMapping.#{i+1}.VirtualName"] = key
154
+ params["BlockDeviceMapping.#{i+1}.DeviceName"] = map[key]
155
+ end
156
+ else
157
+ raise ArgumentError.new("options[:block_device_map] - must be a key => value map") unless options[:block_device_map].nil?
158
+ end
159
+ params.merge!(array_to_params(options[:security_groups], "SecurityGroup"))
160
+
161
+ response = send_query_request(params)
162
+ parser = Awsum::Ec2::InstanceParser.new(self)
163
+ parser.parse(response.body)
164
+ end
165
+ alias_method :launch_instances, :run_instances
166
+
167
+ #Retrieve the information on a number of Instance(s)
168
+ def instances(*instance_ids)
169
+ action = 'DescribeInstances'
170
+ params = {
171
+ 'Action' => action
172
+ }
173
+ params.merge!(array_to_params(instance_ids, 'InstanceId'))
174
+
175
+ response = send_query_request(params)
176
+ parser = Awsum::Ec2::InstanceParser.new(self)
177
+ parser.parse(response.body)
178
+ end
179
+
180
+ #Retrieve the information on a single Instance
181
+ def instance(instance_id)
182
+ instances([instance_id])[0]
183
+ end
184
+
185
+ # Retrieves the currently running Instance
186
+ # This should only be run on a running EC2 instance
187
+ def me
188
+ require 'open-uri'
189
+ begin
190
+ instance_id = open('http://169.254.169.254/latest/meta-data/instance-id').read
191
+ instance instance_id
192
+ rescue OpenURI::HTTPError => e
193
+ nil
194
+ end
195
+ end
196
+
197
+ # Retreives the user-data supplied when starting the currently running Instance
198
+ # This should only be run on a running EC2 instance
199
+ def user_data
200
+ require 'open-uri'
201
+ begin
202
+ open('http://169.254.169.254/latest/user-data').read
203
+ rescue OpenURI::HTTPError => e
204
+ nil
205
+ end
206
+ end
207
+
208
+ # Terminates the Instance(s)
209
+ #
210
+ # Returns true if the terminations succeeds, false otherwise
211
+ def terminate_instances(*instance_ids)
212
+ action = 'TerminateInstances'
213
+ params = {
214
+ 'Action' => action
215
+ }
216
+ params.merge!(array_to_params(instance_ids, 'InstanceId'))
217
+
218
+ response = send_query_request(params)
219
+ response.is_a?(Net::HTTPSuccess)
220
+ end
221
+
222
+ #Retrieve the information on a number of Volume(s)
223
+ def volumes(*volume_ids)
224
+ action = 'DescribeVolumes'
225
+ params = {
226
+ 'Action' => action
227
+ }
228
+ params.merge!(array_to_params(volume_ids, 'VolumeId'))
229
+
230
+ response = send_query_request(params)
231
+ parser = Awsum::Ec2::VolumeParser.new(self)
232
+ parser.parse(response.body)
233
+ end
234
+
235
+ # Retreive information on a Volume
236
+ def volume(volume_id)
237
+ volumes(volume_id)[0]
238
+ end
239
+
240
+ # Create a new volume
241
+ #
242
+ # ===Options:
243
+ # * <tt>:size</tt> - The size of the volume to be created (in GB) (<b>NOTE:</b> Required if you are not creating from a snapshot)
244
+ # * <tt>:snapshot_id</tt> - The snapshot id from which to create the volume
245
+ #
246
+ def create_volume(availability_zone, options = {})
247
+ raise ArgumentError.new('You must specify a size if not creating a volume from a snapshot') if options[:snapshot_id].blank? && options[:size].blank?
248
+
249
+ action = 'CreateVolume'
250
+ params = {
251
+ 'Action' => action,
252
+ 'AvailabilityZone' => availability_zone
253
+ }
254
+ params['Size'] = options[:size] unless options[:size].blank?
255
+ params['SnapshotId'] = options[:snapshot_id] unless options[:snapshot_id].blank?
256
+
257
+ response = send_query_request(params)
258
+ parser = Awsum::Ec2::VolumeParser.new(self)
259
+ parser.parse(response.body)[0]
260
+ end
261
+
262
+ # Attach a volume to an instance
263
+ def attach_volume(volume_id, instance_id, device = '/dev/sdh')
264
+ action = 'AttachVolume'
265
+ params = {
266
+ 'Action' => action,
267
+ 'VolumeId' => volume_id,
268
+ 'InstanceId' => instance_id,
269
+ 'Device' => device
270
+ }
271
+
272
+ response = send_query_request(params)
273
+ response.is_a?(Net::HTTPSuccess)
274
+ end
275
+
276
+ # Detach a volume from an instance
277
+ #
278
+ # ===Options
279
+ # * <tt>:instance_id</tt> - The ID of the instance from which the volume will detach
280
+ # * <tt>:device</tt> - The device name
281
+ # * <tt>:force</tt> - Whether to force the detachment. <b>NOTE:</b> If forced you may have data corruption issues.
282
+ def detach_volume(volume_id, options = {})
283
+ action = 'DetachVolume'
284
+ params = {
285
+ 'Action' => action,
286
+ 'VolumeId' => volume_id
287
+ }
288
+ params['InstanceId'] = options[:instance_id] unless options[:instance_id].blank?
289
+ params['Device'] = options[:device] unless options[:device].blank?
290
+ params['Force'] = options[:force] unless options[:force].blank?
291
+
292
+ response = send_query_request(params)
293
+ response.is_a?(Net::HTTPSuccess)
294
+ end
295
+
296
+ # Delete a volume
297
+ def delete_volume(volume_id)
298
+ action = 'DeleteVolume'
299
+ params = {
300
+ 'Action' => action,
301
+ 'VolumeId' => volume_id
302
+ }
303
+
304
+ response = send_query_request(params)
305
+ response.is_a?(Net::HTTPSuccess)
306
+ end
307
+
308
+ # Create a Snapshot of a Volume
309
+ def create_snapshot(volume_id)
310
+ action = 'CreateSnapshot'
311
+ params = {
312
+ 'Action' => action,
313
+ 'VolumeId' => volume_id
314
+ }
315
+
316
+ response = send_query_request(params)
317
+ parser = Awsum::Ec2::SnapshotParser.new(self)
318
+ parser.parse(response.body)[0]
319
+ end
320
+
321
+ # List Snapshot(s)
322
+ def snapshots(*snapshot_ids)
323
+ action = 'DescribeSnapshots'
324
+ params = {
325
+ 'Action' => action
326
+ }
327
+ params.merge!(array_to_params(snapshot_ids, 'SnapshotId'))
328
+
329
+ response = send_query_request(params)
330
+ parser = Awsum::Ec2::SnapshotParser.new(self)
331
+ parser.parse(response.body)
332
+ end
333
+
334
+ # Get the information about a Snapshot
335
+ def snapshot(snapshot_id)
336
+ snapshots(snapshot_id)[0]
337
+ end
338
+
339
+ # Delete a Snapshot
340
+ def delete_snapshot(snapshot_id)
341
+ action = 'DeleteSnapshot'
342
+ params = {
343
+ 'Action' => action,
344
+ 'SnapshotId' => snapshot_id
345
+ }
346
+
347
+ response = send_query_request(params)
348
+ response.is_a?(Net::HTTPSuccess)
349
+ end
350
+
351
+ # List all AvailabilityZone(s)
352
+ def availability_zones(*zone_names)
353
+ action = 'DescribeAvailabilityZones'
354
+ params = {
355
+ 'Action' => action
356
+ }
357
+ params.merge!(array_to_params(zone_names, 'ZoneName'))
358
+
359
+ response = send_query_request(params)
360
+ parser = Awsum::Ec2::AvailabilityZoneParser.new(self)
361
+ parser.parse(response.body)
362
+ end
363
+
364
+ # List all Region(s)
365
+ def regions(*region_names)
366
+ action = 'DescribeRegions'
367
+ params = {
368
+ 'Action' => action
369
+ }
370
+ params.merge!(array_to_params(region_names, 'RegionName'))
371
+
372
+ response = send_query_request(params)
373
+ parser = Awsum::Ec2::RegionParser.new(self)
374
+ parser.parse(response.body)
375
+ end
376
+
377
+ # List a Region
378
+ def region(region_name, &block)
379
+ region = regions(region_name)[0]
380
+ if block_given?
381
+ region.use(&block)
382
+ else
383
+ region
384
+ end
385
+ end
386
+
387
+ # List Addresses
388
+ def addresses(*public_ips)
389
+ action = 'DescribeAddresses'
390
+ params = {
391
+ 'Action' => action
392
+ }
393
+ params.merge!(array_to_params(public_ips, 'PublicIp'))
394
+
395
+ response = send_query_request(params)
396
+ parser = Awsum::Ec2::AddressParser.new(self)
397
+ parser.parse(response.body)
398
+ end
399
+
400
+ # Get the Address with a specific public ip
401
+ def address(public_ip)
402
+ addresses(public_ip)[0]
403
+ end
404
+
405
+ # Allocate Address
406
+ #
407
+ # Will aquire an elastic ip address for use with your account
408
+ def allocate_address
409
+ action = 'AllocateAddress'
410
+ params = {
411
+ 'Action' => action
412
+ }
413
+
414
+ response = send_query_request(params)
415
+ parser = Awsum::Ec2::AddressParser.new(self)
416
+ parser.parse(response.body)[0]
417
+ end
418
+
419
+ # Associate Address
420
+ #
421
+ # Will link an allocated elastic ip address to an Instance
422
+ #
423
+ # <b>NOTE:</b> If the ip address is already associated with another instance, it will be associated with the new instance.
424
+ #
425
+ # You can run this command more than once and it will not return an error.
426
+ def associate_address(instance_id, public_ip)
427
+ action = 'AssociateAddress'
428
+ params = {
429
+ 'Action' => action,
430
+ 'InstanceId' => instance_id,
431
+ 'PublicIp' => public_ip
432
+ }
433
+
434
+ response = send_query_request(params)
435
+ response.is_a?(Net::HTTPSuccess)
436
+ end
437
+
438
+ # Disassociate Address
439
+ #
440
+ # Will disassociate an allocated elastic ip address from the Instance it's allocated to
441
+ #
442
+ # <b>NOTE:</b> You can run this command more than once and it will not return an error.
443
+ def disassociate_address(public_ip)
444
+ action = 'DisassociateAddress'
445
+ params = {
446
+ 'Action' => action,
447
+ 'PublicIp' => public_ip
448
+ }
449
+
450
+ response = send_query_request(params)
451
+ response.is_a?(Net::HTTPSuccess)
452
+ end
453
+
454
+ # Releases an associated Address
455
+ #
456
+ # <b>NOTE:</b> This is not a direct call to the Amazon web service. This is a safe operation that will first check to see if the address is allocated to an instance and fail if it is
457
+ # To ensure an address is released whether associated or not, use #release_address!
458
+ def release_address(public_ip)
459
+ address = address(public_ip)
460
+
461
+ if address.instance_id.nil?
462
+ action = 'ReleaseAddress'
463
+ params = {
464
+ 'Action' => action,
465
+ 'PublicIp' => public_ip
466
+ }
467
+
468
+ response = send_query_request(params)
469
+ response.is_a?(Net::HTTPSuccess)
470
+ else
471
+ raise 'Address is currently allocated' #FIXME: Add a proper Awsum error here
472
+ end
473
+ end
474
+
475
+ # Releases an associated Address
476
+ #
477
+ # <b>NOTE:</b> This will disassociate an address automatically if it is associated with an instance
478
+ def release_address!(public_ip)
479
+ action = 'ReleaseAddress'
480
+ params = {
481
+ 'Action' => action,
482
+ 'PublicIp' => public_ip
483
+ }
484
+
485
+ response = send_query_request(params)
486
+ response.is_a?(Net::HTTPSuccess)
487
+ end
488
+
489
+ # List KeyPair(s)
490
+ def key_pairs(*key_names)
491
+ action = 'DescribeKeyPairs'
492
+ params = {
493
+ 'Action' => action
494
+ }
495
+ params.merge!(array_to_params(key_names, 'KeyName'))
496
+
497
+ response = send_query_request(params)
498
+ parser = Awsum::Ec2::KeyPairParser.new(self)
499
+ parser.parse(response.body)
500
+ end
501
+
502
+ # Get a single KeyPair
503
+ def key_pair(key_name)
504
+ key_pairs(key_name)[0]
505
+ end
506
+
507
+ # Create a new KeyPair
508
+ def create_key_pair(key_name)
509
+ action = 'CreateKeyPair'
510
+ params = {
511
+ 'Action' => action,
512
+ 'KeyName' => key_name
513
+ }
514
+
515
+ response = send_query_request(params)
516
+ parser = Awsum::Ec2::KeyPairParser.new(self)
517
+ parser.parse(response.body)[0]
518
+ end
519
+
520
+ # Delete a KeyPair
521
+ def delete_key_pair(key_name)
522
+ action = 'DeleteKeyPair'
523
+ params = {
524
+ 'Action' => action,
525
+ 'KeyName' => key_name
526
+ }
527
+
528
+ response = send_query_request(params)
529
+ response.is_a?(Net::HTTPSuccess)
530
+ end
531
+
532
+ # List SecurityGroup(s)
533
+ def security_groups(*group_names)
534
+ action = 'DescribeSecurityGroups'
535
+ params = {
536
+ 'Action' => action
537
+ }
538
+ params.merge!(array_to_params(group_names, 'GroupName'))
539
+
540
+ response = send_query_request(params)
541
+ parser = Awsum::Ec2::SecurityGroupParser.new(self)
542
+ parser.parse(response.body)
543
+ end
544
+
545
+ # Get a single SecurityGroup
546
+ def security_group(group_name)
547
+ security_groups(group_name)[0]
548
+ end
549
+
550
+ # Create a new SecurityGroup
551
+ def create_security_group(name, description)
552
+ action = 'CreateSecurityGroup'
553
+ params = {
554
+ 'Action' => action,
555
+ 'GroupName' => name,
556
+ 'GroupDescription' => description
557
+ }
558
+
559
+ response = send_query_request(params)
560
+ response.is_a?(Net::HTTPSuccess)
561
+ end
562
+
563
+ # Delete a SecurityGroup
564
+ def delete_security_group(group_name)
565
+ action = 'DeleteSecurityGroup'
566
+ params = {
567
+ 'Action' => action,
568
+ 'GroupName' => group_name
569
+ }
570
+
571
+ response = send_query_request(params)
572
+ response.is_a?(Net::HTTPSuccess)
573
+ end
574
+
575
+ # Authorize access on a specific security group
576
+ #
577
+ # ===Options:
578
+ # ====User/Group access
579
+ # * <tt>:source_security_group_name</tt> - Name of the security group to authorize access to when operating on a user/group pair
580
+ # * <tt>:source_security_group_owner_id</tt> - Owner of the security group to authorize access to when operating on a user/group pair
581
+ # ====CIDR IP access
582
+ # * <tt>:ip_protocol</tt> - IP protocol to authorize access to when operating on a CIDR IP (tcp, udp or icmp) (default: tcp)
583
+ # * <tt>:from_port</tt> - Bottom of port range to authorize access to when operating on a CIDR IP. This contains the ICMP type if ICMP is being authorized.
584
+ # * <tt>:to_port</tt> - Top of port range to authorize access to when operating on a CIDR IP. This contains the ICMP type if ICMP is being authorized.
585
+ # * <tt>:cidr_ip</tt> - CIDR IP range to authorize access to when operating on a CIDR IP. (default: 0.0.0.0/0)
586
+ def authorize_security_group_ingress(group_name, options = {})
587
+ got_at_least_one_user_group_option = !options[:source_security_group_name].nil? || !options[:source_security_group_owner_id].nil?
588
+ got_user_group_options = !options[:source_security_group_name].nil? && !options[:source_security_group_owner_id].nil?
589
+ got_at_least_one_cidr_option = !options[:ip_protocol].nil? || !options[:from_port].nil? || !options[:to_port].nil? || !options[:cidr_ip].nil?
590
+ #Add in defaults
591
+ options = {:cidr_ip => '0.0.0.0/0'}.merge(options) if got_at_least_one_cidr_option
592
+ options = {:ip_protocol => 'tcp'}.merge(options) if got_at_least_one_cidr_option
593
+ got_cidr_options = !options[:ip_protocol].nil? && !options[:from_port].nil? && !options[:to_port].nil? && !options[:cidr_ip].nil?
594
+ raise ArgumentError.new('Can only authorize user/group or CIDR IP, not both') if got_at_least_one_user_group_option && got_at_least_one_cidr_option
595
+ raise ArgumentError.new('Need all user/group options when authorizing user/group access') if got_at_least_one_user_group_option && !got_user_group_options
596
+ raise ArgumentError.new('Need all CIDR IP options when authorizing CIDR IP access') if got_at_least_one_cidr_option && !got_cidr_options
597
+ raise ArgumentError.new('ip_protocol can only be one of tcp, udp or icmp') if got_at_least_one_cidr_option && !%w(tcp udp icmp).detect{|p| p == options[:ip_protocol] }
598
+
599
+ action = 'AuthorizeSecurityGroupIngress'
600
+ params = {
601
+ 'Action' => action,
602
+ 'GroupName' => group_name
603
+ }
604
+ params['SourceSecurityGroupName'] = options[:source_security_group_name] unless options[:source_security_group_name].nil?
605
+ params['SourceSecurityGroupOwnerId'] = options[:source_security_group_owner_id] unless options[:source_security_group_owner_id].nil?
606
+ params['IpProtocol'] = options[:ip_protocol] unless options[:ip_protocol].nil?
607
+ params['FromPort'] = options[:from_port] unless options[:from_port].nil?
608
+ params['ToPort'] = options[:to_port] unless options[:to_port].nil?
609
+ params['CidrIp'] = options[:cidr_ip] unless options[:cidr_ip].nil?
610
+
611
+ response = send_query_request(params)
612
+ response.is_a?(Net::HTTPSuccess)
613
+ end
614
+
615
+ # Revoke access on a specific SecurityGroup
616
+ #
617
+ # ===Options:
618
+ # ====User/Group access
619
+ # * <tt>:source_security_group_name</tt> - Name of the security group to authorize access to when operating on a user/group pair
620
+ # * <tt>:source_security_group_owner_id</tt> - Owner of the security group to authorize access to when operating on a user/group pair
621
+ # ====CIDR IP access
622
+ # * <tt>:ip_protocol</tt> - IP protocol to authorize access to when operating on a CIDR IP (tcp, udp or icmp) (default: tcp)
623
+ # * <tt>:from_port</tt> - Bottom of port range to authorize access to when operating on a CIDR IP. This contains the ICMP type if ICMP is being authorized.
624
+ # * <tt>:to_port</tt> - Top of port range to authorize access to when operating on a CIDR IP. This contains the ICMP type if ICMP is being authorized.
625
+ # * <tt>:cidr_ip</tt> - CIDR IP range to authorize access to when operating on a CIDR IP. (default: 0.0.0.0/0)
626
+ def revoke_security_group_ingress(group_name, options = {})
627
+ got_at_least_one_user_group_option = !options[:source_security_group_name].nil? || !options[:source_security_group_owner_id].nil?
628
+ got_user_group_options = !options[:source_security_group_name].nil? && !options[:source_security_group_owner_id].nil?
629
+ got_at_least_one_cidr_option = !options[:ip_protocol].nil? || !options[:from_port].nil? || !options[:to_port].nil? || !options[:cidr_ip].nil?
630
+ #Add in defaults
631
+ options = {:cidr_ip => '0.0.0.0/0'}.merge(options) if got_at_least_one_cidr_option
632
+ options = {:ip_protocol => 'tcp'}.merge(options) if got_at_least_one_cidr_option
633
+ got_cidr_options = !options[:ip_protocol].nil? && !options[:from_port].nil? && !options[:to_port].nil? && !options[:cidr_ip].nil?
634
+ raise ArgumentError.new('Can only authorize user/group or CIDR IP, not both') if got_at_least_one_user_group_option && got_at_least_one_cidr_option
635
+ raise ArgumentError.new('Need all user/group options when revoking user/group access') if got_at_least_one_user_group_option && !got_user_group_options
636
+ raise ArgumentError.new('Need all CIDR IP options when revoking CIDR IP access') if got_at_least_one_cidr_option && !got_cidr_options
637
+ raise ArgumentError.new('ip_protocol can only be one of tcp, udp or icmp') if got_at_least_one_cidr_option && !%w(tcp udp icmp).detect{|p| p == options[:ip_protocol] }
638
+
639
+ action = 'RevokeSecurityGroupIngress'
640
+ params = {
641
+ 'Action' => action,
642
+ 'GroupName' => group_name
643
+ }
644
+ params['SourceSecurityGroupName'] = options[:source_security_group_name] unless options[:source_security_group_name].nil?
645
+ params['SourceSecurityGroupOwnerId'] = options[:source_security_group_owner_id] unless options[:source_security_group_owner_id].nil?
646
+ params['IpProtocol'] = options[:ip_protocol] unless options[:ip_protocol].nil?
647
+ params['FromPort'] = options[:from_port] unless options[:from_port].nil?
648
+ params['ToPort'] = options[:to_port] unless options[:to_port].nil?
649
+ params['CidrIp'] = options[:cidr_ip] unless options[:cidr_ip].nil?
650
+
651
+ response = send_query_request(params)
652
+ response.is_a?(Net::HTTPSuccess)
653
+ end
654
+
655
+ # List all reserved instance offerings that are available for purchase
656
+ #
657
+ # ===Options:
658
+ # * <tt>:reserved_instances_offering_ids</tt> - Display the reserved instance offerings with the specified ids. Can be an individual id or an array of ids
659
+ # * <tt>:instance_type</tt> - Display available reserved instance offerings of the specific instance type, can be one of [m1.small, m1.large, m1.xlarge, c1.medium, c1.xlarge], default is all
660
+ # * <tt>:availability_zone</tt> - Display the reserved instance offerings within the specified availability zone
661
+ # * <tt>:product_description</tt> - Display the reserved instance offerings with the specified product description
662
+ #
663
+ # ===Example
664
+ # #To get all offerings for m1.small instances in availability zone us-east-1a
665
+ # ec2.reserved_instances_offerings(:instance_type => 'm1.small', :availability_zone => 'us-east-1a')
666
+ def reserved_instances_offerings(options = {})
667
+ action = 'DescribeReservedInstancesOfferings'
668
+ params = {
669
+ 'Action' => action
670
+ }
671
+ params.merge!(array_to_params(options[:reserved_instances_offering_ids], 'ReservedInstancesOfferingId')) if options[:reserved_instances_offering_ids]
672
+ params['InstanceType'] = options[:instance_type] if options[:instance_type]
673
+ params['AvailabilityZone'] = options[:availability_zone] if options[:availability_zone]
674
+ params['ProductDescription'] = options[:product_description] if options[:product_description]
675
+
676
+ response = send_query_request(params)
677
+ parser = Awsum::Ec2::ReservedInstancesOfferingParser.new(self)
678
+ parser.parse(response.body)
679
+ end
680
+
681
+ # Get a single reserved instances offering by id
682
+ def reserved_instances_offering(id)
683
+ reserved_instances_offerings(:reserved_instances_offering_ids => id)[0]
684
+ end
685
+
686
+ # Purchase reserved instances
687
+ #
688
+ # ===Options:
689
+ # * <tt>:reserved_instances_offering_ids</tt> - A single reserved instance offering id (or an array of instance ids)
690
+ # * <tt>:instance_counts</tt> - A number of reserved instances to purchase (or an array of counts per instance in the reserved_instances_offering_ids array)
691
+ #
692
+ # ===Example
693
+ # ec2.purchase_reserved_instances_offering('reservation-123456', 1)
694
+ # or
695
+ # ec2.purchase_reserved_instances_offering(['reservation-123456', 'reservation-654321'], [1, 2])
696
+ def purchase_reserved_instances_offering(reserved_instances_offering_ids, instance_counts = 1)
697
+ action = 'PurchaseReservedInstancesOffering'
698
+ params = {
699
+ 'Action' => action,
700
+ }
701
+ params.merge!(array_to_params([instance_counts].flatten, 'InstanceCount'))
702
+ params.merge!(array_to_params([reserved_instances_offering_ids].flatten, 'ReservedInstancesOfferingId'))
703
+
704
+ response = send_query_request(params)
705
+ parser = Awsum::Ec2::PurchaseReservedInstancesOfferingParser.new(self)
706
+ result = parser.parse(response.body)
707
+ if reserved_instances_offering_ids.is_a?(Array)
708
+ reserved_instances(*result)
709
+ else
710
+ reserved_instance(result)
711
+ end
712
+ end
713
+
714
+ def reserved_instances(*reserved_instances_ids)
715
+ action = 'DescribeReservedInstances'
716
+ params = {
717
+ 'Action' => action
718
+ }
719
+ params.merge!(array_to_params(reserved_instances_ids, 'ReservedInstanceId'))
720
+
721
+ response = send_query_request(params)
722
+ parser = Awsum::Ec2::ReservedInstanceParser.new(self)
723
+ parser.parse(response.body)
724
+ end
725
+
726
+ # Retrieve a single reserved instance by id
727
+ def reserved_instance(reserved_instance_id)
728
+ reserved_instances(reserved_instance_id)[0]
729
+ end
730
+
731
+ #private
732
+ #The host to make all requests against
733
+ def host
734
+ @host ||= 'ec2.amazonaws.com'
735
+ end
736
+
737
+ def host=(host)
738
+ @host = host
739
+ end
740
+ end
741
+ end