ec2_amitools 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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