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.
- checksums.yaml +7 -0
- data/README.md +54 -0
- data/bin/console +14 -0
- data/bin/ec2-ami-tools-version +6 -0
- data/bin/ec2-bundle-image +6 -0
- data/bin/ec2-bundle-vol +6 -0
- data/bin/ec2-delete-bundle +6 -0
- data/bin/ec2-download-bundle +6 -0
- data/bin/ec2-migrate-bundle +6 -0
- data/bin/ec2-migrate-manifest +6 -0
- data/bin/ec2-unbundle +6 -0
- data/bin/ec2-upload-bundle +6 -0
- data/bin/setup +8 -0
- data/etc/ec2/amitools/cert-ec2-cn-north-1.pem +28 -0
- data/etc/ec2/amitools/cert-ec2-gov.pem +17 -0
- data/etc/ec2/amitools/cert-ec2.pem +23 -0
- data/etc/ec2/amitools/mappings.csv +9 -0
- data/lib/ec2/amitools/bundle.rb +251 -0
- data/lib/ec2/amitools/bundle_base.rb +58 -0
- data/lib/ec2/amitools/bundleimage.rb +94 -0
- data/lib/ec2/amitools/bundleimageparameters.rb +42 -0
- data/lib/ec2/amitools/bundlemachineparameters.rb +60 -0
- data/lib/ec2/amitools/bundleparameters.rb +120 -0
- data/lib/ec2/amitools/bundlevol.rb +240 -0
- data/lib/ec2/amitools/bundlevolparameters.rb +164 -0
- data/lib/ec2/amitools/crypto.rb +379 -0
- data/lib/ec2/amitools/decryptmanifest.rb +20 -0
- data/lib/ec2/amitools/defaults.rb +12 -0
- data/lib/ec2/amitools/deletebundle.rb +212 -0
- data/lib/ec2/amitools/deletebundleparameters.rb +78 -0
- data/lib/ec2/amitools/downloadbundle.rb +161 -0
- data/lib/ec2/amitools/downloadbundleparameters.rb +84 -0
- data/lib/ec2/amitools/exception.rb +86 -0
- data/lib/ec2/amitools/fileutil.rb +219 -0
- data/lib/ec2/amitools/format.rb +127 -0
- data/lib/ec2/amitools/instance-data.rb +97 -0
- data/lib/ec2/amitools/manifest_wrapper.rb +132 -0
- data/lib/ec2/amitools/manifestv20070829.rb +361 -0
- data/lib/ec2/amitools/manifestv20071010.rb +403 -0
- data/lib/ec2/amitools/manifestv3.rb +331 -0
- data/lib/ec2/amitools/mapids.rb +148 -0
- data/lib/ec2/amitools/migratebundle.rb +222 -0
- data/lib/ec2/amitools/migratebundleparameters.rb +173 -0
- data/lib/ec2/amitools/migratemanifest.rb +225 -0
- data/lib/ec2/amitools/migratemanifestparameters.rb +118 -0
- data/lib/ec2/amitools/minimalec2.rb +116 -0
- data/lib/ec2/amitools/parameter_exceptions.rb +34 -0
- data/lib/ec2/amitools/parameters_base.rb +168 -0
- data/lib/ec2/amitools/region.rb +93 -0
- data/lib/ec2/amitools/s3toolparameters.rb +183 -0
- data/lib/ec2/amitools/showversion.rb +12 -0
- data/lib/ec2/amitools/syschecks.rb +27 -0
- data/lib/ec2/amitools/tool_base.rb +224 -0
- data/lib/ec2/amitools/unbundle.rb +107 -0
- data/lib/ec2/amitools/unbundleparameters.rb +65 -0
- data/lib/ec2/amitools/uploadbundle.rb +361 -0
- data/lib/ec2/amitools/uploadbundleparameters.rb +108 -0
- data/lib/ec2/amitools/util.rb +532 -0
- data/lib/ec2/amitools/version.rb +33 -0
- data/lib/ec2/amitools/xmlbuilder.rb +237 -0
- data/lib/ec2/amitools/xmlutil.rb +55 -0
- data/lib/ec2/common/constants.rb +16 -0
- data/lib/ec2/common/curl.rb +110 -0
- data/lib/ec2/common/headers.rb +95 -0
- data/lib/ec2/common/headersv4.rb +173 -0
- data/lib/ec2/common/http.rb +333 -0
- data/lib/ec2/common/s3support.rb +231 -0
- data/lib/ec2/common/signature.rb +68 -0
- data/lib/ec2/oem/LICENSE.txt +58 -0
- data/lib/ec2/oem/open4.rb +399 -0
- data/lib/ec2/platform/base/architecture.rb +26 -0
- data/lib/ec2/platform/base/constants.rb +54 -0
- data/lib/ec2/platform/base/pipeline.rb +181 -0
- data/lib/ec2/platform/base.rb +57 -0
- data/lib/ec2/platform/current.rb +55 -0
- data/lib/ec2/platform/linux/architecture.rb +35 -0
- data/lib/ec2/platform/linux/constants.rb +23 -0
- data/lib/ec2/platform/linux/fstab.rb +99 -0
- data/lib/ec2/platform/linux/identity.rb +16 -0
- data/lib/ec2/platform/linux/image.rb +811 -0
- data/lib/ec2/platform/linux/mtab.rb +74 -0
- data/lib/ec2/platform/linux/pipeline.rb +40 -0
- data/lib/ec2/platform/linux/rsync.rb +114 -0
- data/lib/ec2/platform/linux/tar.rb +124 -0
- data/lib/ec2/platform/linux/uname.rb +50 -0
- data/lib/ec2/platform/linux.rb +83 -0
- data/lib/ec2/platform/solaris/architecture.rb +28 -0
- data/lib/ec2/platform/solaris/constants.rb +30 -0
- data/lib/ec2/platform/solaris/fstab.rb +43 -0
- data/lib/ec2/platform/solaris/identity.rb +16 -0
- data/lib/ec2/platform/solaris/image.rb +327 -0
- data/lib/ec2/platform/solaris/mtab.rb +29 -0
- data/lib/ec2/platform/solaris/pipeline.rb +40 -0
- data/lib/ec2/platform/solaris/rsync.rb +24 -0
- data/lib/ec2/platform/solaris/tar.rb +36 -0
- data/lib/ec2/platform/solaris/uname.rb +21 -0
- data/lib/ec2/platform/solaris.rb +38 -0
- data/lib/ec2/platform.rb +69 -0
- data/lib/ec2/version.rb +8 -0
- data/lib/ec2_amitools +1 -0
- data/lib/ec2_amitools.rb +7 -0
- 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
|