ec2_amitools 1.0.2

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 (102) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +54 -0
  3. data/bin/console +14 -0
  4. data/bin/ec2-ami-tools-version +6 -0
  5. data/bin/ec2-bundle-image +6 -0
  6. data/bin/ec2-bundle-vol +6 -0
  7. data/bin/ec2-delete-bundle +6 -0
  8. data/bin/ec2-download-bundle +6 -0
  9. data/bin/ec2-migrate-bundle +6 -0
  10. data/bin/ec2-migrate-manifest +6 -0
  11. data/bin/ec2-unbundle +6 -0
  12. data/bin/ec2-upload-bundle +6 -0
  13. data/bin/setup +8 -0
  14. data/etc/ec2/amitools/cert-ec2-cn-north-1.pem +28 -0
  15. data/etc/ec2/amitools/cert-ec2-gov.pem +17 -0
  16. data/etc/ec2/amitools/cert-ec2.pem +23 -0
  17. data/etc/ec2/amitools/mappings.csv +9 -0
  18. data/lib/ec2/amitools/bundle.rb +251 -0
  19. data/lib/ec2/amitools/bundle_base.rb +58 -0
  20. data/lib/ec2/amitools/bundleimage.rb +94 -0
  21. data/lib/ec2/amitools/bundleimageparameters.rb +42 -0
  22. data/lib/ec2/amitools/bundlemachineparameters.rb +60 -0
  23. data/lib/ec2/amitools/bundleparameters.rb +120 -0
  24. data/lib/ec2/amitools/bundlevol.rb +240 -0
  25. data/lib/ec2/amitools/bundlevolparameters.rb +164 -0
  26. data/lib/ec2/amitools/crypto.rb +379 -0
  27. data/lib/ec2/amitools/decryptmanifest.rb +20 -0
  28. data/lib/ec2/amitools/defaults.rb +12 -0
  29. data/lib/ec2/amitools/deletebundle.rb +212 -0
  30. data/lib/ec2/amitools/deletebundleparameters.rb +78 -0
  31. data/lib/ec2/amitools/downloadbundle.rb +161 -0
  32. data/lib/ec2/amitools/downloadbundleparameters.rb +84 -0
  33. data/lib/ec2/amitools/exception.rb +86 -0
  34. data/lib/ec2/amitools/fileutil.rb +219 -0
  35. data/lib/ec2/amitools/format.rb +127 -0
  36. data/lib/ec2/amitools/instance-data.rb +97 -0
  37. data/lib/ec2/amitools/manifest_wrapper.rb +132 -0
  38. data/lib/ec2/amitools/manifestv20070829.rb +361 -0
  39. data/lib/ec2/amitools/manifestv20071010.rb +403 -0
  40. data/lib/ec2/amitools/manifestv3.rb +331 -0
  41. data/lib/ec2/amitools/mapids.rb +148 -0
  42. data/lib/ec2/amitools/migratebundle.rb +222 -0
  43. data/lib/ec2/amitools/migratebundleparameters.rb +173 -0
  44. data/lib/ec2/amitools/migratemanifest.rb +225 -0
  45. data/lib/ec2/amitools/migratemanifestparameters.rb +118 -0
  46. data/lib/ec2/amitools/minimalec2.rb +116 -0
  47. data/lib/ec2/amitools/parameter_exceptions.rb +34 -0
  48. data/lib/ec2/amitools/parameters_base.rb +168 -0
  49. data/lib/ec2/amitools/region.rb +93 -0
  50. data/lib/ec2/amitools/s3toolparameters.rb +183 -0
  51. data/lib/ec2/amitools/showversion.rb +12 -0
  52. data/lib/ec2/amitools/syschecks.rb +27 -0
  53. data/lib/ec2/amitools/tool_base.rb +224 -0
  54. data/lib/ec2/amitools/unbundle.rb +107 -0
  55. data/lib/ec2/amitools/unbundleparameters.rb +65 -0
  56. data/lib/ec2/amitools/uploadbundle.rb +361 -0
  57. data/lib/ec2/amitools/uploadbundleparameters.rb +108 -0
  58. data/lib/ec2/amitools/util.rb +532 -0
  59. data/lib/ec2/amitools/version.rb +33 -0
  60. data/lib/ec2/amitools/xmlbuilder.rb +237 -0
  61. data/lib/ec2/amitools/xmlutil.rb +55 -0
  62. data/lib/ec2/common/constants.rb +16 -0
  63. data/lib/ec2/common/curl.rb +110 -0
  64. data/lib/ec2/common/headers.rb +95 -0
  65. data/lib/ec2/common/headersv4.rb +173 -0
  66. data/lib/ec2/common/http.rb +333 -0
  67. data/lib/ec2/common/s3support.rb +231 -0
  68. data/lib/ec2/common/signature.rb +68 -0
  69. data/lib/ec2/oem/LICENSE.txt +58 -0
  70. data/lib/ec2/oem/open4.rb +399 -0
  71. data/lib/ec2/platform/base/architecture.rb +26 -0
  72. data/lib/ec2/platform/base/constants.rb +54 -0
  73. data/lib/ec2/platform/base/pipeline.rb +181 -0
  74. data/lib/ec2/platform/base.rb +57 -0
  75. data/lib/ec2/platform/current.rb +55 -0
  76. data/lib/ec2/platform/linux/architecture.rb +35 -0
  77. data/lib/ec2/platform/linux/constants.rb +23 -0
  78. data/lib/ec2/platform/linux/fstab.rb +99 -0
  79. data/lib/ec2/platform/linux/identity.rb +16 -0
  80. data/lib/ec2/platform/linux/image.rb +811 -0
  81. data/lib/ec2/platform/linux/mtab.rb +74 -0
  82. data/lib/ec2/platform/linux/pipeline.rb +40 -0
  83. data/lib/ec2/platform/linux/rsync.rb +114 -0
  84. data/lib/ec2/platform/linux/tar.rb +124 -0
  85. data/lib/ec2/platform/linux/uname.rb +50 -0
  86. data/lib/ec2/platform/linux.rb +83 -0
  87. data/lib/ec2/platform/solaris/architecture.rb +28 -0
  88. data/lib/ec2/platform/solaris/constants.rb +30 -0
  89. data/lib/ec2/platform/solaris/fstab.rb +43 -0
  90. data/lib/ec2/platform/solaris/identity.rb +16 -0
  91. data/lib/ec2/platform/solaris/image.rb +327 -0
  92. data/lib/ec2/platform/solaris/mtab.rb +29 -0
  93. data/lib/ec2/platform/solaris/pipeline.rb +40 -0
  94. data/lib/ec2/platform/solaris/rsync.rb +24 -0
  95. data/lib/ec2/platform/solaris/tar.rb +36 -0
  96. data/lib/ec2/platform/solaris/uname.rb +21 -0
  97. data/lib/ec2/platform/solaris.rb +38 -0
  98. data/lib/ec2/platform.rb +69 -0
  99. data/lib/ec2/version.rb +8 -0
  100. data/lib/ec2_amitools +1 -0
  101. data/lib/ec2_amitools.rb +7 -0
  102. metadata +184 -0
@@ -0,0 +1,225 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ require 'ec2/amitools/migratemanifestparameters'
12
+ require 'ec2/amitools/manifest_wrapper'
13
+ require 'fileutils'
14
+ require 'csv'
15
+ require 'net/http'
16
+ require 'ec2/amitools/tool_base'
17
+ require 'ec2/amitools/mapids'
18
+
19
+ MIGRATE_MANIFEST_NAME = "ec2-migrate-manifest"
20
+
21
+ MIGRATE_MANIFEST_MANUAL =<<TEXT
22
+ #{MIGRATE_MANIFEST_NAME} is a command line tool to assist with migrating AMIs to new regions.
23
+
24
+ #{MIGRATE_MANIFEST_NAME} will:
25
+ - automatically replace kernels and ramdisks with replacements suitable for a
26
+ particular target region
27
+ - optionally replace kernels and ramdisks with user-specified replacements
28
+
29
+ TEXT
30
+
31
+ class BadManifestError < RuntimeError
32
+ def initialize(manifest, msg)
33
+ super("Bad manifest '#{manifest}': #{msg}")
34
+ end
35
+ end
36
+
37
+ class ManifestMigrator < AMITool
38
+ include EC2::Platform::Current::Constants
39
+
40
+ def get_manifest(manifest_path, user_cert_path)
41
+ unless File::exists?(manifest_path)
42
+ raise BadManifestError.new(manifest_path, "File not found.")
43
+ end
44
+ begin
45
+ manifest = ManifestWrapper.new(File.open(manifest_path).read())
46
+ rescue ManifestWrapper::InvalidManifest => e
47
+ raise BadManifestError.new(manifest_path, e.message)
48
+ end
49
+ unless manifest.authenticate(File.open(user_cert_path))
50
+ raise BadManifestError.new(manifest_path, "Manifest fails authentication.")
51
+ end
52
+ manifest
53
+ end
54
+
55
+ #----------------------------------------------------------------------------#
56
+
57
+ def get_mappings(*args)
58
+ KernelMappings.new(*args)
59
+ end
60
+
61
+ #----------------------------------------------------------------------------#
62
+
63
+ def map_identifiers(manifest, user, pass, region, kernel_id=nil, ramdisk_id=nil)
64
+ if region.nil?
65
+ raise EC2FatalError.new(1, "No region provided, cannot map automatically.")
66
+ end
67
+ if manifest.kernel_id.nil? and manifest.ramdisk_id.nil?
68
+ # Exit early if we have nothing to do
69
+ return [kernel_id, ramdisk_id]
70
+ end
71
+
72
+ begin
73
+ mappings = get_mappings(user, pass, [manifest.kernel_id, manifest.ramdisk_id].compact, region)
74
+ rescue KernelMappings::MappingError => e
75
+ raise EC2FatalError.new(7, e.message)
76
+ end
77
+
78
+ begin
79
+ if manifest.kernel_id
80
+ kernel_id ||= mappings[manifest.kernel_id]
81
+ end
82
+ if manifest.ramdisk_id
83
+ ramdisk_id ||= mappings[manifest.ramdisk_id]
84
+ end
85
+ warn_about_mappings(mappings.find_missing_targets([kernel_id, ramdisk_id].compact))
86
+ rescue KernelMappings::MappingError => e
87
+ raise EC2FatalError.new(6, e.message)
88
+ end
89
+ [kernel_id, ramdisk_id]
90
+ end
91
+
92
+ #----------------------------------------------------------------------------#
93
+
94
+ def backup_manifest(manifest_path, quiet=false)
95
+ backup_manifest = "#{manifest_path}.bak"
96
+ if File::exists?(backup_manifest)
97
+ raise EC2FatalError.new(2, "Backup file '#{backup_manifest}' already exists. Please delete or rename it and try again.")
98
+ end
99
+ $stdout.puts("Backing up manifest...") unless quiet
100
+ $stdout.puts("Backup manifest at #{backup_manifest}") if @debug
101
+ FileUtils::copy(manifest_path, backup_manifest)
102
+ end
103
+
104
+ #----------------------------------------------------------------------------#
105
+
106
+ def build_migrated_manifest(manifest, user_pk_path, kernel_id=nil, ramdisk_id=nil)
107
+ new_manifest = ManifestV20071010.new()
108
+ manifest_params = {
109
+ :name => manifest.name,
110
+ :user => manifest.user,
111
+ :image_type => manifest.image_type,
112
+ :arch => manifest.arch,
113
+ :reserved => nil,
114
+ :parts => manifest.parts.map { |part| [part.filename, part.digest] },
115
+ :size => manifest.size,
116
+ :bundled_size => manifest.bundled_size,
117
+ :user_encrypted_key => manifest.user_encrypted_key,
118
+ :ec2_encrypted_key => manifest.ec2_encrypted_key,
119
+ :cipher_algorithm => manifest.cipher_algorithm,
120
+ :user_encrypted_iv => manifest.user_encrypted_iv,
121
+ :ec2_encrypted_iv => manifest.ec2_encrypted_iv,
122
+ :digest => manifest.digest,
123
+ :digest_algorithm => manifest.digest_algorithm,
124
+ :privkey_filename => user_pk_path,
125
+ :kernel_id => kernel_id,
126
+ :ramdisk_id => ramdisk_id,
127
+ :product_codes => manifest.product_codes,
128
+ :ancestor_ami_ids => manifest.ancestor_ami_ids,
129
+ :block_device_mapping => manifest.block_device_mapping,
130
+ :bundler_name => manifest.bundler_name,
131
+ :bundler_version => manifest.bundler_version,
132
+ :bundler_release => manifest.bundler_release,
133
+ :kernel_name => manifest.kernel_name,
134
+ }
135
+ new_manifest.init(manifest_params)
136
+ new_manifest
137
+ end
138
+
139
+ #----------------------------------------------------------------------------#
140
+
141
+ def check_and_warn(manifest, kernel_id, ramdisk_id)
142
+ if (manifest.kernel_id and kernel_id.nil?) or (manifest.ramdisk_id and ramdisk_id.nil?)
143
+ message = ["This operation will remove the kernel and/or ramdisk associated with",
144
+ "the AMI. This may cause the AMI to fail to launch unless you specify",
145
+ "an appropriate kernel and ramdisk at launch time.",
146
+ ].join("\n")
147
+ unless warn_confirm(message)
148
+ raise EC2StopExecution.new()
149
+ end
150
+ end
151
+ end
152
+
153
+ #----------------------------------------------------------------------------#
154
+
155
+ def warn_about_mappings(problems)
156
+ return if problems.nil?
157
+ message = ["The following identifiers do not exist in the target region:",
158
+ " " + problems.inspect.gsub(/['"]/, '')
159
+ ].join("\n")
160
+ unless warn_confirm(message)
161
+ raise EC2StopExecution.new()
162
+ end
163
+ end
164
+
165
+ #----------------------------------------------------------------------------#
166
+
167
+ def migrate_manifest(manifest_path,
168
+ user_pk_path,
169
+ user_cert_path,
170
+ user=nil,
171
+ pass=nil,
172
+ use_mapping=true,
173
+ kernel_id=nil,
174
+ ramdisk_id=nil,
175
+ region=nil,
176
+ quiet=false)
177
+ manifest = get_manifest(manifest_path, user_cert_path)
178
+ backup_manifest(manifest_path, quiet)
179
+ if use_mapping
180
+ kernel_id, ramdisk_id = map_identifiers(manifest,
181
+ user,
182
+ pass,
183
+ region,
184
+ kernel_id,
185
+ ramdisk_id)
186
+ end
187
+ check_and_warn(manifest, kernel_id, ramdisk_id)
188
+ new_manifest = build_migrated_manifest(manifest, user_pk_path, kernel_id, ramdisk_id)
189
+ File.open(manifest_path, 'w') { |f| f.write(new_manifest.to_s) }
190
+ $stdout.puts("Successfully migrated #{manifest_path}") unless quiet
191
+ $stdout.puts("It is now suitable for use in #{region}.") unless quiet
192
+ end
193
+
194
+ #------------------------------------------------------------------------------#
195
+ # Overrides
196
+ #------------------------------------------------------------------------------#
197
+
198
+ def get_manual()
199
+ MIGRATE_MANIFEST_MANUAL
200
+ end
201
+
202
+ def get_name()
203
+ MIGRATE_MANIFEST_NAME
204
+ end
205
+
206
+ def main(p)
207
+ migrate_manifest(p.manifest_path,
208
+ p.user_pk_path,
209
+ p.user_cert_path,
210
+ p.user,
211
+ p.pass,
212
+ p.use_mapping,
213
+ p.kernel_id,
214
+ p.ramdisk_id,
215
+ p.region)
216
+ end
217
+
218
+ end
219
+
220
+ #------------------------------------------------------------------------------#
221
+ # Script entry point. Execute only if this file is being executed.
222
+
223
+ if __FILE__ == $0 || $0.match(/bin\/ec2-migrate-manifest/)
224
+ ManifestMigrator.new().run(MigrateManifestParameters)
225
+ end
@@ -0,0 +1,118 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ require 'ec2/amitools/parameters_base'
12
+ require 'ec2/amitools/region'
13
+ require 'ec2/platform/current'
14
+
15
+ #------------------------------------------------------------------------------#
16
+
17
+ class MigrateManifestParameters < ParametersBase
18
+ include EC2::Platform::Current::Constants
19
+
20
+ MANIFEST_DESCRIPTION = "The path to the manifest file."
21
+ DIRECTORY_DESCRIPTION = ["The directory containing the bundled AMI parts to upload.",
22
+ "Defaults to the directory containing the manifest."]
23
+ EC2_CERT_PATH_DESCRIPTION = ['The path to the EC2 X509 public key certificate bundled into the AMI.',
24
+ "Defaults to the certificate of the region (usually '#{Bundling::EC2_X509_CERT}')."]
25
+ KERNEL_DESCRIPTION = "Kernel id to bundle into the AMI."
26
+ RAMDISK_DESCRIPTION = "Ramdisk id to bundle into the AMI."
27
+ USER_DESCRIPTION = "The user's AWS access key ID."
28
+ PASS_DESCRIPTION = "The user's AWS secret access key."
29
+ NO_MAPPING_DESCRIPTION = "Do not perform automatic mappings."
30
+ REGION_DESCRIPTION = "Region to look up in the mapping file."
31
+
32
+ attr_accessor :user_pk_path,
33
+ :user_cert_path,
34
+ :user,
35
+ :pass,
36
+ :ec2_cert_path,
37
+ :manifest_path,
38
+ :kernel_id,
39
+ :ramdisk_id,
40
+ :use_mapping,
41
+ :region
42
+
43
+ #----------------------------------------------------------------------------#
44
+
45
+ def mandatory_params()
46
+ on('-c', '--cert PATH', String, USER_CERT_PATH_DESCRIPTION) do |path|
47
+ assert_file_exists(path, '--cert')
48
+ @user_cert_path = path
49
+ end
50
+
51
+ on('-k', '--privatekey PATH', String, USER_PK_PATH_DESCRIPTION) do |path|
52
+ assert_file_exists(path, '--privatekey')
53
+ @user_pk_path = path
54
+ end
55
+
56
+ on('-m', '--manifest PATH', String, MANIFEST_DESCRIPTION) do |manifest|
57
+ assert_file_exists(manifest, '--manifest')
58
+ @manifest_path = manifest
59
+ end
60
+ end
61
+
62
+ #----------------------------------------------------------------------------#
63
+
64
+ def optional_params()
65
+ on('-a', '--access-key USER', String, USER_DESCRIPTION) do |user|
66
+ @user = user
67
+ end
68
+
69
+ on('-s', '--secret-key PASSWORD', String, PASS_DESCRIPTION) do |pass|
70
+ @pass = pass
71
+ end
72
+
73
+ on('--ec2cert PATH', String, *EC2_CERT_PATH_DESCRIPTION) do |path|
74
+ assert_file_exists(path, '--ec2cert')
75
+ @ec2_cert_path = path
76
+ end
77
+
78
+ on('--kernel KERNEL_ID', String, KERNEL_DESCRIPTION) do |kernel_id|
79
+ @kernel_id = kernel_id
80
+ end
81
+
82
+ on('--ramdisk RAMDISK_ID', String, RAMDISK_DESCRIPTION) do |ramdisk_id|
83
+ @ramdisk_id = ramdisk_id
84
+ end
85
+
86
+ on('--no-mapping', String, NO_MAPPING_DESCRIPTION) do
87
+ @use_mapping = false
88
+ end
89
+
90
+ on('--region REGION', String, REGION_DESCRIPTION) do |region|
91
+ @region = region
92
+ end
93
+ end
94
+
95
+ #----------------------------------------------------------------------------#
96
+
97
+ def validate_params()
98
+ raise MissingMandatory.new('--manifest') unless @manifest_path
99
+ raise MissingMandatory.new('--cert') unless @user_cert_path
100
+ raise MissingMandatory.new('--privatekey') unless @user_pk_path
101
+ @use_mapping = true if @use_mapping.nil? # False is different.
102
+ if @use_mapping
103
+ raise ParameterExceptions::Error.new('If using automatic mapping, --region must be provided.') unless @region
104
+ raise ParameterExceptions::Error.new('If using automatic mapping, --access-key must be provided.') unless @user
105
+ raise ParameterExceptions::Error.new('If using automatic mapping, --secret-key must be provided.') unless @pass
106
+ end
107
+ end
108
+
109
+ #----------------------------------------------------------------------------#
110
+
111
+ def set_defaults()
112
+ @ec2_cert_path ||= case
113
+ when (@region=="us-gov-west-1") then Bundling::EC2_X509_GOV_CERT
114
+ when (@region=="cn-north-1") then Bundling::EC2_X509_CN_NORTH_1_CERT
115
+ else Bundling::EC2_X509_CERT
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,116 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ require 'base64'
12
+ require 'cgi'
13
+ require 'openssl'
14
+ require 'digest/sha1'
15
+ require 'net/https'
16
+ require 'rexml/document'
17
+ require 'time'
18
+ require 'ec2/amitools/version'
19
+
20
+ module EC2
21
+ class EC2Client
22
+ attr_accessor :verbose
23
+ attr_accessor :aws_access_key_id
24
+ attr_accessor :aws_secret_access_key
25
+ attr_accessor :http
26
+
27
+ def parse_url(url)
28
+ bits = url.split(":")
29
+ secure = {"https"=>true, "http"=>false}[bits[0]]
30
+ port = secure ? 443 : 80
31
+ port = Integer(bits[2]) if bits.size > 2
32
+ server = bits[1][2..-1]
33
+ [server, port, secure]
34
+ end
35
+
36
+ def initialize(akid, secretkey, url)
37
+ @aws_access_key_id = akid
38
+ @aws_secret_access_key = secretkey
39
+ server, port, is_secure = parse_url(url)
40
+ @http = Net::HTTP.new(server, port)
41
+ @http.use_ssl = is_secure
42
+ @verbose = false
43
+ end
44
+
45
+ def pathlist(key, arr)
46
+ params = {}
47
+ arr.each_with_index do |value, i|
48
+ params["#{key}.#{i+1}"] = value
49
+ end
50
+ params
51
+ end
52
+
53
+ def describe_regions(regionNames=[])
54
+ params = pathlist("regionName", regionNames)
55
+ make_request("DescribeRegions", params)
56
+ end
57
+
58
+ def describe_images(imageIds=[], kwargs={})
59
+ params = pathlist("ImageId", imageIds)
60
+ params.merge!(pathlist("Owner", kwargs[:owners])) if kwargs[:owners]
61
+ params.merge!(pathlist("ExecutableBy", kwargs[:executableBy])) if kwargs[:executableBy]
62
+ make_request("DescribeImages", params)
63
+ end
64
+
65
+ def make_request(action, params, data='')
66
+ resp = nil
67
+ @http.start do
68
+ params.merge!({ "Action"=>action,
69
+ "SignatureVersion"=>"1",
70
+ "AWSAccessKeyId"=>@aws_access_key_id,
71
+ "Version"=> "2008-12-01",
72
+ "Timestamp"=>Time.now.getutc.iso8601,
73
+ })
74
+ p params if @verbose
75
+
76
+ canonical_string = params.sort_by { |param| param[0].downcase }.map { |param| param.join }.join
77
+ puts canonical_string if @verbose
78
+ sig = encode(@aws_secret_access_key, canonical_string)
79
+
80
+ path = "?" + params.sort.collect do |param|
81
+ CGI::escape(param[0]) + "=" + CGI::escape(param[1])
82
+ end.join("&") + "&Signature=" + sig
83
+
84
+ puts path if @verbose
85
+
86
+ req = Net::HTTP::Get.new("/#{path}")
87
+
88
+ # ruby will automatically add a random content-type on some verbs, so
89
+ # here we add a dummy one to 'supress' it. change this logic if having
90
+ # an empty content-type header becomes semantically meaningful for any
91
+ # other verb.
92
+ req['Content-Type'] ||= ''
93
+ req['User-Agent'] = 'ec2-migrate-manifest #{PKG_VERSION}-#{PKG_RELEASE}'
94
+
95
+ data = nil unless req.request_body_permitted?
96
+ resp = @http.request(req, data)
97
+
98
+ end
99
+ REXML::Document.new(resp.body)
100
+ end
101
+
102
+ # Encodes the given string with the aws_secret_access_key, by taking the
103
+ # hmac-sha1 sum, and then base64 encoding it. Optionally, it will also
104
+ # url encode the result of that to protect the string if it's going to
105
+ # be used as a query string parameter.
106
+ def encode(aws_secret_access_key, str, urlencode=true)
107
+ digest = OpenSSL::Digest::Digest.new('sha1')
108
+ b64_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, aws_secret_access_key, str)).strip
109
+ if urlencode
110
+ return CGI::escape(b64_hmac)
111
+ else
112
+ return b64_hmac
113
+ end
114
+ end
115
+ end
116
+ end