~awstools-dev/ubuntu/lucid/ec2-ami-tools/lucid

« back to all changes in this revision

Viewing changes to lib/ec2/amitools/migratebundle.rb

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2009-01-13 11:46:59 UTC
  • Revision ID: james.westby@ubuntu.com-20090113114659-d2g70wekc6b0dz3x
Tags: 1.3-31057-0ubuntu1
* New upstream version. (LP: #310547)
* debian/patches/exclude-udev-rules.patch: Exclude the copying of 
  /etc/udev/rules.d/70-persistent-net.rules and
  /etc/udev/rules.d/z25_persistent-net.rules when rebundling an image. 
  (LP: #308548)
* debian/patches/point-to-right-place: Updated patch to take in account
  ec2-migrate-manifest and ec2-migrate-bundle.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2008 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/common/s3support'
 
12
require 'ec2/amitools/migratebundleparameters'
 
13
require 'ec2/amitools/migratemanifest'
 
14
require 'ec2/amitools/downloadbundle'
 
15
require 'ec2/amitools/uploadbundle'
 
16
require 'fileutils'
 
17
require 'ec2/amitools/tool_base'
 
18
 
 
19
MIGRATE_BUNDLE_NAME = 'ec2-migrate-bundle'
 
20
 
 
21
#------------------------------------------------------------------------------#
 
22
 
 
23
MIGRATE_BUNDLE_MANUAL =<<TEXT
 
24
#{MIGRATE_BUNDLE_NAME} is a command line tool to assist with migrating AMIs to new regions.
 
25
 
 
26
#{MIGRATE_BUNDLE_NAME} will:
 
27
- download the manifest of the specified AMI
 
28
- attempt to automatically find replacement kernels and ramdisks
 
29
- optionally replace kernels and ramdisks with user-specified replacements
 
30
- copy AMI into new bucket
 
31
- upload new migrated manifest into new bucket
 
32
 
 
33
This tool will not register the AMI in the new region.
 
34
 
 
35
TEXT
 
36
 
 
37
class BundleMigrator < AMITool
 
38
  
 
39
  # If we return true, we have a v2-compliant name.
 
40
  # If we return false, we wish to use a bad name.
 
41
  # Otherwise we quietly wander off to die in peace.
 
42
  def check_bucket_name(bucket, interactive)
 
43
    if EC2::Common::S3Support::bucket_name_s3_v2_safe?(bucket)
 
44
      return true
 
45
    end
 
46
    if interactive
 
47
      begin
 
48
        $stdout.puts "The specified bucket is not S3 v2 safe (see S3 documentation for details):"
 
49
        $stdout.puts bucket
 
50
        $stdout.print "Are you sure you want to continue? [y/N]: "
 
51
        $stdout.flush
 
52
        Timeout::timeout(PROMPT_TIMEOUT) do
 
53
          instr = gets
 
54
          if instr[0..0] =~ /[Yy]/
 
55
            return false
 
56
          end
 
57
          raise EC2FatalError.new(2, nil)
 
58
        end
 
59
      rescue Timeout::Error
 
60
        raise PromptTimeout.new("bucket name confirmation")
 
61
      end
 
62
    else
 
63
      # If we're in batch mode, assume the customer knows what he wants.
 
64
      return false
 
65
    end
 
66
  end
 
67
 
 
68
  def with_temp_dir(manifest_name)
 
69
    # Set up temporary dir
 
70
    tempdir = File::join(Dir::tmpdir, "ami-migration-#{manifest_name}".gsub("/","-"))
 
71
    if File::exists?(tempdir)
 
72
      raise EC2FatalError.new(2, "Temporary directory '#{tempdir}' already exists. Please delete or rename it and try again.")
 
73
    end
 
74
    Dir::mkdir(tempdir)
 
75
 
 
76
    # Let the caller use it
 
77
    begin
 
78
      result = yield tempdir
 
79
    rescue Exception => e
 
80
      # Nuke it
 
81
      FileUtils::rm_rf(tempdir)
 
82
      raise e
 
83
    end
 
84
    # Nuke it
 
85
    FileUtils::rm_rf(tempdir)
 
86
    result
 
87
  end
 
88
 
 
89
  def uri2string(uri)
 
90
    s = "#{uri.scheme}://#{uri.host}:#{uri.port}#{uri.path}"
 
91
    # Remove the trailing '/'.
 
92
    return (s[-1..-1] == "/" ? s[0..-2] : s)
 
93
  end
 
94
 
 
95
  def make_s3_connection(s3_url, user, pass, bucket)
 
96
    s3_uri = URI.parse(s3_url)
 
97
    s3_url = uri2string(s3_uri)
 
98
    v2_bucket = EC2::Common::S3Support::bucket_name_s3_v2_safe?(bucket)
 
99
    EC2::Common::S3Support.new(s3_url, user, pass, (v2_bucket ? nil : :path))
 
100
  end
 
101
 
 
102
  def download_manifest(s3_conn, bucket, manifest_name, manifest_path, user_pk_path, retry_stuff)
 
103
    BundleDownloader.new().download_manifest(s3_conn,
 
104
                                             bucket,
 
105
                                             manifest_name,
 
106
                                             manifest_path,
 
107
                                             user_pk_path,
 
108
                                             retry_stuff)
 
109
  end
 
110
 
 
111
  def get_part_filenames(manifest_path, user_cert_path)
 
112
    manifest = ManifestMigrator.new().get_manifest(manifest_path, user_cert_path)
 
113
    manifest.parts.collect { |part| part.filename }.sort
 
114
  end
 
115
 
 
116
  def copy_part(s3_conn, bucket, dest_bucket, part, acl, retry_copy)
 
117
    source = "/#{bucket}/#{part}"
 
118
    retry_s3(retry_copy) do
 
119
      begin
 
120
        s3_conn.copy(dest_bucket, part, source, {"x-amz-acl"=>acl})
 
121
        return
 
122
      rescue => e
 
123
        raise TryFailed.new("Failed to copy \"#{part}\": #{e.message}")
 
124
      end
 
125
    end
 
126
  end
 
127
 
 
128
  def create_bucket(dest_s3_conn, dest_bucket, location, retry_stuff)
 
129
    uploader = BundleUploader.new()
 
130
    dest_bucket_location = uploader.get_bucket_location(dest_s3_conn, dest_bucket)
 
131
    uploader.create_bucket(dest_s3_conn, dest_bucket, dest_bucket_location, location, retry_stuff)
 
132
  end
 
133
 
 
134
  def upload_manifest(s3_conn, manifest_name, manifest_path, bucket, tempdir, acl, retry_stuff)
 
135
    BundleUploader.new().upload(s3_conn, bucket, manifest_name, manifest_path, acl, retry_stuff)
 
136
  end
 
137
 
 
138
  def migrate_bundle(s3_url,
 
139
                     bucket,
 
140
                     dest_bucket,
 
141
                     manifest_name,
 
142
                     user_pk_path,
 
143
                     user_cert_path,
 
144
                     user,
 
145
                     pass,
 
146
                     location,
 
147
                     kernel_id=nil,
 
148
                     ramdisk_id=nil,
 
149
                     acl='aws-exec-read',
 
150
                     retry_stuff=nil,
 
151
                     use_mapping=true,
 
152
                     mapping_url=nil,
 
153
                     mapping_file=nil,
 
154
                     region=nil)
 
155
    
 
156
    src_s3_conn = make_s3_connection(s3_url, user, pass, bucket)
 
157
    dest_s3_conn = make_s3_connection(s3_url, user, pass, dest_bucket)
 
158
    
 
159
    # Locate destination bucket and create it if necessary.
 
160
    bu = BundleUploader.new()
 
161
    bucket_location = bu.get_bucket_location(dest_s3_conn, dest_bucket)
 
162
    bu.create_bucket(dest_s3_conn, dest_bucket, bucket_location, location, retry_stuff)
 
163
    
 
164
    # Region/location hack:
 
165
    if region.nil?
 
166
      location ||= bucket_location
 
167
      region = "us-east-1"
 
168
      region = "eu-west-1" if location == "EU"
 
169
      puts "Region not provided, guessing from S3 location: #{region}"
 
170
    end
 
171
    
 
172
    with_temp_dir(manifest_name) do |tempdir|
 
173
      manifest_path = File::join(tempdir, "temp-migration.manifest.xml")
 
174
      download_manifest(src_s3_conn, bucket, manifest_name, manifest_path, user_pk_path, retry_stuff)
 
175
      
 
176
      ManifestMigrator.new().migrate_manifest(manifest_path,
 
177
                                              user_pk_path,
 
178
                                              user_cert_path,
 
179
                                              kernel_id,
 
180
                                              ramdisk_id,
 
181
                                              region,
 
182
                                              use_mapping,
 
183
                                              mapping_url,
 
184
                                              mapping_file,
 
185
                                              true)
 
186
      
 
187
      create_bucket(dest_s3_conn, dest_bucket, location, retry_stuff)
 
188
      get_part_filenames(manifest_path, user_cert_path).each do |part|
 
189
        $stdout.puts("Copying '#{part}'...")
 
190
        copy_part(dest_s3_conn, bucket, dest_bucket, part, acl, retry_stuff)
 
191
      end
 
192
      upload_manifest(dest_s3_conn, manifest_name, manifest_path, dest_bucket, tempdir, acl, retry_stuff)
 
193
    end
 
194
  end
 
195
 
 
196
  #------------------------------------------------------------------------------#
 
197
  # Overrides
 
198
  #------------------------------------------------------------------------------#
 
199
 
 
200
  def get_manual()
 
201
    MIGRATE_BUNDLE_MANUAL
 
202
  end
 
203
 
 
204
  def get_name()
 
205
    MIGRATE_BUNDLE_NAME
 
206
  end
 
207
 
 
208
  def main(p)
 
209
    check_bucket_name(p.dest_bucket, p.interactive?)
 
210
    
 
211
    migrate_bundle(p.s3_url,
 
212
                   p.bucket,
 
213
                   p.dest_bucket,
 
214
                   p.manifest_name,
 
215
                   p.user_pk_path,
 
216
                   p.user_cert_path,
 
217
                   p.user,
 
218
                   p.pass,
 
219
                   p.location,
 
220
                   p.kernel_id,
 
221
                   p.ramdisk_id,
 
222
                   p.acl,
 
223
                   p.retry,
 
224
                   p.use_mapping,
 
225
                   p.mapping_url,
 
226
                   p.mapping_file,
 
227
                   p.region)
 
228
    
 
229
    $stdout.puts("\nYour new bundle is in S3 at the following location:")
 
230
    $stdout.puts("#{p.dest_bucket}/#{p.manifest_name}")
 
231
    $stdout.puts("Please register it using your favorite EC2 client.")
 
232
  end
 
233
 
 
234
end
 
235
 
 
236
#------------------------------------------------------------------------------#
 
237
# Script entry point. Execute only if this file is being executed.
 
238
if __FILE__ == $0
 
239
  BundleMigrator.new().run(MigrateBundleParameters)
 
240
end