2
# -*- coding: utf-8 -*-
4
# Software License Agreement (BSD License)
6
# Copyright (c) 2009, Eucalyptus Systems, Inc.
9
# Redistribution and use of this software in source and binary forms, with or
10
# without modification, are permitted provided that the following conditions
13
# Redistributions of source code must retain the above
14
# copyright notice, this list of conditions and the
15
# following disclaimer.
17
# Redistributions in binary form must reproduce the above
18
# copyright notice, this list of conditions and the
19
# following disclaimer in the documentation and/or other
20
# materials provided with the distribution.
22
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
# POSSIBILITY OF SUCH DAMAGE.
34
# Author: Neil Soman neil@eucalyptus.com
39
from euca2ools import Euca2ool, FileValidationError, \
40
DirValidationError, CopyError, MetadataReadError, Util, \
41
NotFoundError, CommandFailed, UnsupportedException
42
from subprocess import *
47
Bundle the local filesystem of a running instance as a bundled image.
49
euca-bundle-vol -u, --user user -s, --size size_in_MB
50
[-c, --cert cert_path] [-k, --privatekey private_key_path]
51
[-a, --all] [-e, --exclude dir1, dir2,...dirN] [-p, --prefix prefix] [--[no-]inherit] [-v, --volume volume_path] [--fstab fstab_path] [--generate-fstab] [--kernel kernel_id] [--ramdisk ramdisk_id] [-B, --block-device-mapping mapping]
52
[-d, --destination destination_path] [--ec2cert ec2cert_path] [-r, --arch target_architecture] [--batch] [--version]
56
-u, --user User ID (12-digit) of the user who is bundling the image.
58
-s, --size Size for the image in MB (default: 10GB or 10240MB).
62
-c, --cert Path to the user's PEM encoded certificate.
64
-k, --privatekey Path to the user's PEM encoded private key.
66
-a, --all Bundle all directories (including mounted filesystems).
68
-p, --prefix The prefix for the bundle image files. (default: image name).
70
--[no-]inherit Add (or do not add) instance metadata to the bundled image. Inherit is set by default.
72
-e, --exclude comma-separated list of directories to exclude.
74
--kernel The kernel to be associated with the bundled image.
76
--ramdisk The ramdisk to be associated with the bundled image.
78
-B, --block-device-mapping Default block device mapping for the image (comma-separated list of key=value pairs).
80
-d, --destination Directory to store the bundled image in (default: "/tmp"). Recommended.
82
--ec2cert The path to the Cloud's X509 public key certificate.
84
-r, --arch Target architecture for the image ('x86_64' or 'i386' default: 'x86_64').
86
-v, --volume Path to mounted volume to create the bundle from (default: "/").
88
--fstab Path to the fstab to be bundled into the image.
90
--generate-fstab Generate fstab to bundle into the image.
92
--batch Run in batch mode (compatibility only. has no effect).
95
MAX_IMAGE_SIZE = 1024 * 10
104
print Util().version()
109
if os.geteuid() == 0:
112
print 'Must be superuser to execute this command.'
116
def check_image_size(size):
117
if size > MAX_IMAGE_SIZE:
118
print 'Image Size is too large (Max = %d MB)' % MAX_IMAGE_SIZE
122
def parse_excludes(excludes_string):
125
excludes_string = excludes_string.replace(' ', '')
126
excludes = excludes_string.split(',')
130
def get_instance_metadata(
139
block_dev_mapping = mapping
140
ancestor_ami_ids = None
142
euca.can_read_instance_metadata()
145
ramdisk_id = euca.get_instance_ramdisk()
146
except MetadataReadError:
147
print 'Unable to read ramdisk id'
151
kernel_id = euca.get_instance_kernel()
152
except MetadataReadError:
153
print 'Unable to read kernel id'
155
if not block_dev_mapping:
157
block_dev_mapping = \
158
euca.get_instance_block_device_mappings()
159
except MetadataReadError:
160
print 'Unable to read block device mapping'
163
product_codes = euca.get_instance_product_codes().split('\n'
165
except MetadataReadError:
166
print 'Unable to read product codes'
169
ancestor_ami_ids = euca.get_ancestor_ami_ids().split('\n')
170
except MetadataReadError:
171
print 'Unable to read product codes'
174
print 'Unable to read instance metadata. Pass the --no-inherit option if you wish to exclude instance metadata.'
177
return (ramdisk_id, kernel_id, block_dev_mapping, product_codes,
181
def add_product_codes(product_code_string, product_codes):
182
if not product_codes:
184
product_code_values = product_code_string.split(',')
186
for p in product_code_values:
187
product_codes.append(p)
193
if os.path.exists(path):
200
euca = Euca2ool('a:c:k:u:B:d:br:p:s:v:e:', [
209
'block-device-mapping=',
230
cert_path = euca.get_environ('EC2_CERT')
231
private_key_path = euca.get_environ('EC2_PRIVATE_KEY')
232
ec2cert_path = euca.get_environ('EUCALYPTUS_CERT')
233
user_string = euca.get_environ('EC2_USER_ID')
234
except NotFoundError:
238
size_in_MB = 10 * 1024
239
destination_path = '/disk1'
240
target_arch = 'x86_64'
242
excludes_string = None
248
ancestor_ami_ids = None
250
generate_fstab = False
251
product_code_string = None
254
user = int(user_string)
256
print 'Invalid user', user_string
260
for (name, value) in euca.opts:
261
if name in ('-h', '--help'):
263
elif name in ('-c', '--cert'):
265
elif name in ('-k', '--privatekey'):
266
private_key_path = value
267
elif name in ('-u', '--user'):
269
value = value.replace('-', '')
272
print 'Invalid user', value
275
elif name == '--kernel':
277
elif name == '--ramdisk':
279
elif name in ('-p', '--prefix'):
281
elif name in ('-s', '--size'):
282
size_in_MB = int(value)
283
elif name in ('-v', '--volume'):
285
elif name in ('-e', '--exclude'):
286
excludes_string = value
287
elif name in ('-d', '--destination'):
288
destination_path = value
289
elif name == '--ec2cert':
291
elif name in ('-a', '--all'):
293
elif name in ('-r', '--arch'):
295
if target_arch != 'i386' and target_arch != 'x86_64':
296
print 'target architecture must be i386 or x86_64'
298
elif name in ('-B', '--block-device-mapping'):
300
elif name == '--no-inherit':
302
elif name == '--generate-fstab':
303
generate_fstab = True
304
elif name == '--fstab':
306
elif name == '--productcodes':
307
product_code_string = value
308
elif name == '--version':
311
if size_in_MB and cert_path and private_key_path and user \
314
euca.validate_file(cert_path)
315
except FileValidationError:
319
euca.validate_file(private_key_path)
320
except FileValidationError:
321
print 'Invalid private key'
324
euca.validate_file(ec2cert_path)
325
except FileValidationError:
326
print 'Invalid ec2cert'
329
euca.validate_dir(volume_path)
330
except DirValidationError:
331
print 'Invalid directory', volume_path
333
if generate_fstab and fstab_path:
334
print '--generate-fstab and --fstab path cannot both be set.'
338
euca.validate_file(fstab_path)
339
except FileValidationError:
340
print 'Invalid fstab path'
343
if platform.machine() == 'i386':
349
check_image_size(size_in_MB)
350
volume_path = os.path.normpath(volume_path)
352
excludes = parse_excludes(excludes_string)
353
euca.add_excludes(volume_path, excludes)
355
(ramdisk, kernel, mapping, product_codes,
356
ancestor_ami_ids) = get_instance_metadata(euca, ramdisk,
358
if product_code_string:
359
product_codes = add_product_codes(product_code_string,
362
image_path = euca.make_image(size_in_MB, excludes, prefix,
364
except NotFoundError:
366
except UnsupportedException:
368
image_path = os.path.normpath(image_path)
369
if image_path.find(volume_path) == 0:
370
exclude_image = image_path.replace(volume_path, '', 1)
371
image_path_parts = exclude_image.split('/')
372
if len(image_path_parts) > 1:
374
exclude_image.replace(image_path_parts[0] + '/', ''
376
excludes.append(exclude_image)
378
euca.copy_volume(image_path, volume_path, excludes,
379
generate_fstab, fstab_path)
381
print 'Unable to copy files'
384
except NotFoundError:
387
except CommandFailed:
390
except UnsupportedException:
394
(image_size, sha_image_digest) = euca.check_image(image_path,
397
prefix = euca.get_relative_filename(image_path)
399
tgz_file = euca.tarzip_image(prefix, image_path,
401
except NotFoundError:
403
except CommandFailed:
406
(encrypted_file, key, iv, bundled_size) = \
407
euca.encrypt_image(tgz_file)
409
(parts, parts_digest) = euca.split_image(encrypted_file)
410
euca.generate_manifest(
432
os.remove(encrypted_file)
435
# ....cleanup(image_path)
438
print 'size must be specified.'
440
print 'cert must be specified.'
441
if not private_key_path:
442
print 'privatekey must be specified.'
444
print 'user must be specified.'
446
defcert = "/usr/share/euca2ools/cert-ec2.pem"
447
if os.path.exists(defcert):
448
ec2cert_path = defcert
450
print 'ec2cert must be specified or exist in %s.' % defcert
454
if __name__ == '__main__':