Merge lp:~smoser/ubuntu/natty/euca2ools/euca2ools-1.3.1 into lp:ubuntu/natty/euca2ools

Proposed by Scott Moser on 2010-11-17
Status: Merged
Merged at revision: 25
Proposed branch: lp:~smoser/ubuntu/natty/euca2ools/euca2ools-1.3.1
Merge into: lp:ubuntu/natty/euca2ools
Diff against target: 17095 lines (+10928/-2506)
134 files modified
.pc/.quilt_patches (+1/-0)
.pc/.quilt_series (+1/-0)
.pc/.version (+1/-0)
.pc/applied-patches (+11/-0)
.pc/bundle-image-support-symlinks.patch/euca2ools/euca2ools/__init__.py (+1458/-0)
.pc/bundle-image-usage-on-invalid-user.patch/bin/euca-bundle-image (+285/-0)
.pc/bundle-vol-exclude-persistent-udev-net-rules.patch/bin/euca-bundle-vol (+456/-0)
.pc/bundle-vol-use-ec2-cert-by-default.patch/bin/euca-bundle-vol (+452/-0)
.pc/describe-image-attribute-empty-kernel-ramdisk.patch/bin/euca-describe-image-attribute (+166/-0)
.pc/describe-images-return-results-like-ec2-describe-images.patch/bin/euca-describe-images (+162/-0)
.pc/download-bundle-fix-usage.patch/bin/euca-download-bundle (+189/-0)
.pc/download-bundle-fix-usage.patch/man/euca-download-bundle.1 (+72/-0)
.pc/euca-revoke-exit-on-usage.patch/bin/euca-revoke (+202/-0)
.pc/print-instances-cleanup.patch/bin/euca-describe-instances (+156/-0)
.pc/print-instances-cleanup.patch/bin/euca-run-instances (+260/-0)
.pc/print-instances-cleanup.patch/euca2ools/euca2ools/__init__.py (+1458/-0)
.pc/run-instances-error-not-trace-on-bad-instance-count.patch/bin/euca-run-instances (+256/-0)
.pc/run-instances-usage-and-manpage-keypair.patch/bin/euca-run-instances (+256/-0)
.pc/run-instances-usage-and-manpage-keypair.patch/man/euca-run-instances.1 (+67/-0)
CHANGELOG (+17/-0)
INSTALL (+7/-7)
bin/euca-add-group (+33/-24)
bin/euca-add-keypair (+28/-20)
bin/euca-allocate-address (+21/-14)
bin/euca-associate-address (+39/-30)
bin/euca-attach-volume (+43/-36)
bin/euca-authorize (+96/-83)
bin/euca-bundle-image (+136/-91)
bin/euca-bundle-instance (+205/-0)
bin/euca-bundle-vol (+275/-200)
bin/euca-cancel-bundle-task (+120/-0)
bin/euca-confirm-product-instance (+42/-33)
bin/euca-create-snapshot (+38/-26)
bin/euca-create-volume (+60/-50)
bin/euca-delete-bundle (+137/-113)
bin/euca-delete-group (+25/-16)
bin/euca-delete-keypair (+27/-19)
bin/euca-delete-snapshot (+31/-23)
bin/euca-delete-volume (+32/-25)
bin/euca-deregister (+28/-22)
bin/euca-describe-addresses (+30/-19)
bin/euca-describe-availability-zones (+26/-16)
bin/euca-describe-bundle-tasks (+118/-0)
bin/euca-describe-groups (+42/-30)
bin/euca-describe-image-attribute (+70/-53)
bin/euca-describe-images (+51/-24)
bin/euca-describe-instances (+40/-31)
bin/euca-describe-keypairs (+26/-18)
bin/euca-describe-regions (+26/-17)
bin/euca-describe-snapshots (+36/-24)
bin/euca-describe-volumes (+53/-37)
bin/euca-detach-volume (+37/-28)
bin/euca-disassociate-address (+27/-20)
bin/euca-download-bundle (+72/-59)
bin/euca-get-console-output (+35/-26)
bin/euca-get-password (+126/-0)
bin/euca-get-password-data (+106/-0)
bin/euca-modify-image-attribute (+59/-46)
bin/euca-reboot-instances (+29/-21)
bin/euca-register (+94/-21)
bin/euca-release-address (+29/-21)
bin/euca-reset-image-attribute (+32/-24)
bin/euca-revoke (+92/-77)
bin/euca-run-instances (+145/-100)
bin/euca-terminate-instances (+30/-21)
bin/euca-unbundle (+77/-65)
bin/euca-upload-bundle (+118/-87)
bin/euca-version (+20/-13)
debian/changelog (+7/-0)
debian/patches/bundle-image-support-symlinks.patch (+17/-0)
debian/patches/bundle-image-usage-on-invalid-user.patch (+54/-0)
debian/patches/bundle-vol-exclude-persistent-udev-net-rules.patch (+31/-0)
debian/patches/bundle-vol-use-ec2-cert-by-default.patch (+20/-0)
debian/patches/describe-image-attribute-empty-kernel-ramdisk.patch (+26/-0)
debian/patches/describe-images-return-results-like-ec2-describe-images.patch (+92/-0)
debian/patches/download-bundle-fix-usage.patch (+39/-0)
debian/patches/euca-revoke-exit-on-usage.patch (+19/-0)
debian/patches/print-instances-cleanup.patch (+122/-0)
debian/patches/run-instances-error-not-trace-on-bad-instance-count.patch (+33/-0)
debian/patches/run-instances-usage-and-manpage-keypair.patch (+49/-0)
debian/patches/series (+11/-0)
debian/source/format (+1/-0)
debian/watch (+1/-1)
euca2ools.spec (+76/-42)
euca2ools/euca2ools/__init__.py (+995/-639)
euca2ools/setup.py (+21/-17)
man/euca-add-group.1 (+1/-1)
man/euca-add-keypair.1 (+1/-1)
man/euca-allocate-address.1 (+1/-1)
man/euca-associate-address.1 (+1/-1)
man/euca-attach-volume.1 (+1/-1)
man/euca-authorize.1 (+1/-1)
man/euca-bundle-image.1 (+1/-1)
man/euca-bundle-instance.1 (+46/-0)
man/euca-bundle-vol.1 (+1/-1)
man/euca-cancel-bundle-task.1 (+32/-0)
man/euca-confirm-product-instance.1 (+1/-1)
man/euca-create-snapshot.1 (+1/-1)
man/euca-create-volume.1 (+2/-2)
man/euca-delete-bundle.1 (+1/-1)
man/euca-delete-group.1 (+1/-1)
man/euca-delete-keypair.1 (+1/-1)
man/euca-delete-snapshot.1 (+1/-1)
man/euca-delete-volume.1 (+1/-1)
man/euca-deregister.1 (+1/-1)
man/euca-describe-addresses.1 (+1/-1)
man/euca-describe-availability-zones.1 (+1/-1)
man/euca-describe-bundle-tasks.1 (+33/-0)
man/euca-describe-groups.1 (+1/-1)
man/euca-describe-image-attribute.1 (+1/-1)
man/euca-describe-images.1 (+1/-1)
man/euca-describe-instances.1 (+1/-1)
man/euca-describe-keypairs.1 (+1/-1)
man/euca-describe-regions.1 (+1/-1)
man/euca-describe-snapshots.1 (+1/-1)
man/euca-describe-volumes.1 (+1/-1)
man/euca-detach-volume.1 (+1/-1)
man/euca-disassociate-address.1 (+1/-1)
man/euca-download-bundle.1 (+3/-3)
man/euca-get-console-output.1 (+1/-1)
man/euca-get-password-data.1 (+32/-0)
man/euca-get-password.1 (+34/-0)
man/euca-modify-image-attribute.1 (+6/-5)
man/euca-reboot-instances.1 (+1/-1)
man/euca-register.1 (+20/-4)
man/euca-release-address.1 (+1/-1)
man/euca-reset-image-attribute.1 (+2/-2)
man/euca-revoke.1 (+1/-1)
man/euca-run-instances.1 (+34/-23)
man/euca-terminate-instances.1 (+1/-1)
man/euca-unbundle.1 (+1/-1)
man/euca-upload-bundle.1 (+1/-1)
man/euca-version.1 (+2/-2)
util/euca2ools (+38/-1)
To merge this branch: bzr merge lp:~smoser/ubuntu/natty/euca2ools/euca2ools-1.3.1
Reviewer Review Type Date Requested Status
Dave Walker 2010-11-17 Approve on 2010-11-17
Dustin Kirkland  2010-11-17 Pending
Ubuntu branches 2010-11-17 Pending
Review via email: mp+41105@code.launchpad.net
To post a comment you must log in.
Dave Walker (davewalker) wrote :

Nice one Scott!

Have you had any success in pushing these patches upstream?

Are you able to get this uploaded ASAP... would be good to start hammering it..

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc'
2=== added file '.pc/.quilt_patches'
3--- .pc/.quilt_patches 1970-01-01 00:00:00 +0000
4+++ .pc/.quilt_patches 2010-11-17 22:00:42 +0000
5@@ -0,0 +1,1 @@
6+debian/patches
7
8=== added file '.pc/.quilt_series'
9--- .pc/.quilt_series 1970-01-01 00:00:00 +0000
10+++ .pc/.quilt_series 2010-11-17 22:00:42 +0000
11@@ -0,0 +1,1 @@
12+series
13
14=== added file '.pc/.version'
15--- .pc/.version 1970-01-01 00:00:00 +0000
16+++ .pc/.version 2010-11-17 22:00:42 +0000
17@@ -0,0 +1,1 @@
18+2
19
20=== added file '.pc/applied-patches'
21--- .pc/applied-patches 1970-01-01 00:00:00 +0000
22+++ .pc/applied-patches 2010-11-17 22:00:42 +0000
23@@ -0,0 +1,11 @@
24+bundle-vol-use-ec2-cert-by-default.patch
25+bundle-image-support-symlinks.patch
26+describe-images-return-results-like-ec2-describe-images.patch
27+run-instances-usage-and-manpage-keypair.patch
28+run-instances-error-not-trace-on-bad-instance-count.patch
29+print-instances-cleanup.patch
30+euca-revoke-exit-on-usage.patch
31+download-bundle-fix-usage.patch
32+bundle-image-usage-on-invalid-user.patch
33+describe-image-attribute-empty-kernel-ramdisk.patch
34+bundle-vol-exclude-persistent-udev-net-rules.patch
35
36=== added directory '.pc/bundle-image-support-symlinks.patch'
37=== added file '.pc/bundle-image-support-symlinks.patch/.timestamp'
38=== added directory '.pc/bundle-image-support-symlinks.patch/euca2ools'
39=== added directory '.pc/bundle-image-support-symlinks.patch/euca2ools/euca2ools'
40=== added file '.pc/bundle-image-support-symlinks.patch/euca2ools/euca2ools/__init__.py'
41--- .pc/bundle-image-support-symlinks.patch/euca2ools/euca2ools/__init__.py 1970-01-01 00:00:00 +0000
42+++ .pc/bundle-image-support-symlinks.patch/euca2ools/euca2ools/__init__.py 2010-11-17 22:00:42 +0000
43@@ -0,0 +1,1458 @@
44+#!/usr/bin/python
45+# -*- coding: utf-8 -*-
46+# Software License Agreement (BSD License)
47+#
48+# Copyright (c) 2009, Eucalyptus Systems, Inc.
49+# All rights reserved.
50+#
51+# Redistribution and use of this software in source and binary forms, with or
52+# without modification, are permitted provided that the following conditions
53+# are met:
54+#
55+# Redistributions of source code must retain the above
56+# copyright notice, this list of conditions and the
57+# following disclaimer.
58+#
59+# Redistributions in binary form must reproduce the above
60+# copyright notice, this list of conditions and the
61+# following disclaimer in the documentation and/or other
62+# materials provided with the distribution.
63+#
64+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
65+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
68+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
69+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
70+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
71+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
72+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
73+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
74+# POSSIBILITY OF SUCH DAMAGE.
75+#
76+# Author: Neil Soman neil@eucalyptus.com
77+
78+import boto
79+import getopt
80+import sys
81+import os
82+import tarfile
83+from xml.dom.minidom import Document
84+from xml.dom import minidom
85+from hashlib import sha1 as sha
86+from M2Crypto import BN, EVP, RSA, X509
87+from binascii import hexlify, unhexlify
88+from subprocess import *
89+import platform
90+import urllib
91+import re
92+import shutil
93+from boto.ec2.regioninfo import RegionInfo
94+from boto.ec2.blockdevicemapping import BlockDeviceMapping
95+from boto.ec2.blockdevicemapping import EBSBlockDeviceType
96+from boto.ec2.connection import EC2Connection
97+from boto.resultset import ResultSet
98+import logging
99+import base64
100+
101+BUNDLER_NAME = 'euca-tools'
102+BUNDLER_VERSION = '1.3'
103+VERSION = '2007-10-10'
104+RELEASE = '31337'
105+AES = 'AES-128-CBC'
106+
107+IP_PROTOCOLS = ['tcp', 'udp', 'icmp']
108+
109+IMAGE_IO_CHUNK = 10 * 1024
110+IMAGE_SPLIT_CHUNK = IMAGE_IO_CHUNK * 1024
111+MAX_LOOP_DEVS = 256
112+
113+METADATA_URL = 'http://169.254.169.254/latest/meta-data/'
114+
115+#
116+# Monkey patch the SAX endElement handler in boto's
117+# BlockDeviceMapping class to not break on Eucalyptus's
118+# DescribeImageAttribute output. It's impossible to test
119+# this against EC2 because EC2 will not let you run a
120+# DescribeImageAttribute on the blockDeviceMapping attribute,
121+# even for an image you own.
122+#
123+def endElement(self, name, value, connection):
124+ if name == 'virtualName':
125+ self.current_vname = value
126+ elif name == 'device' or name == 'deviceName':
127+ if hasattr(self, 'current_vname') and self.current_vname:
128+ self[self.current_vname] = value
129+ self.current_vname = None
130+ else:
131+ self.current_name = value
132+
133+BlockDeviceMapping.endElement = endElement
134+
135+#
136+# Monkey patch the register_image method from EC2Connection
137+# The one in 1.9b required a value for the "name" parameter
138+# but in fact that parameter is only required for EBS-backed
139+# images. So, an EBS image needs a name but not a location
140+# and the S3 image needs a location but not a name.
141+#
142+def register_image(self, name=None, description=None, image_location=None,
143+ architecture=None, kernel_id=None, ramdisk_id=None,
144+ root_device_name=None, block_device_map=None):
145+ """
146+ Register an image.
147+
148+ :type name: string
149+ :param name: The name of the AMI. Valid only for EBS-based images.
150+
151+ :type description: string
152+ :param description: The description of the AMI.
153+
154+ :type image_location: string
155+ :param image_location: Full path to your AMI manifest in Amazon S3 storage.
156+ Only used for S3-based AMI's.
157+
158+ :type architecture: string
159+ :param architecture: The architecture of the AMI. Valid choices are:
160+ i386 | x86_64
161+
162+ :type kernel_id: string
163+ :param kernel_id: The ID of the kernel with which to launch the instances
164+
165+ :type root_device_name: string
166+ :param root_device_name: The root device name (e.g. /dev/sdh)
167+
168+ :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping`
169+ :param block_device_map: A BlockDeviceMapping data structure
170+ describing the EBS volumes associated
171+ with the Image.
172+
173+ :rtype: string
174+ :return: The new image id
175+ """
176+ params = {}
177+ if name:
178+ params['Name'] = name
179+ if description:
180+ params['Description'] = description
181+ if architecture:
182+ params['Architecture'] = architecture
183+ if kernel_id:
184+ params['KernelId'] = kernel_id
185+ if ramdisk_id:
186+ params['RamdiskId'] = ramdisk_id
187+ if image_location:
188+ params['ImageLocation'] = image_location
189+ if root_device_name:
190+ params['RootDeviceName'] = root_device_name
191+ if block_device_map:
192+ block_device_map.build_list_params(params)
193+ rs = self.get_object('RegisterImage', params, ResultSet)
194+ image_id = getattr(rs, 'imageId', None)
195+ return image_id
196+
197+EC2Connection.register_image = register_image
198+
199+class LinuxImage:
200+
201+ ALLOWED_FS_TYPES = ['ext2', 'ext3', 'xfs', 'jfs', 'reiserfs']
202+ BANNED_MOUNTS = [
203+ '/dev',
204+ '/media',
205+ '/mnt',
206+ '/proc',
207+ '/sys',
208+ '/cdrom',
209+ '/tmp',
210+ ]
211+ ESSENTIAL_DIRS = ['proc', 'tmp', 'dev', 'mnt', 'sys']
212+ ESSENTIAL_DEVS = [
213+ [os.path.join('dev', 'console'), 'c', '5', '1'],
214+ [os.path.join('dev', 'full'), 'c', '1', '7'],
215+ [os.path.join('dev', 'null'), 'c', '1', '3'],
216+ [os.path.join('dev', 'zero'), 'c', '1', '5'],
217+ [os.path.join('dev', 'tty'), 'c', '5', '0'],
218+ [os.path.join('dev', 'tty0'), 'c', '4', '0'],
219+ [os.path.join('dev', 'tty1'), 'c', '4', '1'],
220+ [os.path.join('dev', 'tty2'), 'c', '4', '2'],
221+ [os.path.join('dev', 'tty3'), 'c', '4', '3'],
222+ [os.path.join('dev', 'tty4'), 'c', '4', '4'],
223+ [os.path.join('dev', 'tty5'), 'c', '4', '5'],
224+ [os.path.join('dev', 'xvc0'), 'c', '204', '191'],
225+ ]
226+ MAKEFS_CMD = 'mkfs.ext3'
227+ NEW_FSTAB = \
228+ """
229+/dev/sda1 / ext3 defaults 1 1
230+/dev/sdb /mnt ext3 defaults 0 0
231+none /dev/pts devpts gid=5,mode=620 0 0
232+none /proc proc defaults 0 0
233+none /sys sysfs defaults 0 0
234+ """
235+
236+ OLD_FSTAB = \
237+ """/dev/sda1 / ext3 defaults,errors=remount-ro 0 0
238+/dev/sda2 /mnt ext3 defaults 0 0
239+/dev/sda3 swap swap defaults 0 0
240+proc /proc proc defaults 0 0
241+devpts /dev/pts devpts gid=5,mode=620 0 0"""
242+
243+ def __init__(self, debug=False):
244+ self.debug = debug
245+
246+ def create_image(self, size_in_MB, image_path):
247+ dd_cmd = ['dd']
248+ dd_cmd.append('if=/dev/zero')
249+ dd_cmd.append('of=%s' % image_path)
250+ dd_cmd.append('count=1')
251+ dd_cmd.append('bs=1M')
252+ dd_cmd.append('seek=%s' % (size_in_MB - 1))
253+ if self.debug:
254+ print 'Creating disk image...', image_path
255+ Popen(dd_cmd, PIPE).communicate()[0]
256+
257+ def make_fs(self, image_path):
258+ Util().check_prerequisite_command(self.MAKEFS_CMD)
259+
260+ if self.debug:
261+ print 'Creating filesystem...'
262+ makefs_cmd = Popen([self.MAKEFS_CMD, '-F', image_path],
263+ PIPE).communicate()[0]
264+
265+ def add_fstab(
266+ self,
267+ mount_point,
268+ generate_fstab,
269+ fstab_path,
270+ ):
271+ if not fstab_path:
272+ return
273+ fstab = None
274+ if fstab_path == 'old':
275+ if not generate_fstab:
276+ return
277+ fstab = self.OLD_FSTAB
278+ elif fstab_path == 'new':
279+ if not generate_fstab:
280+ return
281+ fstab = self.NEW_FSTAB
282+
283+ etc_file_path = os.path.join(mount_point, 'etc')
284+ fstab_file_path = os.path.join(etc_file_path, 'fstab')
285+ if not os.path.exists(etc_file_path):
286+ os.mkdir(etc_file_path)
287+ else:
288+ if os.path.exists(fstab_file_path):
289+ fstab_copy_path = fstab_file_path + '.old'
290+ shutil.copyfile(fstab_file_path, fstab_copy_path)
291+
292+ if self.debug:
293+ print 'Updating fstab entry'
294+ fstab_file = open(fstab_file_path, 'w')
295+ if fstab:
296+ fstab_file.write(fstab)
297+ else:
298+ orig_fstab_file = open(fstab_path, 'r')
299+ while 1:
300+ data = orig_fstab_file.read(IMAGE_IO_CHUNK)
301+ if not data:
302+ break
303+ fstab_file.write(data)
304+ orig_fstab_file.close()
305+ fstab_file.close()
306+
307+ def make_essential_devs(self, image_path):
308+ for entry in self.ESSENTIAL_DEVS:
309+ cmd = ['mknod']
310+ entry[0] = os.path.join(image_path, entry[0])
311+ cmd.extend(entry)
312+ Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
313+
314+
315+class SolarisImage:
316+
317+ ALLOWED_FS_TYPES = ['ext2', 'ext3', 'xfs', 'jfs', 'reiserfs']
318+ BANNED_MOUNTS = [
319+ '/dev',
320+ '/media',
321+ '/mnt',
322+ '/proc',
323+ '/sys',
324+ '/cdrom',
325+ '/tmp',
326+ ]
327+ ESSENTIAL_DIRS = ['proc', 'tmp', 'dev', 'mnt', 'sys']
328+
329+ def __init__(self, debug=False):
330+ self.debug = debug
331+
332+ def create_image(self, size_in_MB, image_path):
333+ print 'Sorry. Solaris not supported yet'
334+ raise UnsupportedException
335+
336+ def make_fs(self, image_path):
337+ print 'Sorry. Solaris not supported yet'
338+ raise UnsupportedException
339+
340+ def make_essential_devs(self, image_path):
341+ print 'Sorry. Solaris not supported yet'
342+ raise UnsupportedException
343+
344+
345+class Util:
346+
347+ usage_string = \
348+ """
349+-a, --access-key User's Access Key ID.
350+
351+-s, --secret-key User's Secret Key.
352+
353+-U, --url URL of the Cloud to connect to.
354+
355+--config Read credentials and cloud settings from the
356+ specified config file (defaults to $HOME/.eucarc or /etc/euca2ools/eucarc).
357+
358+-h, --help Display this help message.
359+
360+--version Display the version of this tool.
361+
362+--debug Turn on debugging.
363+
364+Euca2ools will use the environment variables EC2_URL, EC2_ACCESS_KEY, EC2_SECRET_KEY, EC2_CERT, EC2_PRIVATE_KEY, S3_URL, EUCALYPTUS_CERT by default.
365+ """
366+
367+ version_string = """ Version: 1.2 (BSD)"""
368+
369+ def version(self):
370+ return self.version_string
371+
372+ def usage(self, compat=False):
373+ if compat:
374+ self.usage_string = self.usage_string.replace('-s,', '-S,')
375+ self.usage_string = self.usage_string.replace('-a,', '-A,')
376+ print self.usage_string
377+
378+ def check_prerequisite_command(self, command):
379+ cmd = [command]
380+ try:
381+ output = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
382+ except OSError, e:
383+ error_string = '%s' % e
384+ if 'No such' in error_string:
385+ print 'Command %s not found. Is it installed?' % command
386+ raise NotFoundError
387+ else:
388+ raise OSError(e)
389+
390+
391+class AddressValidationError:
392+
393+ def __init__(self):
394+ self.message = 'Invalid address'
395+
396+
397+class InstanceValidationError:
398+
399+ def __init__(self):
400+ self.message = 'Invalid instance id'
401+
402+
403+class VolumeValidationError:
404+
405+ def __init__(self):
406+ self.message = 'Invalid volume id'
407+
408+
409+class SizeValidationError:
410+
411+ def __init__(self):
412+ self.message = 'Invalid size'
413+
414+
415+class SnapshotValidationError:
416+
417+ def __init__(self):
418+ self.message = 'Invalid snapshot id'
419+
420+
421+class ProtocolValidationError:
422+
423+ def __init__(self):
424+ self.message = 'Invalid protocol'
425+
426+
427+class FileValidationError:
428+
429+ def __init__(self):
430+ self.message = 'Invalid file'
431+
432+
433+class DirValidationError:
434+
435+ def __init__(self):
436+ self.message = 'Invalid directory'
437+
438+
439+class BundleValidationError:
440+
441+ def __init__(self):
442+ self.message = 'Invalid bundle id'
443+
444+
445+class CopyError:
446+
447+ def __init__(self):
448+ self.message = 'Unable to copy'
449+
450+
451+class MetadataReadError:
452+
453+ def __init__(self):
454+ self.message = 'Unable to read metadata'
455+
456+
457+class NullHandler(logging.Handler):
458+
459+ def emit(self, record):
460+ pass
461+
462+
463+class NotFoundError:
464+
465+ def __init__(self):
466+ self.message = 'Unable to find'
467+
468+
469+class UnsupportedException:
470+
471+ def __init__(self):
472+ self.message = 'Not supported'
473+
474+
475+class CommandFailed:
476+
477+ def __init__(self):
478+ self.message = 'Command failed'
479+
480+
481+class ConnectionFailed:
482+
483+ def __init__(self):
484+ self.message = 'Connection failed'
485+
486+
487+class ParseError:
488+
489+ def __init__(self, msg):
490+ self.message = msg
491+
492+
493+class Euca2ool:
494+
495+ def process_args(self):
496+ ids = []
497+ for arg in self.args:
498+ ids.append(arg)
499+ return ids
500+
501+ def __init__(
502+ self,
503+ short_opts=None,
504+ long_opts=None,
505+ is_s3=False,
506+ compat=False,
507+ ):
508+ self.ec2_user_access_key = None
509+ self.ec2_user_secret_key = None
510+ self.ec2_url = None
511+ self.s3_url = None
512+ self.config_file_path = None
513+ self.is_s3 = is_s3
514+ if compat:
515+ self.secret_key_opt = 'S'
516+ self.access_key_opt = 'A'
517+ else:
518+ self.secret_key_opt = 's'
519+ self.access_key_opt = 'a'
520+ if not short_opts:
521+ short_opts = ''
522+ if not long_opts:
523+ long_opts = ['']
524+ short_opts += 'hU:'
525+ short_opts += '%s:' % self.secret_key_opt
526+ short_opts += '%s:' % self.access_key_opt
527+ long_opts += [
528+ 'access-key=',
529+ 'secret-key=',
530+ 'url=',
531+ 'help',
532+ 'version',
533+ 'debug',
534+ 'config=',
535+ ]
536+ (opts, args) = getopt.gnu_getopt(sys.argv[1:], short_opts,
537+ long_opts)
538+ self.opts = opts
539+ self.args = args
540+ self.debug = False
541+ for (name, value) in opts:
542+ if name in ('-%s' % self.access_key_opt, '--access-key'):
543+ self.ec2_user_access_key = value
544+ elif name in ('-%s' % self.secret_key_opt, '--secret-key'):
545+ try:
546+ self.ec2_user_secret_key = int(value)
547+ self.ec2_user_secret_key = None
548+ except ValueError:
549+ self.ec2_user_secret_key = value
550+ elif name in ('-U', '--url'):
551+ self.ec2_url = value
552+ elif name == '--debug':
553+ self.debug = True
554+ elif name == '--config':
555+ self.config_file_path = value
556+ system_string = platform.system()
557+ if system_string == 'Linux':
558+ self.img = LinuxImage(self.debug)
559+ elif system_string == 'SunOS':
560+ self.img = SolarisImage(self.debug)
561+ else:
562+ self.img = 'Unsupported'
563+ self.setup_environ()
564+
565+ h = NullHandler()
566+ logging.getLogger('boto').addHandler(h)
567+
568+ SYSTEM_EUCARC_PATH = os.path.join('/etc', 'euca2ools', 'eucarc')
569+
570+ def setup_environ(self):
571+ envlist = (
572+ 'EC2_ACCESS_KEY',
573+ 'EC2_SECRET_KEY',
574+ 'S3_URL',
575+ 'EC2_URL',
576+ 'EC2_CERT',
577+ 'EC2_PRIVATE_KEY',
578+ 'EUCALYPTUS_CERT',
579+ 'EC2_USER_ID',
580+ )
581+ self.environ = {}
582+ user_eucarc = None
583+ if 'HOME' in os.environ:
584+ user_eucarc = os.path.join(os.getenv('HOME'), '.eucarc')
585+ read_config = False
586+ if self.config_file_path \
587+ and os.path.exists(self.config_file_path):
588+ read_config = self.config_file_path
589+ elif user_eucarc is not None and os.path.exists(user_eucarc):
590+ read_config = user_eucarc
591+ elif os.path.exists(self.SYSTEM_EUCARC_PATH):
592+ read_config = self.SYSTEM_EUCARC_PATH
593+ if read_config:
594+ parse_config(read_config, self.environ, envlist)
595+ else:
596+ for v in envlist:
597+ self.environ[v] = os.getenv(v)
598+
599+ def get_environ(self, name):
600+ if self.environ.has_key(name):
601+ return self.environ[name]
602+ else:
603+ print '%s not found' % name
604+ raise NotFoundError
605+
606+ def make_connection(self):
607+ if not self.ec2_user_access_key:
608+ self.ec2_user_access_key = self.environ['EC2_ACCESS_KEY']
609+ if not self.ec2_user_access_key:
610+ print 'EC2_ACCESS_KEY environment variable must be set.'
611+ raise ConnectionFailed
612+
613+ if not self.ec2_user_secret_key:
614+ self.ec2_user_secret_key = self.environ['EC2_SECRET_KEY']
615+ if not self.ec2_user_secret_key:
616+ print 'EC2_SECRET_KEY environment variable must be set.'
617+ raise ConnectionFailed
618+
619+ if not self.is_s3:
620+ if not self.ec2_url:
621+ self.ec2_url = self.environ['EC2_URL']
622+ if not self.ec2_url:
623+ self.ec2_url = \
624+ 'http://localhost:8773/services/Eucalyptus'
625+ print 'EC2_URL not specified. Trying %s' \
626+ % self.ec2_url
627+ else:
628+ if not self.ec2_url:
629+ self.ec2_url = self.environ['S3_URL']
630+ if not self.ec2_url:
631+ self.ec2_url = \
632+ 'http://localhost:8773/services/Walrus'
633+ print 'S3_URL not specified. Trying %s' \
634+ % self.ec2_url
635+
636+ self.port = None
637+ self.service_path = '/'
638+ if self.ec2_url.find('https://') >= 0:
639+ self.ec2_url = self.ec2_url.replace('https://', '')
640+ self.is_secure = True
641+ else:
642+ self.ec2_url = self.ec2_url.replace('http://', '')
643+ self.is_secure = False
644+ self.host = self.ec2_url
645+ url_parts = self.ec2_url.split(':')
646+ if len(url_parts) > 1:
647+ self.host = url_parts[0]
648+ path_parts = url_parts[1].split('/', 1)
649+ if len(path_parts) > 1:
650+ self.port = int(path_parts[0])
651+ self.service_path = self.service_path + path_parts[1]
652+ else:
653+ self.port = int(url_parts[1])
654+
655+ if not self.is_s3:
656+ return EC2Connection(
657+ aws_access_key_id=self.ec2_user_access_key,
658+ aws_secret_access_key=self.ec2_user_secret_key,
659+ is_secure=self.is_secure,
660+ region=RegionInfo(None, 'eucalyptus', self.host),
661+ port=self.port,
662+ path=self.service_path,
663+ )
664+ else:
665+ return boto.s3.Connection(
666+ aws_access_key_id=self.ec2_user_access_key,
667+ aws_secret_access_key=self.ec2_user_secret_key,
668+ is_secure=self.is_secure,
669+ host=self.host,
670+ port=self.port,
671+ calling_format=boto.s3.connection.OrdinaryCallingFormat(),
672+ path=self.service_path,
673+ )
674+
675+ def validate_address(self, address):
676+ if not re.match("[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(\/[0-9]+)?$",
677+ address):
678+ raise AddressValidationError
679+
680+ def validate_instance_id(self, id):
681+ if not re.match('i-', id):
682+ raise InstanceValidationError
683+
684+ def validate_volume_id(self, id):
685+ if not re.match('vol-', id):
686+ raise VolumeValidationError
687+
688+ def validate_volume_size(self, size):
689+ if size < 0 or size > 1024:
690+ raise SizeValidationError
691+
692+ def validate_snapshot_id(self, id):
693+ if not re.match('snap-', id):
694+ raise SnapshotValidationError
695+
696+ def validate_protocol(self, proto):
697+ if not proto in IP_PROTOCOLS:
698+ raise ProtocolValidationError
699+
700+ def validate_file(self, path):
701+ if not os.path.exists(path) or not os.path.isfile(path):
702+ raise FileValidationError
703+
704+ def validate_dir(self, path):
705+ if not os.path.exists(path) or not os.path.isdir(path):
706+ raise DirValidationError
707+
708+ def validate_bundle_id(self, id):
709+ if not re.match('bun-', id):
710+ raise BundleValidationError
711+
712+ def get_relative_filename(self, filename):
713+ f_parts = filename.split('/')
714+ return f_parts[len(f_parts) - 1]
715+
716+ def get_file_path(self, filename):
717+ relative_filename = self.get_relative_filename(filename)
718+ file_path = os.path.dirname(filename)
719+ if len(file_path) == 0:
720+ file_path = '.'
721+ return file_path
722+
723+ def split_file(self, file, chunk_size):
724+ parts = []
725+ parts_digest = []
726+ file_size = os.path.getsize(file)
727+ in_file = open(file, 'rb')
728+ number_parts = int(file_size / chunk_size)
729+ number_parts += 1
730+ bytes_read = 0
731+ for i in range(0, number_parts, 1):
732+ filename = '%s.%d' % (file, i)
733+ part_digest = sha()
734+ file_part = open(filename, 'wb')
735+ print 'Part:', self.get_relative_filename(filename)
736+ part_bytes_written = 0
737+ while part_bytes_written < IMAGE_SPLIT_CHUNK:
738+ data = in_file.read(IMAGE_IO_CHUNK)
739+ file_part.write(data)
740+ part_digest.update(data)
741+ data_len = len(data)
742+ part_bytes_written += data_len
743+ bytes_read += data_len
744+ if bytes_read >= file_size:
745+ break
746+ file_part.close()
747+ parts.append(filename)
748+ parts_digest.append(hexlify(part_digest.digest()))
749+
750+ in_file.close()
751+ return (parts, parts_digest)
752+
753+ def check_image(self, image_file, path):
754+ print 'Checking image'
755+ if not os.path.exists(path):
756+ os.makedirs(path)
757+ image_size = os.path.getsize(image_file)
758+ if self.debug:
759+ print 'Image Size:', image_size, 'bytes'
760+ in_file = open(image_file, 'rb')
761+ sha_image = sha()
762+ while 1:
763+ buf = in_file.read(IMAGE_IO_CHUNK)
764+ if not buf:
765+ break
766+ sha_image.update(buf)
767+ return (image_size, hexlify(sha_image.digest()))
768+
769+ def tarzip_image(
770+ self,
771+ prefix,
772+ file,
773+ path,
774+ ):
775+ Util().check_prerequisite_command('tar')
776+
777+ print 'Tarring image'
778+ tar_file = '%s.tar.gz' % os.path.join(path, prefix)
779+ outfile = open(tar_file, 'wb')
780+ file_path = self.get_file_path(file)
781+ tar_cmd = ['tar', 'c', '-S']
782+ if file_path:
783+ tar_cmd.append('-C')
784+ tar_cmd.append(file_path)
785+ tar_cmd.append(self.get_relative_filename(file))
786+ else:
787+ tar_cmd.append(file)
788+ p1 = Popen(tar_cmd, stdout=PIPE)
789+ p2 = Popen(['gzip'], stdin=p1.stdout, stdout=outfile)
790+ p2.communicate()
791+ outfile.close
792+ if os.path.getsize(tar_file) <= 0:
793+ print 'Could not tar image'
794+ raise CommandFailed
795+ return tar_file
796+
797+ def hexToBytes(self, hexString):
798+ bytes = []
799+ hexString = ''.join(hexString.split(' '))
800+ for i in range(0, len(hexString), 2):
801+ bytes.append(chr(int(hexString[i:i + 2], 16)))
802+
803+ return ''.join(bytes)
804+
805+ def crypt_file(
806+ self,
807+ cipher,
808+ in_file,
809+ out_file,
810+ ):
811+ while 1:
812+ buf = in_file.read(IMAGE_IO_CHUNK)
813+ if not buf:
814+ break
815+ out_file.write(cipher.update(buf))
816+ out_file.write(cipher.final())
817+
818+ def encrypt_image(self, file):
819+ print 'Encrypting image'
820+ enc_file = '%s.part' % file.replace('.tar.gz', '')
821+
822+ key = hex(BN.rand(16 * 8))[2:34].replace('L', 'c')
823+ if self.debug:
824+ print 'Key: %s' % key
825+ iv = hex(BN.rand(16 * 8))[2:34].replace('L', 'c')
826+ if self.debug:
827+ print 'IV: %s' % iv
828+
829+ k = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(key),
830+ iv=unhexlify(iv), op=1)
831+
832+ in_file = open(file)
833+ out_file = open(enc_file, 'wb')
834+ self.crypt_file(k, in_file, out_file)
835+ in_file.close()
836+ out_file.close()
837+ bundled_size = os.path.getsize(enc_file)
838+ return (enc_file, key, iv, bundled_size)
839+
840+ def split_image(self, file):
841+ print 'Splitting image...'
842+ return self.split_file(file, IMAGE_SPLIT_CHUNK)
843+
844+ def get_verification_string(self, manifest_string):
845+ start_mc = manifest_string.find('<machine_configuration>')
846+ end_mc = manifest_string.find('</machine_configuration>')
847+ mc_config_string = manifest_string[start_mc:end_mc
848+ + len('</machine_configuration>')]
849+ start_image = manifest_string.find('<image>')
850+ end_image = manifest_string.find('</image>')
851+ image_string = manifest_string[start_image:end_image
852+ + len('</image>')]
853+
854+ return mc_config_string + image_string
855+
856+ def parse_manifest(self, manifest_filename):
857+ parts = []
858+ encrypted_key = None
859+ encrypted_iv = None
860+ dom = minidom.parse(manifest_filename)
861+ manifest_elem = dom.getElementsByTagName('manifest')[0]
862+ parts_list = manifest_elem.getElementsByTagName('filename')
863+ for part_elem in parts_list:
864+ nodes = part_elem.childNodes
865+ for node in nodes:
866+ if node.nodeType == node.TEXT_NODE:
867+ parts.append(node.data)
868+ encrypted_key_elem = \
869+ manifest_elem.getElementsByTagName('user_encrypted_key')[0]
870+ nodes = encrypted_key_elem.childNodes
871+ for node in nodes:
872+ if node.nodeType == node.TEXT_NODE:
873+ encrypted_key = node.data
874+ encrypted_iv_elem = \
875+ manifest_elem.getElementsByTagName('user_encrypted_iv')[0]
876+ nodes = encrypted_iv_elem.childNodes
877+ for node in nodes:
878+ if node.nodeType == node.TEXT_NODE:
879+ encrypted_iv = node.data
880+ return (parts, encrypted_key, encrypted_iv)
881+
882+ def assemble_parts(
883+ self,
884+ src_directory,
885+ directory,
886+ manifest_path,
887+ parts,
888+ ):
889+ manifest_filename = self.get_relative_filename(manifest_path)
890+ encrypted_filename = os.path.join(directory,
891+ manifest_filename.replace('.manifest.xml', '.enc.tar.gz'
892+ ))
893+ if len(parts) > 0:
894+ if not os.path.exists(directory):
895+ os.makedirs(directory)
896+ encrypted_file = open(encrypted_filename, 'wb')
897+ for part in parts:
898+ print 'Part:', self.get_relative_filename(part)
899+ part_filename = os.path.join(src_directory, part)
900+ part_file = open(part_filename, 'rb')
901+ while 1:
902+ data = part_file.read(IMAGE_IO_CHUNK)
903+ if not data:
904+ break
905+ encrypted_file.write(data)
906+ part_file.close()
907+ encrypted_file.close()
908+ return encrypted_filename
909+
910+ def decrypt_image(
911+ self,
912+ encrypted_filename,
913+ encrypted_key,
914+ encrypted_iv,
915+ private_key_path,
916+ ):
917+ user_priv_key = RSA.load_key(private_key_path)
918+ key = user_priv_key.private_decrypt(unhexlify(encrypted_key),
919+ RSA.pkcs1_padding)
920+ iv = user_priv_key.private_decrypt(unhexlify(encrypted_iv),
921+ RSA.pkcs1_padding)
922+ k = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(key),
923+ iv=unhexlify(iv), op=0)
924+
925+ decrypted_filename = encrypted_filename.replace('.enc', '')
926+ decrypted_file = open(decrypted_filename, 'wb')
927+ encrypted_file = open(encrypted_filename, 'rb')
928+ self.crypt_file(k, encrypted_file, decrypted_file)
929+ encrypted_file.close()
930+ decrypted_file.close()
931+ return decrypted_filename
932+
933+ def decrypt_string(
934+ self,
935+ encrypted_string,
936+ private_key_path,
937+ encoded=False,
938+ ):
939+ user_priv_key = RSA.load_key(private_key_path)
940+ string_to_decrypt = encrypted_string
941+ if encoded:
942+ string_to_decrypt = base64.b64decode(encrypted_string)
943+ return user_priv_key.private_decrypt(string_to_decrypt,
944+ RSA.pkcs1_padding)
945+
946+ def untarzip_image(self, path, file):
947+ untarred_filename = file.replace('.tar.gz', '')
948+ tar_file = tarfile.open(file, 'r|gz')
949+ tar_file.extractall(path)
950+ untarred_names = tar_file.getnames()
951+ tar_file.close()
952+ return untarred_names
953+
954+ def get_block_devs(self, mapping):
955+ virtual = []
956+ devices = []
957+
958+ vname = None
959+ for m in mapping:
960+ if not vname:
961+ vname = m
962+ virtual.append(vname)
963+ else:
964+ devices.append(m)
965+ vname = None
966+
967+ return (virtual, devices)
968+
969+ def generate_manifest(
970+ self,
971+ path,
972+ prefix,
973+ parts,
974+ parts_digest,
975+ file,
976+ key,
977+ iv,
978+ cert_path,
979+ ec2cert_path,
980+ private_key_path,
981+ target_arch,
982+ image_size,
983+ bundled_size,
984+ image_digest,
985+ user,
986+ kernel,
987+ ramdisk,
988+ mapping=None,
989+ product_codes=None,
990+ ancestor_ami_ids=None,
991+ ):
992+ user_pub_key = X509.load_cert(cert_path).get_pubkey().get_rsa()
993+ cloud_pub_key = \
994+ X509.load_cert(ec2cert_path).get_pubkey().get_rsa()
995+
996+ user_encrypted_key = hexlify(user_pub_key.public_encrypt(key,
997+ RSA.pkcs1_padding))
998+ user_encrypted_iv = hexlify(user_pub_key.public_encrypt(iv,
999+ RSA.pkcs1_padding))
1000+
1001+ cloud_encrypted_key = hexlify(cloud_pub_key.public_encrypt(key,
1002+ RSA.pkcs1_padding))
1003+ cloud_encrypted_iv = hexlify(cloud_pub_key.public_encrypt(iv,
1004+ RSA.pkcs1_padding))
1005+
1006+ user_priv_key = RSA.load_key(private_key_path)
1007+
1008+ manifest_file = '%s.manifest.xml' % os.path.join(path, prefix)
1009+ if self.debug:
1010+ print 'Manifest: ', manifest_file
1011+
1012+ print 'Generating manifest %s' % manifest_file
1013+
1014+ manifest_out_file = open(manifest_file, 'wb')
1015+ doc = Document()
1016+
1017+ manifest_elem = doc.createElement('manifest')
1018+ doc.appendChild(manifest_elem)
1019+
1020+ # version
1021+
1022+ version_elem = doc.createElement('version')
1023+ version_value = doc.createTextNode(VERSION)
1024+ version_elem.appendChild(version_value)
1025+ manifest_elem.appendChild(version_elem)
1026+
1027+ # bundler info
1028+
1029+ bundler_elem = doc.createElement('bundler')
1030+ bundler_name_elem = doc.createElement('name')
1031+ bundler_name_value = doc.createTextNode(BUNDLER_NAME)
1032+ bundler_name_elem.appendChild(bundler_name_value)
1033+ bundler_version_elem = doc.createElement('version')
1034+ bundler_version_value = doc.createTextNode(BUNDLER_VERSION)
1035+ bundler_version_elem.appendChild(bundler_version_value)
1036+ bundler_elem.appendChild(bundler_name_elem)
1037+ bundler_elem.appendChild(bundler_version_elem)
1038+
1039+ # release
1040+
1041+ release_elem = doc.createElement('release')
1042+ release_value = doc.createTextNode(RELEASE)
1043+ release_elem.appendChild(release_value)
1044+ bundler_elem.appendChild(release_elem)
1045+ manifest_elem.appendChild(bundler_elem)
1046+
1047+ # machine config
1048+
1049+ machine_config_elem = doc.createElement('machine_configuration')
1050+ manifest_elem.appendChild(machine_config_elem)
1051+
1052+ target_arch_elem = doc.createElement('architecture')
1053+ target_arch_value = doc.createTextNode(target_arch)
1054+ target_arch_elem.appendChild(target_arch_value)
1055+ machine_config_elem.appendChild(target_arch_elem)
1056+
1057+ # block device mapping
1058+
1059+ if mapping:
1060+ block_dev_mapping_elem = \
1061+ doc.createElement('block_device_mapping')
1062+ (virtual_names, device_names) = self.get_block_devs(mapping)
1063+ vname_index = 0
1064+ for vname in virtual_names:
1065+ dname = device_names[vname_index]
1066+ mapping_elem = doc.createElement('mapping')
1067+ virtual_elem = doc.createElement('virtual')
1068+ virtual_value = doc.createTextNode(vname)
1069+ virtual_elem.appendChild(virtual_value)
1070+ mapping_elem.appendChild(virtual_elem)
1071+ device_elem = doc.createElement('device')
1072+ device_value = doc.createTextNode(dname)
1073+ device_elem.appendChild(device_value)
1074+ mapping_elem.appendChild(device_elem)
1075+ block_dev_mapping_elem.appendChild(mapping_elem)
1076+ vname_index = vname_index + 1
1077+ machine_config_elem.appendChild(block_dev_mapping_elem)
1078+
1079+ if product_codes:
1080+ product_codes_elem = doc.createElement('product_codes')
1081+ for product_code in product_codes:
1082+ product_code_elem = doc.createElement('product_code')
1083+ product_code_value = doc.createTextNode(product_code)
1084+ product_code_elem.appendChild(product_code_value)
1085+ product_codes_elem.appendChild(product_code_elem)
1086+ machine_config_elem.appendChild(product_codes_elem)
1087+
1088+ # kernel and ramdisk
1089+
1090+ if kernel:
1091+ kernel_id_elem = doc.createElement('kernel_id')
1092+ kernel_id_value = doc.createTextNode(kernel)
1093+ kernel_id_elem.appendChild(kernel_id_value)
1094+ machine_config_elem.appendChild(kernel_id_elem)
1095+
1096+ if ramdisk:
1097+ ramdisk_id_elem = doc.createElement('ramdisk_id')
1098+ ramdisk_id_value = doc.createTextNode(ramdisk)
1099+ ramdisk_id_elem.appendChild(ramdisk_id_value)
1100+ machine_config_elem.appendChild(ramdisk_id_elem)
1101+
1102+ image_elem = doc.createElement('image')
1103+ manifest_elem.appendChild(image_elem)
1104+
1105+ # name
1106+
1107+ image_name_elem = doc.createElement('name')
1108+ image_name_value = \
1109+ doc.createTextNode(self.get_relative_filename(file))
1110+ image_name_elem.appendChild(image_name_value)
1111+ image_elem.appendChild(image_name_elem)
1112+
1113+ # user
1114+
1115+ user_elem = doc.createElement('user')
1116+ user_value = doc.createTextNode('%s' % user)
1117+ user_elem.appendChild(user_value)
1118+ image_elem.appendChild(user_elem)
1119+
1120+ # type
1121+ # TODO: fixme
1122+
1123+ image_type_elem = doc.createElement('type')
1124+ image_type_value = doc.createTextNode('machine')
1125+ image_type_elem.appendChild(image_type_value)
1126+ image_elem.appendChild(image_type_elem)
1127+
1128+ # ancestor ami ids
1129+
1130+ if ancestor_ami_ids:
1131+ ancestry_elem = doc.createElement('ancestry')
1132+ for ancestor_ami_id in ancestor_ami_ids:
1133+ ancestor_id_elem = doc.createElement('ancestor_ami_id')
1134+ ancestor_id_value = doc.createTextNode(ancestor_ami_id)
1135+ ancestor_id_elem.appendChild(ancestor_id_value)
1136+ ancestry_elem.appendChild(ancestor_id_elem)
1137+ image_elem.appendChild(ancestry_elem)
1138+
1139+ # digest
1140+
1141+ image_digest_elem = doc.createElement('digest')
1142+ image_digest_elem.setAttribute('algorithm', 'SHA1')
1143+ image_digest_value = doc.createTextNode('%s' % image_digest)
1144+ image_digest_elem.appendChild(image_digest_value)
1145+ image_elem.appendChild(image_digest_elem)
1146+
1147+ # size
1148+
1149+ image_size_elem = doc.createElement('size')
1150+ image_size_value = doc.createTextNode('%s' % image_size)
1151+ image_size_elem.appendChild(image_size_value)
1152+ image_elem.appendChild(image_size_elem)
1153+
1154+ # bundled size
1155+
1156+ bundled_size_elem = doc.createElement('bundled_size')
1157+ bundled_size_value = doc.createTextNode('%s' % bundled_size)
1158+ bundled_size_elem.appendChild(bundled_size_value)
1159+ image_elem.appendChild(bundled_size_elem)
1160+
1161+ # key, iv
1162+
1163+ cloud_encrypted_key_elem = doc.createElement('ec2_encrypted_key'
1164+ )
1165+ cloud_encrypted_key_value = doc.createTextNode('%s'
1166+ % cloud_encrypted_key)
1167+ cloud_encrypted_key_elem.appendChild(cloud_encrypted_key_value)
1168+ cloud_encrypted_key_elem.setAttribute('algorithm', AES)
1169+ image_elem.appendChild(cloud_encrypted_key_elem)
1170+
1171+ user_encrypted_key_elem = doc.createElement('user_encrypted_key'
1172+ )
1173+ user_encrypted_key_value = doc.createTextNode('%s'
1174+ % user_encrypted_key)
1175+ user_encrypted_key_elem.appendChild(user_encrypted_key_value)
1176+ user_encrypted_key_elem.setAttribute('algorithm', AES)
1177+ image_elem.appendChild(user_encrypted_key_elem)
1178+
1179+ cloud_encrypted_iv_elem = doc.createElement('ec2_encrypted_iv')
1180+ cloud_encrypted_iv_value = doc.createTextNode('%s'
1181+ % cloud_encrypted_iv)
1182+ cloud_encrypted_iv_elem.appendChild(cloud_encrypted_iv_value)
1183+ image_elem.appendChild(cloud_encrypted_iv_elem)
1184+
1185+ user_encrypted_iv_elem = doc.createElement('user_encrypted_iv')
1186+ user_encrypted_iv_value = doc.createTextNode('%s'
1187+ % user_encrypted_iv)
1188+ user_encrypted_iv_elem.appendChild(user_encrypted_iv_value)
1189+ image_elem.appendChild(user_encrypted_iv_elem)
1190+
1191+ # parts
1192+
1193+ parts_elem = doc.createElement('parts')
1194+ parts_elem.setAttribute('count', '%s' % len(parts))
1195+ part_number = 0
1196+ for part in parts:
1197+ part_elem = doc.createElement('part')
1198+ filename_elem = doc.createElement('filename')
1199+ filename_value = \
1200+ doc.createTextNode(self.get_relative_filename(part))
1201+ filename_elem.appendChild(filename_value)
1202+ part_elem.appendChild(filename_elem)
1203+
1204+ # digest
1205+
1206+ part_digest_elem = doc.createElement('digest')
1207+ part_digest_elem.setAttribute('algorithm', 'SHA1')
1208+ part_digest_value = \
1209+ doc.createTextNode(parts_digest[part_number])
1210+ part_digest_elem.appendChild(part_digest_value)
1211+ part_elem.appendChild(part_digest_elem)
1212+ part_elem.setAttribute('index', '%s' % part_number)
1213+ parts_elem.appendChild(part_elem)
1214+ part_number += 1
1215+ image_elem.appendChild(parts_elem)
1216+
1217+ manifest_string = doc.toxml()
1218+
1219+ string_to_sign = self.get_verification_string(manifest_string)
1220+ signature_elem = doc.createElement('signature')
1221+ sha_manifest = sha()
1222+ sha_manifest.update(string_to_sign)
1223+ signature_value = doc.createTextNode('%s'
1224+ % hexlify(user_priv_key.sign(sha_manifest.digest())))
1225+ signature_elem.appendChild(signature_value)
1226+ manifest_elem.appendChild(signature_elem)
1227+ manifest_out_file.write(doc.toxml())
1228+ manifest_out_file.close()
1229+
1230+ def add_excludes(self, path, excludes):
1231+ if self.debug:
1232+ print 'Reading /etc/mtab...'
1233+ mtab_file = open('/etc/mtab', 'r')
1234+ while 1:
1235+ mtab_line = mtab_file.readline()
1236+ if not mtab_line:
1237+ break
1238+ mtab_line_parts = mtab_line.split(' ')
1239+ mount_point = mtab_line_parts[1]
1240+ fs_type = mtab_line_parts[2]
1241+ if mount_point.find(path) == 0 and fs_type \
1242+ not in self.img.ALLOWED_FS_TYPES:
1243+ if self.debug:
1244+ print 'Excluding %s...' % mount_point
1245+ excludes.append(mount_point)
1246+ mtab_file.close()
1247+ for banned in self.img.BANNED_MOUNTS:
1248+ excludes.append(banned)
1249+
1250+ def make_image(
1251+ self,
1252+ size_in_MB,
1253+ excludes,
1254+ prefix,
1255+ destination_path,
1256+ ):
1257+ image_file = '%s.img' % prefix
1258+ image_path = '%s/%s' % (destination_path, image_file)
1259+ if not os.path.exists(destination_path):
1260+ os.makedirs(destination_path)
1261+ if self.img == 'Unsupported':
1262+ print 'Platform not fully supported.'
1263+ raise UnsupportedException
1264+ self.img.create_image(size_in_MB, image_path)
1265+ self.img.make_fs(image_path)
1266+ return image_path
1267+
1268+ def create_loopback(self, image_path):
1269+ Util().check_prerequisite_command('losetup')
1270+ tries = 0
1271+ while tries < MAX_LOOP_DEVS:
1272+ loop_dev = Popen(['losetup', '-f'],
1273+ stdout=PIPE).communicate()[0].replace('\n'
1274+ , '')
1275+ if loop_dev:
1276+ output = Popen(['losetup', '%s' % loop_dev, '%s'
1277+ % image_path], stdout=PIPE,
1278+ stderr=PIPE).communicate()
1279+ if not output[1]:
1280+ return loop_dev
1281+ else:
1282+ print 'Could not create loopback device. Aborting'
1283+ raise CommandFailed
1284+ tries += 1
1285+
1286+ def mount_image(self, image_path):
1287+ Util().check_prerequisite_command('mount')
1288+
1289+ tmp_mnt_point = '/tmp/%s' % hex(BN.rand(16))[2:6]
1290+ if not os.path.exists(tmp_mnt_point):
1291+ os.makedirs(tmp_mnt_point)
1292+ if self.debug:
1293+ print 'Creating loopback device...'
1294+ loop_dev = self.create_loopback(image_path)
1295+ if self.debug:
1296+ print 'Mounting image...'
1297+ Popen(['mount', loop_dev, tmp_mnt_point],
1298+ stdout=PIPE).communicate()
1299+ return (tmp_mnt_point, loop_dev)
1300+
1301+ def copy_to_image(
1302+ self,
1303+ mount_point,
1304+ volume_path,
1305+ excludes,
1306+ ):
1307+ try:
1308+ Util().check_prerequisite_command('rsync')
1309+ except NotFoundError:
1310+ raise CopyError
1311+ rsync_cmd = ['rsync', '-aXS']
1312+ for exclude in excludes:
1313+ rsync_cmd.append('--exclude')
1314+ rsync_cmd.append(exclude)
1315+ rsync_cmd.append(volume_path)
1316+ rsync_cmd.append(mount_point)
1317+ if self.debug:
1318+ print 'Copying files...'
1319+ for exclude in excludes:
1320+ print 'Excluding:', exclude
1321+
1322+ pipe = Popen(rsync_cmd, stdout=PIPE, stderr=PIPE)
1323+ output = pipe.communicate()
1324+ for dir in self.img.ESSENTIAL_DIRS:
1325+ dir_path = os.path.join(mount_point, dir)
1326+ if not os.path.exists(dir_path):
1327+ os.mkdir(dir_path)
1328+ if dir == 'tmp':
1329+ os.chmod(dir_path, 01777)
1330+ self.img.make_essential_devs(mount_point)
1331+ mtab_file = open('/etc/mtab', 'r')
1332+ while 1:
1333+ mtab_line = mtab_file.readline()
1334+ if not mtab_line:
1335+ break
1336+ mtab_line_parts = mtab_line.split(' ')
1337+ mount_location = mtab_line_parts[1]
1338+ fs_type = mtab_line_parts[2]
1339+ if fs_type == 'tmpfs':
1340+ mount_location = mount_location[1:]
1341+ dir_path = os.path.join(mount_point, mount_location)
1342+ if not os.path.exists(dir_path):
1343+ if self.debug:
1344+ print 'Making essential directory %s' \
1345+ % mount_location
1346+ os.makedirs(dir_path)
1347+ mtab_file.close()
1348+ if pipe.returncode:
1349+
1350+ # rsync return code 23: Partial transfer due to error
1351+ # rsync return code 24: Partial transfer due to vanished source files
1352+
1353+ if pipe.returncode in (23, 24):
1354+ print 'Warning: rsync reports files partially copied:'
1355+ print output
1356+ else:
1357+ print 'Error: rsync failed with return code %d' \
1358+ % pipe.returncode
1359+ raise CopyError
1360+
1361+ def unmount_image(self, mount_point):
1362+ Util().check_prerequisite_command('umount')
1363+ if self.debug:
1364+ print 'Unmounting image...'
1365+ Popen(['umount', '-d', mount_point],
1366+ stdout=PIPE).communicate()[0]
1367+ os.rmdir(mount_point)
1368+
1369+ def copy_volume(
1370+ self,
1371+ image_path,
1372+ volume_path,
1373+ excludes,
1374+ generate_fstab,
1375+ fstab_path,
1376+ ):
1377+ (mount_point, loop_dev) = self.mount_image(image_path)
1378+ try:
1379+ output = self.copy_to_image(mount_point, volume_path,
1380+ excludes)
1381+ if self.img == 'Unsupported':
1382+ print 'Platform not fully supported.'
1383+ raise UnsupportedException
1384+ self.img.add_fstab(mount_point, generate_fstab, fstab_path)
1385+ except CopyError:
1386+ raise CopyError
1387+ finally:
1388+ self.unmount_image(mount_point)
1389+
1390+ def can_read_instance_metadata(self):
1391+ meta_data = urllib.urlopen(METADATA_URL)
1392+
1393+ def get_instance_metadata(self, type):
1394+ if self.debug:
1395+ print 'Reading instance metadata', type
1396+ metadata = urllib.urlopen(METADATA_URL + type).read()
1397+ if 'Not' in metadata and 'Found' in metadata and '404' \
1398+ in metadata:
1399+ raise MetadataReadError
1400+ return metadata
1401+
1402+ def get_instance_ramdisk(self):
1403+ return self.get_instance_metadata('ramdisk-id')
1404+
1405+ def get_instance_kernel(self):
1406+ return self.get_instance_metadata('kernel-id')
1407+
1408+ def get_instance_product_codes(self):
1409+ return self.get_instance_metadata('product-codes')
1410+
1411+ def get_ancestor_ami_ids(self):
1412+ return self.get_instance_metadata('ancestor-ami-ids')
1413+
1414+ def get_instance_block_device_mappings(self):
1415+ keys = self.get_instance_metadata('block-device-mapping'
1416+ ).split('\n')
1417+ mapping = []
1418+ for k in keys:
1419+ mapping.append(k)
1420+ mapping.append(self.get_instance_metadata(os.path.join('block-device-mapping'
1421+ , k)))
1422+ return mapping
1423+
1424+ def display_error_and_exit(self, msg):
1425+ code = None
1426+ message = None
1427+ index = msg.find('<')
1428+ if index < 0:
1429+ print msg
1430+ sys.exit(1)
1431+ msg = msg[index - 1:]
1432+ msg = msg.replace('\n', '')
1433+ dom = minidom.parseString(msg)
1434+ try:
1435+ error_elem = dom.getElementsByTagName('Error')[0]
1436+ code_elem = error_elem.getElementsByTagName('Code')[0]
1437+ nodes = code_elem.childNodes
1438+ for node in nodes:
1439+ if node.nodeType == node.TEXT_NODE:
1440+ code = node.data
1441+
1442+ msg_elem = error_elem.getElementsByTagName('Message')[0]
1443+ nodes = msg_elem.childNodes
1444+ for node in nodes:
1445+ if node.nodeType == node.TEXT_NODE:
1446+ message = node.data
1447+
1448+ print '%s:' % code, message
1449+ except Exception:
1450+ print msg
1451+ sys.exit(1)
1452+
1453+ def parse_block_device_args(self, block_device_maps_args):
1454+ block_device_map = BlockDeviceMapping()
1455+ for block_device_map_arg in block_device_maps_args:
1456+ parts = block_device_map_arg.split('=')
1457+ if len(parts) > 1:
1458+ device_name = parts[0]
1459+ block_dev_type = EBSBlockDeviceType()
1460+ value_parts = parts[1].split(':')
1461+ if value_parts[0].startswith('snap'):
1462+ block_dev_type.snapshot_id = value_parts[0]
1463+ else:
1464+ if value_parts[0].startswith('ephemeral'):
1465+ block_dev_type.ephemeral_name = value_parts[0]
1466+ if len(value_parts) > 1:
1467+ block_dev_type.size = int(value_parts[1])
1468+ if len(value_parts) > 2:
1469+ if value_parts[2] == 'true':
1470+ block_dev_type.delete_on_termination = True
1471+ block_device_map[device_name] = block_dev_type
1472+ return block_device_map
1473+
1474+
1475+# read the config file 'config', update 'dict', setting
1476+# the value from the config file for each element in array 'keylist'
1477+# "config" is a bash syntax file defining bash variables
1478+
1479+
1480+def parse_config(config, dict, keylist):
1481+ fmt = ''
1482+ str = ''
1483+ for v in keylist:
1484+ str = '%s "${%s}" ' % (str, v)
1485+ fmt = fmt + '%s%s' % ('%s', '\\0')
1486+
1487+ cmd = ['bash', '-ec', ". '%s' >/dev/null; printf '%s' %s"
1488+ % (config, fmt, str)]
1489+
1490+ handle = Popen(cmd, stderr=PIPE, stdout=PIPE)
1491+ (stdout, stderr) = handle.communicate()
1492+ if handle.returncode != 0:
1493+ raise ParseError('Parsing config file %s failed:\n\t%s'
1494+ % (config, stderr))
1495+
1496+ values = stdout.split("\0")
1497+ for i in range(len(values) - 1):
1498+ if values[i] != '':
1499+ dict[keylist[i]] = values[i]
1500+
1501+
1502
1503=== added directory '.pc/bundle-image-usage-on-invalid-user.patch'
1504=== added file '.pc/bundle-image-usage-on-invalid-user.patch/.timestamp'
1505=== added directory '.pc/bundle-image-usage-on-invalid-user.patch/bin'
1506=== added file '.pc/bundle-image-usage-on-invalid-user.patch/bin/euca-bundle-image'
1507--- .pc/bundle-image-usage-on-invalid-user.patch/bin/euca-bundle-image 1970-01-01 00:00:00 +0000
1508+++ .pc/bundle-image-usage-on-invalid-user.patch/bin/euca-bundle-image 2010-11-17 22:00:42 +0000
1509@@ -0,0 +1,285 @@
1510+#!/usr/bin/python
1511+# -*- coding: utf-8 -*-
1512+
1513+# Software License Agreement (BSD License)
1514+#
1515+# Copyright (c) 2009, Eucalyptus Systems, Inc.
1516+# All rights reserved.
1517+#
1518+# Redistribution and use of this software in source and binary forms, with or
1519+# without modification, are permitted provided that the following conditions
1520+# are met:
1521+#
1522+# Redistributions of source code must retain the above
1523+# copyright notice, this list of conditions and the
1524+# following disclaimer.
1525+#
1526+# Redistributions in binary form must reproduce the above
1527+# copyright notice, this list of conditions and the
1528+# following disclaimer in the documentation and/or other
1529+# materials provided with the distribution.
1530+#
1531+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1532+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1533+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1534+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
1535+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1536+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1537+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1538+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1539+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1540+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1541+# POSSIBILITY OF SUCH DAMAGE.
1542+#
1543+# Author: Neil Soman neil@eucalyptus.com
1544+
1545+import getopt
1546+import sys
1547+import os
1548+from euca2ools import Euca2ool, FileValidationError, Util, \
1549+ NotFoundError, CommandFailed
1550+
1551+usage_string = \
1552+ """
1553+Bundles an image for use with Eucalyptus or Amazon EC2.
1554+
1555+euca-bundle-image -i, --image image_path -u, --user user [-c, --cert cert_path]
1556+[-k, --privatekey private_key_path] [-p, --prefix prefix] [--kernel kernel_id]
1557+[--ramdisk ramdisk_id] [-B, --block-device-mapping mapping]
1558+[-d, --destination destination_path] [--ec2cert ec2cert_path]
1559+[-r, --arch target_architecture] [--batch] [-h, --help] [--version] [--debug]
1560+
1561+REQUIRED PARAMETERS
1562+
1563+-i, --image Path to the image file to bundle.
1564+
1565+-u, --user User ID (12-digit) of the user who is bundling the image.
1566+
1567+OPTIONAL PARAMETERS
1568+
1569+-c, --cert Path to the user's PEM encoded certificate.
1570+
1571+-k, --privatekey Path to the user's PEM encoded private key.
1572+
1573+-p, --prefix The prefix for the bundle image files. (default: image name).
1574+
1575+--kernel The kernel to be associated with the bundled image.
1576+
1577+--ramdisk The ramdisk to be associated with the bundled image.
1578+
1579+-B, --block-device-mapping Default block device mapping for the image (comma-separated list of key=value pairs).
1580+
1581+-d, --destination Directory to store the bundled image in (default: "/tmp"). Recommended.
1582+
1583+--ec2cert The path to the Cloud's X509 public key certificate.
1584+
1585+-r, --arch Target architecture for the image ('x86_64' or 'i386' default: 'x86_64').
1586+
1587+--batch Run in batch mode (compatibility only. has no effect).
1588+"""
1589+
1590+
1591+def usage(status=1):
1592+ print usage_string
1593+ Util().usage()
1594+ sys.exit(status)
1595+
1596+
1597+def version():
1598+ print Util().version()
1599+ sys.exit()
1600+
1601+
1602+def get_block_devs(mapping_str):
1603+ mapping = []
1604+ mapping_pairs = mapping_str.split(',')
1605+ for m in mapping_pairs:
1606+ m_parts = m.split('=')
1607+ if len(m_parts) > 1:
1608+ mapping.append(m_parts[0])
1609+ mapping.append(m_parts[1])
1610+ return mapping
1611+
1612+
1613+def add_product_codes(product_code_string, product_codes):
1614+ if not product_codes:
1615+ product_codes = []
1616+ product_code_values = product_code_string.split(',')
1617+
1618+ for p in product_code_values:
1619+ product_codes.append(p)
1620+
1621+ return product_codes
1622+
1623+
1624+def main():
1625+ euca = None
1626+ try:
1627+ euca = Euca2ool('i:c:k:u:B:d:br:p:', [
1628+ 'image=',
1629+ 'cert=',
1630+ 'privatekey=',
1631+ 'user=',
1632+ 'prefix=',
1633+ 'kernel=',
1634+ 'ramdisk=',
1635+ 'block-device-mapping=',
1636+ 'destination=',
1637+ 'ec2cert=',
1638+ 'arch=',
1639+ 'productcodes=',
1640+ 'batch',
1641+ ])
1642+ except Exception, e:
1643+ print e
1644+ usage()
1645+
1646+ image_path = None
1647+ kernel = None
1648+ user = None
1649+ ramdisk = None
1650+ try:
1651+ cert_path = euca.get_environ('EC2_CERT')
1652+ private_key_path = euca.get_environ('EC2_PRIVATE_KEY')
1653+ ec2cert_path = euca.get_environ('EUCALYPTUS_CERT')
1654+ user_string = euca.get_environ('EC2_USER_ID')
1655+ except NotFoundError:
1656+ sys.exit(1)
1657+
1658+ prefix = None
1659+ destination_path = '/tmp'
1660+ target_arch = 'x86_64'
1661+ mapping = None
1662+ product_codes = None
1663+ product_code_string = None
1664+ if user_string:
1665+ try:
1666+ user = int(user_string)
1667+ except ValueError:
1668+ print 'Invalid user', user_string
1669+ sys.exit()
1670+ user = user_string
1671+
1672+ for (name, value) in euca.opts:
1673+ if name in ('-h', '--help'):
1674+ usage(0)
1675+ elif name in ('-i', '--image'):
1676+ image_path = value
1677+ elif name in ('-c', '--cert'):
1678+ cert_path = value
1679+ elif name in ('-k', '--privatekey'):
1680+ private_key_path = value
1681+ elif name in ('-u', '--user'):
1682+ try:
1683+ value = value.replace('-', '')
1684+ user = int(value)
1685+ except ValueError:
1686+ print 'Invalid user', value
1687+ sys.exit()
1688+ user = value
1689+ elif name == '--kernel':
1690+ kernel = value
1691+ elif name == '--ramdisk':
1692+ ramdisk = value
1693+ elif name in ('-p', '--prefix'):
1694+ prefix = value
1695+ elif name in ('-d', '--destination'):
1696+ destination_path = value
1697+ elif name == '--ec2cert':
1698+ ec2cert_path = value
1699+ elif name in ('-r', '--arch'):
1700+ target_arch = value
1701+ print target_arch
1702+ if target_arch != 'i386' and target_arch != 'x86_64':
1703+ print 'target architecture must be i386 or x86_64'
1704+ usage()
1705+ elif name in ('-B', '--block-device-mapping'):
1706+ mapping = value
1707+ elif name == '--productcodes':
1708+ product_code_string = value
1709+ elif name == '--version':
1710+ version()
1711+
1712+ if image_path and cert_path and private_key_path and user \
1713+ and ec2cert_path:
1714+ try:
1715+ euca.validate_file(image_path)
1716+ except FileValidationError:
1717+ print 'Invalid image'
1718+ sys.exit(1)
1719+ try:
1720+ euca.validate_file(cert_path)
1721+ except FileValidationError:
1722+ print 'Invalid cert'
1723+ sys.exit(1)
1724+ try:
1725+ euca.validate_file(private_key_path)
1726+ except FileValidationError:
1727+ print 'Invalid private key'
1728+ sys.exit(1)
1729+ try:
1730+ euca.validate_file(ec2cert_path)
1731+ except FileValidationError:
1732+ print 'Invalid ec2cert'
1733+ sys.exit(1)
1734+
1735+ (image_size, sha_image_digest) = euca.check_image(image_path,
1736+ destination_path)
1737+ if not prefix:
1738+ prefix = euca.get_relative_filename(image_path)
1739+ try:
1740+ tgz_file = euca.tarzip_image(prefix, image_path,
1741+ destination_path)
1742+ except NotFoundError:
1743+ sys.exit(1)
1744+ except CommandFailed:
1745+ sys.exit(1)
1746+
1747+ (encrypted_file, key, iv, bundled_size) = \
1748+ euca.encrypt_image(tgz_file)
1749+ os.remove(tgz_file)
1750+ (parts, parts_digest) = euca.split_image(encrypted_file)
1751+ if mapping:
1752+ mapping = get_block_devs(mapping)
1753+ if product_code_string:
1754+ product_codes = add_product_codes(product_code_string,
1755+ product_codes)
1756+ euca.generate_manifest(
1757+ destination_path,
1758+ prefix,
1759+ parts,
1760+ parts_digest,
1761+ image_path,
1762+ key,
1763+ iv,
1764+ cert_path,
1765+ ec2cert_path,
1766+ private_key_path,
1767+ target_arch,
1768+ image_size,
1769+ bundled_size,
1770+ sha_image_digest,
1771+ user,
1772+ kernel,
1773+ ramdisk,
1774+ mapping,
1775+ product_codes,
1776+ )
1777+ os.remove(encrypted_file)
1778+ else:
1779+ if not image_path:
1780+ print 'image be specified.'
1781+ if not cert_path:
1782+ print 'cert must be specified.'
1783+ if not private_key_path:
1784+ print 'private key must be specified.'
1785+ if not user:
1786+ print 'user must be specified.'
1787+ if not ec2cert_path:
1788+ print 'ec2cert must be specified.'
1789+ usage()
1790+
1791+
1792+if __name__ == '__main__':
1793+ main()
1794+
1795
1796=== added directory '.pc/bundle-vol-exclude-persistent-udev-net-rules.patch'
1797=== added file '.pc/bundle-vol-exclude-persistent-udev-net-rules.patch/.timestamp'
1798=== added directory '.pc/bundle-vol-exclude-persistent-udev-net-rules.patch/bin'
1799=== added file '.pc/bundle-vol-exclude-persistent-udev-net-rules.patch/bin/euca-bundle-vol'
1800--- .pc/bundle-vol-exclude-persistent-udev-net-rules.patch/bin/euca-bundle-vol 1970-01-01 00:00:00 +0000
1801+++ .pc/bundle-vol-exclude-persistent-udev-net-rules.patch/bin/euca-bundle-vol 2010-11-17 22:00:42 +0000
1802@@ -0,0 +1,456 @@
1803+#!/usr/bin/python
1804+# -*- coding: utf-8 -*-
1805+
1806+# Software License Agreement (BSD License)
1807+#
1808+# Copyright (c) 2009, Eucalyptus Systems, Inc.
1809+# All rights reserved.
1810+#
1811+# Redistribution and use of this software in source and binary forms, with or
1812+# without modification, are permitted provided that the following conditions
1813+# are met:
1814+#
1815+# Redistributions of source code must retain the above
1816+# copyright notice, this list of conditions and the
1817+# following disclaimer.
1818+#
1819+# Redistributions in binary form must reproduce the above
1820+# copyright notice, this list of conditions and the
1821+# following disclaimer in the documentation and/or other
1822+# materials provided with the distribution.
1823+#
1824+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1825+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1826+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1827+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
1828+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1829+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1830+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1831+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1832+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1833+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1834+# POSSIBILITY OF SUCH DAMAGE.
1835+#
1836+# Author: Neil Soman neil@eucalyptus.com
1837+
1838+import getopt
1839+import sys
1840+import os
1841+from euca2ools import Euca2ool, FileValidationError, \
1842+ DirValidationError, CopyError, MetadataReadError, Util, \
1843+ NotFoundError, CommandFailed, UnsupportedException
1844+from subprocess import *
1845+import platform
1846+
1847+usage_string = \
1848+ """
1849+Bundle the local filesystem of a running instance as a bundled image.
1850+
1851+euca-bundle-vol -u, --user user -s, --size size_in_MB
1852+[-c, --cert cert_path] [-k, --privatekey private_key_path]
1853+[-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]
1854+[-d, --destination destination_path] [--ec2cert ec2cert_path] [-r, --arch target_architecture] [--batch] [--version]
1855+
1856+REQUIRED PARAMETERS
1857+
1858+-u, --user User ID (12-digit) of the user who is bundling the image.
1859+
1860+-s, --size Size for the image in MB (default: 10GB or 10240MB).
1861+
1862+OPTIONAL PARAMETERS
1863+
1864+-c, --cert Path to the user's PEM encoded certificate.
1865+
1866+-k, --privatekey Path to the user's PEM encoded private key.
1867+
1868+-a, --all Bundle all directories (including mounted filesystems).
1869+
1870+-p, --prefix The prefix for the bundle image files. (default: image name).
1871+
1872+--[no-]inherit Add (or do not add) instance metadata to the bundled image. Inherit is set by default.
1873+
1874+-e, --exclude comma-separated list of directories to exclude.
1875+
1876+--kernel The kernel to be associated with the bundled image.
1877+
1878+--ramdisk The ramdisk to be associated with the bundled image.
1879+
1880+-B, --block-device-mapping Default block device mapping for the image (comma-separated list of key=value pairs).
1881+
1882+-d, --destination Directory to store the bundled image in (default: "/tmp"). Recommended.
1883+
1884+--ec2cert The path to the Cloud's X509 public key certificate.
1885+
1886+-r, --arch Target architecture for the image ('x86_64' or 'i386' default: 'x86_64').
1887+
1888+-v, --volume Path to mounted volume to create the bundle from (default: "/").
1889+
1890+--fstab Path to the fstab to be bundled into the image.
1891+
1892+--generate-fstab Generate fstab to bundle into the image.
1893+
1894+--batch Run in batch mode (compatibility only. has no effect).
1895+"""
1896+
1897+MAX_IMAGE_SIZE = 1024 * 10
1898+
1899+
1900+def usage(status=1):
1901+ print usage_string
1902+ sys.exit(status)
1903+
1904+
1905+def version():
1906+ print Util().version()
1907+ sys.exit()
1908+
1909+
1910+def check_root():
1911+ if os.geteuid() == 0:
1912+ return
1913+ else:
1914+ print 'Must be superuser to execute this command.'
1915+ sys.exit()
1916+
1917+
1918+def check_image_size(size):
1919+ if size > MAX_IMAGE_SIZE:
1920+ print 'Image Size is too large (Max = %d MB)' % MAX_IMAGE_SIZE
1921+ sys.exit()
1922+
1923+
1924+def parse_excludes(excludes_string):
1925+ excludes = []
1926+ if excludes_string:
1927+ excludes_string = excludes_string.replace(' ', '')
1928+ excludes = excludes_string.split(',')
1929+ return excludes
1930+
1931+
1932+def get_instance_metadata(
1933+ euca,
1934+ ramdisk,
1935+ kernel,
1936+ mapping,
1937+ ):
1938+ product_codes = None
1939+ ramdisk_id = ramdisk
1940+ kernel_id = kernel
1941+ block_dev_mapping = mapping
1942+ ancestor_ami_ids = None
1943+ try:
1944+ euca.can_read_instance_metadata()
1945+ if not ramdisk_id:
1946+ try:
1947+ ramdisk_id = euca.get_instance_ramdisk()
1948+ except MetadataReadError:
1949+ print 'Unable to read ramdisk id'
1950+
1951+ if not kernel_id:
1952+ try:
1953+ kernel_id = euca.get_instance_kernel()
1954+ except MetadataReadError:
1955+ print 'Unable to read kernel id'
1956+
1957+ if not block_dev_mapping:
1958+ try:
1959+ block_dev_mapping = \
1960+ euca.get_instance_block_device_mappings()
1961+ except MetadataReadError:
1962+ print 'Unable to read block device mapping'
1963+
1964+ try:
1965+ product_codes = euca.get_instance_product_codes().split('\n'
1966+ )
1967+ except MetadataReadError:
1968+ print 'Unable to read product codes'
1969+
1970+ try:
1971+ ancestor_ami_ids = euca.get_ancestor_ami_ids().split('\n')
1972+ except MetadataReadError:
1973+ print 'Unable to read product codes'
1974+ except IOError:
1975+
1976+ print 'Unable to read instance metadata. Pass the --no-inherit option if you wish to exclude instance metadata.'
1977+ sys.exit()
1978+
1979+ return (ramdisk_id, kernel_id, block_dev_mapping, product_codes,
1980+ ancestor_ami_ids)
1981+
1982+
1983+def add_product_codes(product_code_string, product_codes):
1984+ if not product_codes:
1985+ product_codes = []
1986+ product_code_values = product_code_string.split(',')
1987+
1988+ for p in product_code_values:
1989+ product_codes.append(p)
1990+
1991+ return product_codes
1992+
1993+
1994+def cleanup(path):
1995+ if os.path.exists(path):
1996+ os.remove(path)
1997+
1998+
1999+def main():
2000+ euca = None
2001+ try:
2002+ euca = Euca2ool('a:c:k:u:B:d:br:p:s:v:e:', [
2003+ 'cert=',
2004+ 'privatekey=',
2005+ 'user=',
2006+ 'prefix=',
2007+ 'volume=',
2008+ 'all',
2009+ 'kernel=',
2010+ 'ramdisk=',
2011+ 'block-device-mapping=',
2012+ 'destination=',
2013+ 'ec2cert=',
2014+ 'arch=',
2015+ 'size=',
2016+ 'exclude=',
2017+ 'inherit=',
2018+ 'no-inherit',
2019+ 'batch',
2020+ 'fstab=',
2021+ 'generate-fstab',
2022+ 'productcodes=',
2023+ ])
2024+ except Exception, e:
2025+ print e
2026+ usage()
2027+
2028+ kernel = None
2029+ user = None
2030+ ramdisk = None
2031+ try:
2032+ cert_path = euca.get_environ('EC2_CERT')
2033+ private_key_path = euca.get_environ('EC2_PRIVATE_KEY')
2034+ ec2cert_path = euca.get_environ('EUCALYPTUS_CERT')
2035+ user_string = euca.get_environ('EC2_USER_ID')
2036+ except NotFoundError:
2037+ sys.exit(1)
2038+
2039+ prefix = 'image'
2040+ size_in_MB = 10 * 1024
2041+ destination_path = '/disk1'
2042+ target_arch = 'x86_64'
2043+ mapping = None
2044+ excludes_string = None
2045+ excludes = None
2046+ all = False
2047+ volume_path = '/'
2048+ inherit = True
2049+ product_codes = None
2050+ ancestor_ami_ids = None
2051+ fstab_path = None
2052+ generate_fstab = False
2053+ product_code_string = None
2054+ if user_string:
2055+ try:
2056+ user = int(user_string)
2057+ except ValueError:
2058+ print 'Invalid user', user_string
2059+ sys.exit()
2060+ user = user_string
2061+
2062+ for (name, value) in euca.opts:
2063+ if name in ('-h', '--help'):
2064+ usage(0)
2065+ elif name in ('-c', '--cert'):
2066+ cert_path = value
2067+ elif name in ('-k', '--privatekey'):
2068+ private_key_path = value
2069+ elif name in ('-u', '--user'):
2070+ try:
2071+ value = value.replace('-', '')
2072+ user = int(value)
2073+ except ValueError:
2074+ print 'Invalid user', value
2075+ sys.exit()
2076+ user = value
2077+ elif name == '--kernel':
2078+ kernel = value
2079+ elif name == '--ramdisk':
2080+ ramdisk = value
2081+ elif name in ('-p', '--prefix'):
2082+ prefix = value
2083+ elif name in ('-s', '--size'):
2084+ size_in_MB = int(value)
2085+ elif name in ('-v', '--volume'):
2086+ volume_path = value
2087+ elif name in ('-e', '--exclude'):
2088+ excludes_string = value
2089+ elif name in ('-d', '--destination'):
2090+ destination_path = value
2091+ elif name == '--ec2cert':
2092+ ec2cert_path = value
2093+ elif name in ('-a', '--all'):
2094+ all = True
2095+ elif name in ('-r', '--arch'):
2096+ target_arch = value
2097+ if target_arch != 'i386' and target_arch != 'x86_64':
2098+ print 'target architecture must be i386 or x86_64'
2099+ usage()
2100+ elif name in ('-B', '--block-device-mapping'):
2101+ mapping = value
2102+ elif name == '--no-inherit':
2103+ inherit = False
2104+ elif name == '--generate-fstab':
2105+ generate_fstab = True
2106+ elif name == '--fstab':
2107+ fstab_path = value
2108+ elif name == '--productcodes':
2109+ product_code_string = value
2110+ elif name == '--version':
2111+ version()
2112+
2113+ if size_in_MB and cert_path and private_key_path and user \
2114+ and ec2cert_path:
2115+ try:
2116+ euca.validate_file(cert_path)
2117+ except FileValidationError:
2118+ print 'Invalid cert'
2119+ sys.exit(1)
2120+ try:
2121+ euca.validate_file(private_key_path)
2122+ except FileValidationError:
2123+ print 'Invalid private key'
2124+ sys.exit(1)
2125+ try:
2126+ euca.validate_file(ec2cert_path)
2127+ except FileValidationError:
2128+ print 'Invalid ec2cert'
2129+ sys.exit(1)
2130+ try:
2131+ euca.validate_dir(volume_path)
2132+ except DirValidationError:
2133+ print 'Invalid directory', volume_path
2134+ sys.exit(1)
2135+ if generate_fstab and fstab_path:
2136+ print '--generate-fstab and --fstab path cannot both be set.'
2137+ sys.exit(1)
2138+ if fstab_path:
2139+ try:
2140+ euca.validate_file(fstab_path)
2141+ except FileValidationError:
2142+ print 'Invalid fstab path'
2143+ sys.exit(1)
2144+ if not fstab_path:
2145+ if platform.machine() == 'i386':
2146+ fstab_path = 'old'
2147+ else:
2148+ fstab_path = 'new'
2149+
2150+ check_root()
2151+ check_image_size(size_in_MB)
2152+ volume_path = os.path.normpath(volume_path)
2153+ if not all:
2154+ excludes = parse_excludes(excludes_string)
2155+ euca.add_excludes(volume_path, excludes)
2156+ if inherit:
2157+ (ramdisk, kernel, mapping, product_codes,
2158+ ancestor_ami_ids) = get_instance_metadata(euca, ramdisk,
2159+ kernel, mapping)
2160+ if product_code_string:
2161+ product_codes = add_product_codes(product_code_string,
2162+ product_codes)
2163+ try:
2164+ image_path = euca.make_image(size_in_MB, excludes, prefix,
2165+ destination_path)
2166+ except NotFoundError:
2167+ sys.exit(1)
2168+ except UnsupportedException:
2169+ sys.exit(1)
2170+ image_path = os.path.normpath(image_path)
2171+ if image_path.find(volume_path) == 0:
2172+ exclude_image = image_path.replace(volume_path, '', 1)
2173+ image_path_parts = exclude_image.split('/')
2174+ if len(image_path_parts) > 1:
2175+ exclude_image = \
2176+ exclude_image.replace(image_path_parts[0] + '/', ''
2177+ , 1)
2178+ excludes.append(exclude_image)
2179+ try:
2180+ euca.copy_volume(image_path, volume_path, excludes,
2181+ generate_fstab, fstab_path)
2182+ except CopyError:
2183+ print 'Unable to copy files'
2184+ cleanup(image_path)
2185+ sys.exit(1)
2186+ except NotFoundError:
2187+ cleanup(image_path)
2188+ sys.exit(1)
2189+ except CommandFailed:
2190+ cleanup(image_path)
2191+ sys.exit(1)
2192+ except UnsupportedException:
2193+ cleanup(image_path)
2194+ sys.exit(1)
2195+
2196+ (image_size, sha_image_digest) = euca.check_image(image_path,
2197+ destination_path)
2198+ if not prefix:
2199+ prefix = euca.get_relative_filename(image_path)
2200+ try:
2201+ tgz_file = euca.tarzip_image(prefix, image_path,
2202+ destination_path)
2203+ except NotFoundError:
2204+ sys.exit(1)
2205+ except CommandFailed:
2206+ sys.exit(1)
2207+
2208+ (encrypted_file, key, iv, bundled_size) = \
2209+ euca.encrypt_image(tgz_file)
2210+ os.remove(tgz_file)
2211+ (parts, parts_digest) = euca.split_image(encrypted_file)
2212+ euca.generate_manifest(
2213+ destination_path,
2214+ prefix,
2215+ parts,
2216+ parts_digest,
2217+ image_path,
2218+ key,
2219+ iv,
2220+ cert_path,
2221+ ec2cert_path,
2222+ private_key_path,
2223+ target_arch,
2224+ image_size,
2225+ bundled_size,
2226+ sha_image_digest,
2227+ user,
2228+ kernel,
2229+ ramdisk,
2230+ mapping,
2231+ product_codes,
2232+ ancestor_ami_ids,
2233+ )
2234+ os.remove(encrypted_file)
2235+ else:
2236+
2237+# ....cleanup(image_path)
2238+
2239+ if not size_in_MB:
2240+ print 'size must be specified.'
2241+ if not cert_path:
2242+ print 'cert must be specified.'
2243+ if not private_key_path:
2244+ print 'privatekey must be specified.'
2245+ if not user:
2246+ print 'user must be specified.'
2247+ if not ec2cert_path:
2248+ defcert = "/usr/share/euca2ools/cert-ec2.pem"
2249+ if os.path.exists(defcert):
2250+ ec2cert_path = defcert
2251+ else:
2252+ print 'ec2cert must be specified or exist in %s.' % defcert
2253+ usage()
2254+
2255+
2256+if __name__ == '__main__':
2257+ main()
2258+
2259
2260=== added directory '.pc/bundle-vol-use-ec2-cert-by-default.patch'
2261=== added file '.pc/bundle-vol-use-ec2-cert-by-default.patch/.timestamp'
2262=== added directory '.pc/bundle-vol-use-ec2-cert-by-default.patch/bin'
2263=== added file '.pc/bundle-vol-use-ec2-cert-by-default.patch/bin/euca-bundle-vol'
2264--- .pc/bundle-vol-use-ec2-cert-by-default.patch/bin/euca-bundle-vol 1970-01-01 00:00:00 +0000
2265+++ .pc/bundle-vol-use-ec2-cert-by-default.patch/bin/euca-bundle-vol 2010-11-17 22:00:42 +0000
2266@@ -0,0 +1,452 @@
2267+#!/usr/bin/python
2268+# -*- coding: utf-8 -*-
2269+
2270+# Software License Agreement (BSD License)
2271+#
2272+# Copyright (c) 2009, Eucalyptus Systems, Inc.
2273+# All rights reserved.
2274+#
2275+# Redistribution and use of this software in source and binary forms, with or
2276+# without modification, are permitted provided that the following conditions
2277+# are met:
2278+#
2279+# Redistributions of source code must retain the above
2280+# copyright notice, this list of conditions and the
2281+# following disclaimer.
2282+#
2283+# Redistributions in binary form must reproduce the above
2284+# copyright notice, this list of conditions and the
2285+# following disclaimer in the documentation and/or other
2286+# materials provided with the distribution.
2287+#
2288+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2289+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2290+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2291+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2292+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2293+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2294+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2295+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2296+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2297+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2298+# POSSIBILITY OF SUCH DAMAGE.
2299+#
2300+# Author: Neil Soman neil@eucalyptus.com
2301+
2302+import getopt
2303+import sys
2304+import os
2305+from euca2ools import Euca2ool, FileValidationError, \
2306+ DirValidationError, CopyError, MetadataReadError, Util, \
2307+ NotFoundError, CommandFailed, UnsupportedException
2308+from subprocess import *
2309+import platform
2310+
2311+usage_string = \
2312+ """
2313+Bundle the local filesystem of a running instance as a bundled image.
2314+
2315+euca-bundle-vol -u, --user user -s, --size size_in_MB
2316+[-c, --cert cert_path] [-k, --privatekey private_key_path]
2317+[-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]
2318+[-d, --destination destination_path] [--ec2cert ec2cert_path] [-r, --arch target_architecture] [--batch] [--version]
2319+
2320+REQUIRED PARAMETERS
2321+
2322+-u, --user User ID (12-digit) of the user who is bundling the image.
2323+
2324+-s, --size Size for the image in MB (default: 10GB or 10240MB).
2325+
2326+OPTIONAL PARAMETERS
2327+
2328+-c, --cert Path to the user's PEM encoded certificate.
2329+
2330+-k, --privatekey Path to the user's PEM encoded private key.
2331+
2332+-a, --all Bundle all directories (including mounted filesystems).
2333+
2334+-p, --prefix The prefix for the bundle image files. (default: image name).
2335+
2336+--[no-]inherit Add (or do not add) instance metadata to the bundled image. Inherit is set by default.
2337+
2338+-e, --exclude comma-separated list of directories to exclude.
2339+
2340+--kernel The kernel to be associated with the bundled image.
2341+
2342+--ramdisk The ramdisk to be associated with the bundled image.
2343+
2344+-B, --block-device-mapping Default block device mapping for the image (comma-separated list of key=value pairs).
2345+
2346+-d, --destination Directory to store the bundled image in (default: "/tmp"). Recommended.
2347+
2348+--ec2cert The path to the Cloud's X509 public key certificate.
2349+
2350+-r, --arch Target architecture for the image ('x86_64' or 'i386' default: 'x86_64').
2351+
2352+-v, --volume Path to mounted volume to create the bundle from (default: "/").
2353+
2354+--fstab Path to the fstab to be bundled into the image.
2355+
2356+--generate-fstab Generate fstab to bundle into the image.
2357+
2358+--batch Run in batch mode (compatibility only. has no effect).
2359+"""
2360+
2361+MAX_IMAGE_SIZE = 1024 * 10
2362+
2363+
2364+def usage(status=1):
2365+ print usage_string
2366+ sys.exit(status)
2367+
2368+
2369+def version():
2370+ print Util().version()
2371+ sys.exit()
2372+
2373+
2374+def check_root():
2375+ if os.geteuid() == 0:
2376+ return
2377+ else:
2378+ print 'Must be superuser to execute this command.'
2379+ sys.exit()
2380+
2381+
2382+def check_image_size(size):
2383+ if size > MAX_IMAGE_SIZE:
2384+ print 'Image Size is too large (Max = %d MB)' % MAX_IMAGE_SIZE
2385+ sys.exit()
2386+
2387+
2388+def parse_excludes(excludes_string):
2389+ excludes = []
2390+ if excludes_string:
2391+ excludes_string = excludes_string.replace(' ', '')
2392+ excludes = excludes_string.split(',')
2393+ return excludes
2394+
2395+
2396+def get_instance_metadata(
2397+ euca,
2398+ ramdisk,
2399+ kernel,
2400+ mapping,
2401+ ):
2402+ product_codes = None
2403+ ramdisk_id = ramdisk
2404+ kernel_id = kernel
2405+ block_dev_mapping = mapping
2406+ ancestor_ami_ids = None
2407+ try:
2408+ euca.can_read_instance_metadata()
2409+ if not ramdisk_id:
2410+ try:
2411+ ramdisk_id = euca.get_instance_ramdisk()
2412+ except MetadataReadError:
2413+ print 'Unable to read ramdisk id'
2414+
2415+ if not kernel_id:
2416+ try:
2417+ kernel_id = euca.get_instance_kernel()
2418+ except MetadataReadError:
2419+ print 'Unable to read kernel id'
2420+
2421+ if not block_dev_mapping:
2422+ try:
2423+ block_dev_mapping = \
2424+ euca.get_instance_block_device_mappings()
2425+ except MetadataReadError:
2426+ print 'Unable to read block device mapping'
2427+
2428+ try:
2429+ product_codes = euca.get_instance_product_codes().split('\n'
2430+ )
2431+ except MetadataReadError:
2432+ print 'Unable to read product codes'
2433+
2434+ try:
2435+ ancestor_ami_ids = euca.get_ancestor_ami_ids().split('\n')
2436+ except MetadataReadError:
2437+ print 'Unable to read product codes'
2438+ except IOError:
2439+
2440+ print 'Unable to read instance metadata. Pass the --no-inherit option if you wish to exclude instance metadata.'
2441+ sys.exit()
2442+
2443+ return (ramdisk_id, kernel_id, block_dev_mapping, product_codes,
2444+ ancestor_ami_ids)
2445+
2446+
2447+def add_product_codes(product_code_string, product_codes):
2448+ if not product_codes:
2449+ product_codes = []
2450+ product_code_values = product_code_string.split(',')
2451+
2452+ for p in product_code_values:
2453+ product_codes.append(p)
2454+
2455+ return product_codes
2456+
2457+
2458+def cleanup(path):
2459+ if os.path.exists(path):
2460+ os.remove(path)
2461+
2462+
2463+def main():
2464+ euca = None
2465+ try:
2466+ euca = Euca2ool('a:c:k:u:B:d:br:p:s:v:e:', [
2467+ 'cert=',
2468+ 'privatekey=',
2469+ 'user=',
2470+ 'prefix=',
2471+ 'volume=',
2472+ 'all',
2473+ 'kernel=',
2474+ 'ramdisk=',
2475+ 'block-device-mapping=',
2476+ 'destination=',
2477+ 'ec2cert=',
2478+ 'arch=',
2479+ 'size=',
2480+ 'exclude=',
2481+ 'inherit=',
2482+ 'no-inherit',
2483+ 'batch',
2484+ 'fstab=',
2485+ 'generate-fstab',
2486+ 'productcodes=',
2487+ ])
2488+ except Exception, e:
2489+ print e
2490+ usage()
2491+
2492+ kernel = None
2493+ user = None
2494+ ramdisk = None
2495+ try:
2496+ cert_path = euca.get_environ('EC2_CERT')
2497+ private_key_path = euca.get_environ('EC2_PRIVATE_KEY')
2498+ ec2cert_path = euca.get_environ('EUCALYPTUS_CERT')
2499+ user_string = euca.get_environ('EC2_USER_ID')
2500+ except NotFoundError:
2501+ sys.exit(1)
2502+
2503+ prefix = 'image'
2504+ size_in_MB = 10 * 1024
2505+ destination_path = '/disk1'
2506+ target_arch = 'x86_64'
2507+ mapping = None
2508+ excludes_string = None
2509+ excludes = None
2510+ all = False
2511+ volume_path = '/'
2512+ inherit = True
2513+ product_codes = None
2514+ ancestor_ami_ids = None
2515+ fstab_path = None
2516+ generate_fstab = False
2517+ product_code_string = None
2518+ if user_string:
2519+ try:
2520+ user = int(user_string)
2521+ except ValueError:
2522+ print 'Invalid user', user_string
2523+ sys.exit()
2524+ user = user_string
2525+
2526+ for (name, value) in euca.opts:
2527+ if name in ('-h', '--help'):
2528+ usage(0)
2529+ elif name in ('-c', '--cert'):
2530+ cert_path = value
2531+ elif name in ('-k', '--privatekey'):
2532+ private_key_path = value
2533+ elif name in ('-u', '--user'):
2534+ try:
2535+ value = value.replace('-', '')
2536+ user = int(value)
2537+ except ValueError:
2538+ print 'Invalid user', value
2539+ sys.exit()
2540+ user = value
2541+ elif name == '--kernel':
2542+ kernel = value
2543+ elif name == '--ramdisk':
2544+ ramdisk = value
2545+ elif name in ('-p', '--prefix'):
2546+ prefix = value
2547+ elif name in ('-s', '--size'):
2548+ size_in_MB = int(value)
2549+ elif name in ('-v', '--volume'):
2550+ volume_path = value
2551+ elif name in ('-e', '--exclude'):
2552+ excludes_string = value
2553+ elif name in ('-d', '--destination'):
2554+ destination_path = value
2555+ elif name == '--ec2cert':
2556+ ec2cert_path = value
2557+ elif name in ('-a', '--all'):
2558+ all = True
2559+ elif name in ('-r', '--arch'):
2560+ target_arch = value
2561+ if target_arch != 'i386' and target_arch != 'x86_64':
2562+ print 'target architecture must be i386 or x86_64'
2563+ usage()
2564+ elif name in ('-B', '--block-device-mapping'):
2565+ mapping = value
2566+ elif name == '--no-inherit':
2567+ inherit = False
2568+ elif name == '--generate-fstab':
2569+ generate_fstab = True
2570+ elif name == '--fstab':
2571+ fstab_path = value
2572+ elif name == '--productcodes':
2573+ product_code_string = value
2574+ elif name == '--version':
2575+ version()
2576+
2577+ if size_in_MB and cert_path and private_key_path and user \
2578+ and ec2cert_path:
2579+ try:
2580+ euca.validate_file(cert_path)
2581+ except FileValidationError:
2582+ print 'Invalid cert'
2583+ sys.exit(1)
2584+ try:
2585+ euca.validate_file(private_key_path)
2586+ except FileValidationError:
2587+ print 'Invalid private key'
2588+ sys.exit(1)
2589+ try:
2590+ euca.validate_file(ec2cert_path)
2591+ except FileValidationError:
2592+ print 'Invalid ec2cert'
2593+ sys.exit(1)
2594+ try:
2595+ euca.validate_dir(volume_path)
2596+ except DirValidationError:
2597+ print 'Invalid directory', volume_path
2598+ sys.exit(1)
2599+ if generate_fstab and fstab_path:
2600+ print '--generate-fstab and --fstab path cannot both be set.'
2601+ sys.exit(1)
2602+ if fstab_path:
2603+ try:
2604+ euca.validate_file(fstab_path)
2605+ except FileValidationError:
2606+ print 'Invalid fstab path'
2607+ sys.exit(1)
2608+ if not fstab_path:
2609+ if platform.machine() == 'i386':
2610+ fstab_path = 'old'
2611+ else:
2612+ fstab_path = 'new'
2613+
2614+ check_root()
2615+ check_image_size(size_in_MB)
2616+ volume_path = os.path.normpath(volume_path)
2617+ if not all:
2618+ excludes = parse_excludes(excludes_string)
2619+ euca.add_excludes(volume_path, excludes)
2620+ if inherit:
2621+ (ramdisk, kernel, mapping, product_codes,
2622+ ancestor_ami_ids) = get_instance_metadata(euca, ramdisk,
2623+ kernel, mapping)
2624+ if product_code_string:
2625+ product_codes = add_product_codes(product_code_string,
2626+ product_codes)
2627+ try:
2628+ image_path = euca.make_image(size_in_MB, excludes, prefix,
2629+ destination_path)
2630+ except NotFoundError:
2631+ sys.exit(1)
2632+ except UnsupportedException:
2633+ sys.exit(1)
2634+ image_path = os.path.normpath(image_path)
2635+ if image_path.find(volume_path) == 0:
2636+ exclude_image = image_path.replace(volume_path, '', 1)
2637+ image_path_parts = exclude_image.split('/')
2638+ if len(image_path_parts) > 1:
2639+ exclude_image = \
2640+ exclude_image.replace(image_path_parts[0] + '/', ''
2641+ , 1)
2642+ excludes.append(exclude_image)
2643+ try:
2644+ euca.copy_volume(image_path, volume_path, excludes,
2645+ generate_fstab, fstab_path)
2646+ except CopyError:
2647+ print 'Unable to copy files'
2648+ cleanup(image_path)
2649+ sys.exit(1)
2650+ except NotFoundError:
2651+ cleanup(image_path)
2652+ sys.exit(1)
2653+ except CommandFailed:
2654+ cleanup(image_path)
2655+ sys.exit(1)
2656+ except UnsupportedException:
2657+ cleanup(image_path)
2658+ sys.exit(1)
2659+
2660+ (image_size, sha_image_digest) = euca.check_image(image_path,
2661+ destination_path)
2662+ if not prefix:
2663+ prefix = euca.get_relative_filename(image_path)
2664+ try:
2665+ tgz_file = euca.tarzip_image(prefix, image_path,
2666+ destination_path)
2667+ except NotFoundError:
2668+ sys.exit(1)
2669+ except CommandFailed:
2670+ sys.exit(1)
2671+
2672+ (encrypted_file, key, iv, bundled_size) = \
2673+ euca.encrypt_image(tgz_file)
2674+ os.remove(tgz_file)
2675+ (parts, parts_digest) = euca.split_image(encrypted_file)
2676+ euca.generate_manifest(
2677+ destination_path,
2678+ prefix,
2679+ parts,
2680+ parts_digest,
2681+ image_path,
2682+ key,
2683+ iv,
2684+ cert_path,
2685+ ec2cert_path,
2686+ private_key_path,
2687+ target_arch,
2688+ image_size,
2689+ bundled_size,
2690+ sha_image_digest,
2691+ user,
2692+ kernel,
2693+ ramdisk,
2694+ mapping,
2695+ product_codes,
2696+ ancestor_ami_ids,
2697+ )
2698+ os.remove(encrypted_file)
2699+ else:
2700+
2701+# ....cleanup(image_path)
2702+
2703+ if not size_in_MB:
2704+ print 'size must be specified.'
2705+ if not cert_path:
2706+ print 'cert must be specified.'
2707+ if not private_key_path:
2708+ print 'privatekey must be specified.'
2709+ if not user:
2710+ print 'user must be specified.'
2711+ if not ec2cert_path:
2712+ print 'ec2cert must be specified.'
2713+ usage()
2714+
2715+
2716+if __name__ == '__main__':
2717+ main()
2718+
2719
2720=== added directory '.pc/describe-image-attribute-empty-kernel-ramdisk.patch'
2721=== added file '.pc/describe-image-attribute-empty-kernel-ramdisk.patch/.timestamp'
2722=== added directory '.pc/describe-image-attribute-empty-kernel-ramdisk.patch/bin'
2723=== added file '.pc/describe-image-attribute-empty-kernel-ramdisk.patch/bin/euca-describe-image-attribute'
2724--- .pc/describe-image-attribute-empty-kernel-ramdisk.patch/bin/euca-describe-image-attribute 1970-01-01 00:00:00 +0000
2725+++ .pc/describe-image-attribute-empty-kernel-ramdisk.patch/bin/euca-describe-image-attribute 2010-11-17 22:00:42 +0000
2726@@ -0,0 +1,166 @@
2727+#!/usr/bin/python
2728+# -*- coding: utf-8 -*-
2729+
2730+# Software License Agreement (BSD License)
2731+#
2732+# Copyright (c) 2009, Eucalyptus Systems, Inc.
2733+# All rights reserved.
2734+#
2735+# Redistribution and use of this software in source and binary forms, with or
2736+# without modification, are permitted provided that the following conditions
2737+# are met:
2738+#
2739+# Redistributions of source code must retain the above
2740+# copyright notice, this list of conditions and the
2741+# following disclaimer.
2742+#
2743+# Redistributions in binary form must reproduce the above
2744+# copyright notice, this list of conditions and the
2745+# following disclaimer in the documentation and/or other
2746+# materials provided with the distribution.
2747+#
2748+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2749+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2750+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2751+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2752+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2753+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2754+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2755+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2756+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2757+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2758+# POSSIBILITY OF SUCH DAMAGE.
2759+#
2760+# Author: Neil Soman neil@eucalyptus.com
2761+
2762+import getopt
2763+import sys
2764+import os
2765+from euca2ools import Euca2ool, Util, ConnectionFailed
2766+
2767+usage_string = \
2768+ """
2769+Show image attributes.
2770+
2771+euca-describe-image-attribute [-l, --launch-permission] [-p, --product-code]
2772+[-B, --block-device-mapping] [--kernel] [--ramdisk]
2773+[-h, --help] [--version] [--debug] image_id
2774+
2775+REQUIRED PARAMETERS
2776+
2777+image_id unique identifier for the image that you want to retrieve the attributes for.
2778+
2779+OPTIONAL PARAMETERS
2780+
2781+-B, --block-device-mapping show block device mapping.
2782+-l, --launch-permission show launch permissions.
2783+-p, --product-code show the product codes associated with the image
2784+--kernel show the kernel id associated with the image.
2785+--ramdisk show the ramdisk id associated with the image.
2786+
2787+"""
2788+
2789+
2790+def usage(status=1):
2791+ print usage_string
2792+ Util().usage()
2793+ sys.exit(status)
2794+
2795+
2796+def version():
2797+ print Util().version()
2798+ sys.exit()
2799+
2800+
2801+def display_image_attribute(image_id, image_attribute):
2802+ if image_attribute.name == 'launch_permission':
2803+ if image_attribute.attrs.has_key('groups'):
2804+ for group in image_attribute.attrs['groups']:
2805+ print 'launchPermission\t%s\tgroup\t%s' \
2806+ % (image_attribute.image_id, group)
2807+ if image_attribute.attrs.has_key('user_ids'):
2808+ for userid in image_attribute.attrs['user_ids']:
2809+ print 'launchPermission\t%s\tuserId\t%s' \
2810+ % (image_attribute.image_id, userid)
2811+ if image_attribute.attrs.has_key('product_codes'):
2812+ for product_code in image_attribute.attrs['product_codes']:
2813+ print 'productCodes\t%s\tproductCode\t%s' \
2814+ % (image_attribute.image_id, product_code)
2815+ if image_attribute.kernel is not None:
2816+ print 'kernel\t%s\t\t%s' % (image_attribute.image_id,
2817+ image_attribute.value)
2818+ if image_attribute.ramdisk is not None:
2819+ print 'ramdisk\t%s\t\t%s' % (image_attribute.image_id,
2820+ image_attribute.value)
2821+ if image_attribute.attrs.has_key('block_device_mapping'):
2822+ block_device_mapping = \
2823+ image_attribute.attrs['block_device_mapping']
2824+ for dev_name in block_device_mapping:
2825+ print 'blockDeviceMapping\t%s\tblockDeviceMap\t%s: %s' \
2826+ % (image_id, dev_name,
2827+ block_device_mapping[dev_name])
2828+
2829+def main():
2830+ euca = None
2831+ try:
2832+ euca = Euca2ool('lpB', ['block-device-mapping',
2833+ 'launch-permission', 'product-code', 'kernel',
2834+ 'ramdisk'])
2835+ except Exception, e:
2836+ print e
2837+ usage()
2838+
2839+ image_id = None
2840+ image_attribute = None
2841+
2842+ for (name, value) in euca.opts:
2843+ if name in ('-p', '--product-code'):
2844+ if not image_attribute:
2845+ image_attribute = 'productCodes'
2846+ elif name in ('-l', '--launch-permission'):
2847+ if not image_attribute:
2848+ image_attribute = 'launchPermission'
2849+ elif name in ('-B', '--block-device-mapping'):
2850+ if not image_attribute:
2851+ image_attribute = 'blockDeviceMapping'
2852+ elif name == '--kernel':
2853+ if not image_attribute:
2854+ image_attribute = 'kernel'
2855+ elif name == '--ramdisk':
2856+ if not image_attribute:
2857+ image_attribute = 'ramdisk'
2858+ elif name in ('-h', '--help'):
2859+ usage(0)
2860+ elif name == '--version':
2861+ version()
2862+
2863+ for arg in euca.args:
2864+ image_id = arg
2865+ break
2866+
2867+ if image_id and image_attribute:
2868+ try:
2869+ euca_conn = euca.make_connection()
2870+ except ConnectionFailed, e:
2871+ print e.message
2872+ sys.exit(1)
2873+ try:
2874+ image_attribute = \
2875+ euca_conn.get_image_attribute(image_id=image_id,
2876+ attribute=image_attribute)
2877+ except Exception, ex:
2878+ euca.display_error_and_exit('%s' % ex)
2879+
2880+ if image_attribute:
2881+ display_image_attribute(image_id, image_attribute)
2882+ else:
2883+ if not image_id:
2884+ print 'image_id must be specified'
2885+ if not image_attribute:
2886+ print 'image attribute must be specified'
2887+ usage()
2888+
2889+
2890+if __name__ == '__main__':
2891+ main()
2892+
2893
2894=== added directory '.pc/describe-images-return-results-like-ec2-describe-images.patch'
2895=== added file '.pc/describe-images-return-results-like-ec2-describe-images.patch/.timestamp'
2896=== added directory '.pc/describe-images-return-results-like-ec2-describe-images.patch/bin'
2897=== added file '.pc/describe-images-return-results-like-ec2-describe-images.patch/bin/euca-describe-images'
2898--- .pc/describe-images-return-results-like-ec2-describe-images.patch/bin/euca-describe-images 1970-01-01 00:00:00 +0000
2899+++ .pc/describe-images-return-results-like-ec2-describe-images.patch/bin/euca-describe-images 2010-11-17 22:00:42 +0000
2900@@ -0,0 +1,162 @@
2901+#!/usr/bin/python
2902+# -*- coding: utf-8 -*-
2903+
2904+# Software License Agreement (BSD License)
2905+#
2906+# Copyright (c) 2009, Eucalyptus Systems, Inc.
2907+# All rights reserved.
2908+#
2909+# Redistribution and use of this software in source and binary forms, with or
2910+# without modification, are permitted provided that the following conditions
2911+# are met:
2912+#
2913+# Redistributions of source code must retain the above
2914+# copyright notice, this list of conditions and the
2915+# following disclaimer.
2916+#
2917+# Redistributions in binary form must reproduce the above
2918+# copyright notice, this list of conditions and the
2919+# following disclaimer in the documentation and/or other
2920+# materials provided with the distribution.
2921+#
2922+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2923+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2924+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2925+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2926+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2927+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2928+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2929+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2930+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2931+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2932+# POSSIBILITY OF SUCH DAMAGE.
2933+#
2934+# Author: Neil Soman neil@eucalyptus.com
2935+
2936+import getopt
2937+import sys
2938+import os
2939+from euca2ools import Euca2ool, Util, ConnectionFailed
2940+
2941+usage_string = \
2942+ """
2943+Shows information about machine images.
2944+
2945+euca-describe-images [-a] [-o owner] [-x user] [-h, --help] [--version] [--debug] [image1 image2 ... imageN]
2946+
2947+OPTIONAL PARAMETERS
2948+
2949+image1 image2 ... imageN Images to describe.
2950+
2951+-a Show all images that the user has access to.
2952+
2953+-o Show only images owned by the owner specified are displayed.
2954+
2955+-x Show only images that the specified user is permitted to launch.
2956+
2957+"""
2958+
2959+
2960+def usage(status=1):
2961+ print usage_string
2962+ Util().usage(compat=True)
2963+ sys.exit(status)
2964+
2965+
2966+def version():
2967+ print Util().version()
2968+ sys.exit()
2969+
2970+
2971+def display_images(images, image_ids):
2972+ check_image_ids = False
2973+ if len(image_ids) > 0:
2974+ check_image_ids = True
2975+ for image in images:
2976+ if check_image_ids:
2977+ if not image.id in image_ids:
2978+ continue
2979+ image_string = '%s\t%s\t%s\t%s' % (image.id, image.location,
2980+ image.ownerId, image.state)
2981+ if image.is_public:
2982+ image_string += '\tpublic'
2983+ else:
2984+ image_string += '\tprivate'
2985+
2986+ image_string += '\t%s' % ','.join(image.product_codes)
2987+
2988+ for i in [image.architecture, image.type, image.kernel_id,
2989+ image.ramdisk_id]:
2990+ image_string += '\t%s' % ((' ' if i == None else i))
2991+
2992+ if image.platform:
2993+ image_string += '\t%s' % image.platform
2994+ if image.root_device_type:
2995+ image_string += '\t%s' % image.root_device_type
2996+ print 'IMAGE\t%s' % image_string
2997+ if image.block_device_mapping:
2998+ block_dev_mapping = image.block_device_mapping
2999+ if image.root_device_type == 'ebs':
3000+ block_dev_string = '%s\t%s\t%s' \
3001+ % (block_dev_mapping.current_name,
3002+ block_dev_mapping.current_value.snapshot_id,
3003+ block_dev_mapping.current_value.size)
3004+ print 'BLOCKDEVICEMAPPING\t%s' % block_dev_string
3005+
3006+
3007+def main():
3008+ euca = None
3009+ try:
3010+ euca = Euca2ool('ao:x:', compat=True)
3011+ except Exception, e:
3012+ print e
3013+ usage()
3014+
3015+ show_all = False
3016+ executable_by = ['self']
3017+ owners = ['self']
3018+ defaults = True
3019+
3020+ for (name, value) in euca.opts:
3021+ if name in ('-h', '--help'):
3022+ usage(0)
3023+ elif name == '-x':
3024+ if defaults:
3025+ executable_by = []
3026+ defaults = False
3027+ owners = []
3028+ executable_by.append(value)
3029+ elif name == '-o':
3030+ if defaults:
3031+ executable_by = []
3032+ defaults = False
3033+ owners.append(value)
3034+ elif name == '-a':
3035+ executable_by = ['self', 'all']
3036+ owners = []
3037+ elif name == '--version':
3038+ version()
3039+
3040+ image_ids = euca.process_args()
3041+ if defaults and len(image_ids) > 0:
3042+ executable_by = ['self', 'all']
3043+ owners = []
3044+
3045+ try:
3046+ euca_conn = euca.make_connection()
3047+ except ConnectionFailed, e:
3048+ print e.message
3049+ sys.exit(1)
3050+
3051+ try:
3052+ images = euca_conn.get_all_images(image_ids=image_ids,
3053+ owners=owners, executable_by=executable_by)
3054+ except Exception, ex:
3055+ euca.display_error_and_exit('%s' % ex)
3056+
3057+ display_images(images, image_ids)
3058+
3059+
3060+if __name__ == '__main__':
3061+ main()
3062+
3063
3064=== added directory '.pc/download-bundle-fix-usage.patch'
3065=== added file '.pc/download-bundle-fix-usage.patch/.timestamp'
3066=== added directory '.pc/download-bundle-fix-usage.patch/bin'
3067=== added file '.pc/download-bundle-fix-usage.patch/bin/euca-download-bundle'
3068--- .pc/download-bundle-fix-usage.patch/bin/euca-download-bundle 1970-01-01 00:00:00 +0000
3069+++ .pc/download-bundle-fix-usage.patch/bin/euca-download-bundle 2010-11-17 22:00:42 +0000
3070@@ -0,0 +1,189 @@
3071+#!/usr/bin/python
3072+# -*- coding: utf-8 -*-
3073+
3074+# Software License Agreement (BSD License)
3075+#
3076+# Copyright (c) 2009, Eucalyptus Systems, Inc.
3077+# All rights reserved.
3078+#
3079+# Redistribution and use of this software in source and binary forms, with or
3080+# without modification, are permitted provided that the following conditions
3081+# are met:
3082+#
3083+# Redistributions of source code must retain the above
3084+# copyright notice, this list of conditions and the
3085+# following disclaimer.
3086+#
3087+# Redistributions in binary form must reproduce the above
3088+# copyright notice, this list of conditions and the
3089+# following disclaimer in the documentation and/or other
3090+# materials provided with the distribution.
3091+#
3092+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3093+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3094+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3095+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
3096+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3097+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3098+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3099+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3100+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3101+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3102+# POSSIBILITY OF SUCH DAMAGE.
3103+#
3104+# Author: Neil Soman neil@eucalyptus.com
3105+
3106+import getopt
3107+import sys
3108+import os
3109+from xml.dom import minidom
3110+from euca2ools import Euca2ool, FileValidationError, Util, \
3111+ ConnectionFailed
3112+from boto.exception import S3ResponseError
3113+from boto.s3 import Connection
3114+from boto.s3.key import Key
3115+
3116+usage_string = \
3117+ """
3118+Downloads a bundled image from a bucket.
3119+
3120+euca-download-bundle -b, --bucket bucket [-m, --manifest manifest_path] [-d, --directory directory]
3121+[-h, --help] [--version] [--debug]
3122+
3123+REQUIRED PARAMETERS
3124+
3125+-b, --bucket The name of the bucket to download to. Bucket will be created if it does not exist.
3126+
3127+OPTIONAL PARAMETERS
3128+
3129+-m, --manifest_path The path to the manifest file.
3130+
3131+-d, --directory The name of the directory to download the bundled parts to.
3132+
3133+"""
3134+
3135+
3136+def usage(status=1):
3137+ print usage_string
3138+ Util().usage()
3139+ sys.exit(status)
3140+
3141+
3142+def version():
3143+ print Util().version()
3144+ sys.exit()
3145+
3146+
3147+def ensure_bucket(connection, bucket):
3148+ bucket_instance = None
3149+ try:
3150+ bucket_instance = connection.get_bucket(bucket)
3151+ except S3ResponseError, s3error:
3152+ print 'Unable to get bucket %s' % bucket
3153+ sys.exit()
3154+ return bucket_instance
3155+
3156+
3157+def get_parts(manifest_filename):
3158+ parts = []
3159+ dom = minidom.parse(manifest_filename)
3160+ manifest_elem = dom.getElementsByTagName('manifest')[0]
3161+ parts_list = manifest_elem.getElementsByTagName('filename')
3162+ for part_elem in parts_list:
3163+ nodes = part_elem.childNodes
3164+ for node in nodes:
3165+ if node.nodeType == node.TEXT_NODE:
3166+ parts.append(node.data)
3167+ return parts
3168+
3169+
3170+def get_relative_filename(filename):
3171+ f_parts = filename.split('/')
3172+ return f_parts[len(f_parts) - 1]
3173+
3174+
3175+def get_manifests(bucket):
3176+ manifests = []
3177+ keys = bucket.get_all_keys()
3178+ for k in keys:
3179+ if k.name:
3180+ if k.name.find('manifest') >= 0:
3181+ manifests.append(k.name)
3182+ return manifests
3183+
3184+
3185+def download_manifests(bucket, manifests, directory):
3186+ if len(manifests) > 0:
3187+ if not os.path.exists(directory):
3188+ os.makedirs(directory)
3189+ for manifest in manifests:
3190+ k = Key(bucket)
3191+ k.key = manifest
3192+ print 'Downloading', manifest
3193+ manifest_file = open(os.path.join(directory, manifest), 'wb')
3194+ k.get_contents_to_file(manifest_file)
3195+ manifest_file.close()
3196+
3197+
3198+def download_parts(bucket, manifests, directory):
3199+ for manifest in manifests:
3200+ manifest_filename = os.path.join(directory, manifest)
3201+ parts = get_parts(manifest_filename)
3202+ for part in parts:
3203+ k = Key(bucket)
3204+ k.key = part
3205+ print 'Downloading', part
3206+ part_file = open(os.path.join(directory, part), 'wb')
3207+ k.get_contents_to_file(part_file)
3208+ part_file.close()
3209+
3210+
3211+def main():
3212+ euca = None
3213+ try:
3214+ euca = Euca2ool('b:m:d:', ['bucket=', 'manifest=', 'directory='
3215+ ], is_s3=True)
3216+ except Exception, e:
3217+ print e
3218+ usage()
3219+
3220+ bucket = None
3221+ manifest_path = None
3222+ directory = '/tmp'
3223+
3224+ for (name, value) in euca.opts:
3225+ if name in ('-h', '--help'):
3226+ usage(0)
3227+ elif name in ('-d', '--directory'):
3228+ directory = value
3229+ elif name in ('-b', '--bucket'):
3230+ bucket = value
3231+ elif name in ('-m', '--manifest'):
3232+ manifest_path = value
3233+
3234+ if bucket:
3235+ if manifest_path:
3236+ try:
3237+ euca.validate_file(manifest_path)
3238+ except FileValidationError:
3239+ print 'Invalid manifest', manifest_path
3240+ sys.exit(1)
3241+
3242+ try:
3243+ conn = euca.make_connection()
3244+ except ConnectionFailed, e:
3245+ print e.message
3246+ sys.exit(1)
3247+
3248+ bucket_instance = ensure_bucket(conn, bucket)
3249+ manifests = get_manifests(bucket_instance)
3250+ download_manifests(bucket_instance, manifests, directory)
3251+ download_parts(bucket_instance, manifests, directory)
3252+ else:
3253+ print 'bucket must be specified.'
3254+ usage()
3255+
3256+
3257+if __name__ == '__main__':
3258+ main()
3259+
3260
3261=== added directory '.pc/download-bundle-fix-usage.patch/man'
3262=== added file '.pc/download-bundle-fix-usage.patch/man/euca-download-bundle.1'
3263--- .pc/download-bundle-fix-usage.patch/man/euca-download-bundle.1 1970-01-01 00:00:00 +0000
3264+++ .pc/download-bundle-fix-usage.patch/man/euca-download-bundle.1 2010-11-17 22:00:42 +0000
3265@@ -0,0 +1,72 @@
3266+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
3267+.TH BUCKET "1" "July 2010" "bucket must be specified." "User Commands"
3268+.SH NAME
3269+bucket \- Eucalyptus tool: Downloads a bundled image from a bucket.
3270+.SH DESCRIPTION
3271+Downloads a bundled image from a bucket.
3272+.PP
3273+euca\-download\-bundle \fB\-b\fR, \fB\-\-bucket\fR bucket [\-m, \fB\-\-manifest\fR manifest_path] [\-d, \fB\-\-directory\fR directory]
3274+[\-h, \fB\-\-help]\fR [\-\-version] [\-\-debug]
3275+.PP
3276+REQUIRED PARAMETERS
3277+.PP
3278+
3279+\fB\-b\fR, \fB\-\-bucket\fR The name of the bucket to download to. Bucket will be created if it does not exist.
3280+.PP
3281+OPTIONAL PARAMETERS
3282+.PP
3283+\fB\-m\fR, \fB\-\-manifest_path\fR The path to the manifest file.
3284+.PP
3285+\fB\-d\fR, \fB\-\-directory\fR The name of the directory to download the bundled parts to.
3286+.PP
3287+\fB\-a\fR, \fB\-\-access\-key\fR User's Access Key ID.
3288+.PP
3289+\fB\-s\fR, \fB\-\-secret\-key\fR User's Secret Key.
3290+.PP
3291+\fB\-U\fR, \fB\-\-url\fR URL of the Cloud to connect to.
3292+.PP
3293+\fB\-\-config\fR Read credentials and cloud settings from the
3294+.IP
3295+specified config file (defaults to $HOME/.eucarc or /etc/euca2ools/eucarc).
3296+.PP
3297+\fB\-h\fR, \fB\-\-help\fR Display this help message.
3298+.PP
3299+\fB\-\-version\fR Display the version of this tool.
3300+.PP
3301+\fB\-\-debug\fR Turn on debugging.
3302+.PP
3303+Euca2ools will use the environment variables EC2_URL, EC2_ACCESS_KEY, EC2_SECRET_KEY, EC2_CERT, EC2_PRIVATE_KEY, S3_URL, EUCALYPTUS_CERT by default.
3304+.PP
3305+Downloads a bundled image from a bucket.
3306+.PP
3307+euca\-download\-bundle \fB\-b\fR, \fB\-\-bucket\fR bucket [\-m, \fB\-\-manifest\fR manifest_path] [\-d, \fB\-\-directory\fR directory]
3308+[\-h, \fB\-\-help]\fR [\-\-version] [\-\-debug]
3309+.PP
3310+REQUIRED PARAMETERS
3311+.PP
3312+
3313+\fB\-b\fR, \fB\-\-bucket\fR The name of the bucket to download to. Bucket will be created if it does not exist.
3314+.PP
3315+OPTIONAL PARAMETERS
3316+.PP
3317+\fB\-m\fR, \fB\-\-manifest_path\fR The path to the manifest file.
3318+.PP
3319+\fB\-d\fR, \fB\-\-directory\fR The name of the directory to download the bundled parts to.
3320+.PP
3321+\fB\-a\fR, \fB\-\-access\-key\fR User's Access Key ID.
3322+.PP
3323+\fB\-s\fR, \fB\-\-secret\-key\fR User's Secret Key.
3324+.PP
3325+\fB\-U\fR, \fB\-\-url\fR URL of the Cloud to connect to.
3326+.PP
3327+\fB\-\-config\fR Read credentials and cloud settings from the
3328+.IP
3329+specified config file (defaults to $HOME/.eucarc or /etc/euca2ools/eucarc).
3330+.PP
3331+\fB\-h\fR, \fB\-\-help\fR Display this help message.
3332+.PP
3333+\fB\-\-version\fR Display the version of this tool.
3334+.PP
3335+\fB\-\-debug\fR Turn on debugging.
3336+.PP
3337+Euca2ools will use the environment variables EC2_URL, EC2_ACCESS_KEY, EC2_SECRET_KEY, EC2_CERT, EC2_PRIVATE_KEY, S3_URL, EUCALYPTUS_CERT by default.
3338
3339=== added directory '.pc/euca-revoke-exit-on-usage.patch'
3340=== added file '.pc/euca-revoke-exit-on-usage.patch/.timestamp'
3341=== added directory '.pc/euca-revoke-exit-on-usage.patch/bin'
3342=== added file '.pc/euca-revoke-exit-on-usage.patch/bin/euca-revoke'
3343--- .pc/euca-revoke-exit-on-usage.patch/bin/euca-revoke 1970-01-01 00:00:00 +0000
3344+++ .pc/euca-revoke-exit-on-usage.patch/bin/euca-revoke 2010-11-17 22:00:42 +0000
3345@@ -0,0 +1,202 @@
3346+#!/usr/bin/python
3347+# -*- coding: utf-8 -*-
3348+
3349+# Software License Agreement (BSD License)
3350+#
3351+# Copyright (c) 2009, Eucalyptus Systems, Inc.
3352+# All rights reserved.
3353+#
3354+# Redistribution and use of this software in source and binary forms, with or
3355+# without modification, are permitted provided that the following conditions
3356+# are met:
3357+#
3358+# Redistributions of source code must retain the above
3359+# copyright notice, this list of conditions and the
3360+# following disclaimer.
3361+#
3362+# Redistributions in binary form must reproduce the above
3363+# copyright notice, this list of conditions and the
3364+# following disclaimer in the documentation and/or other
3365+# materials provided with the distribution.
3366+#
3367+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3368+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3369+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3370+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
3371+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3372+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3373+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3374+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3375+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3376+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3377+# POSSIBILITY OF SUCH DAMAGE.
3378+#
3379+# Author: Neil Soman neil@eucalyptus.com
3380+
3381+import getopt
3382+import sys
3383+import os
3384+from euca2ools import Euca2ool, AddressValidationError, \
3385+ ProtocolValidationError, Util, ConnectionFailed
3386+
3387+usage_string = \
3388+ """
3389+Revoke a rule for a security group.
3390+
3391+euca-revoke [-P | --protocol protocol] [-p | --port-range port_range]
3392+[-t | --icmp-type-code type:code] [-o | --source-group source_group]
3393+[-u | --source-group-user source_group_user] [-s | --source-subnet source_subnet]
3394+[-h, --help] [--version] [--debug] group_name
3395+
3396+REQUIRED PARAMETERS
3397+
3398+group_name Name of the group to add the rule to.
3399+
3400+OPTIONAL PARAMETERS
3401+
3402+-P, --protocol Protocol ("tcp" "udp" or "icmp").
3403+
3404+-p, --port-range Range of ports for the rule (specified as "from-to").
3405+
3406+-t, --icmp-type-code ICMP type and code specified as "type:code"
3407+
3408+-o, --source-group Group from which traffic is authorized by the rule.
3409+
3410+-u, --source-group-user User ID for the source group.
3411+
3412+-s, --source-subnet The source subnet for the rule.
3413+
3414+"""
3415+
3416+
3417+def usage(status=1):
3418+ print usage_string
3419+ Util().usage(compat=True)
3420+
3421+
3422+def version():
3423+ print Util().version()
3424+ sys.exit(status)
3425+
3426+
3427+def main():
3428+ euca = None
3429+ try:
3430+ euca = Euca2ool('P:p:o:u:s:t:', [
3431+ 'protocol=',
3432+ 'port-range=',
3433+ 'source-group=',
3434+ 'source-group-user=',
3435+ 'source-subnet=',
3436+ 'icmp-type-code=',
3437+ ], compat=True)
3438+ except Exception, e:
3439+ print e
3440+ usage()
3441+
3442+ group_name = None
3443+ protocol = 'tcp'
3444+ from_port = None
3445+ to_port = None
3446+ source_group_name = None
3447+ source_group_owner_id = None
3448+ cidr_ip = None
3449+
3450+ for (name, value) in euca.opts:
3451+ if name in ('-P', '--protocol'):
3452+ protocol = value
3453+ elif name in ('-p', '--port-range'):
3454+ ports = value.split('-')
3455+ if len(ports) > 1:
3456+ from_port = int(ports[0])
3457+ to_port = int(ports[1])
3458+ else:
3459+ from_port = to_port = int(ports[0])
3460+ elif name in ('-o', '--source-group'):
3461+ source_group_name = value
3462+ protocol = None
3463+ elif name in ('-u', '--source-group-user'):
3464+ source_group_owner_id = value
3465+ elif name in ('-s', '--source-subnet'):
3466+ cidr_ip = value
3467+ elif name in ('-t', '--icmp-type-code'):
3468+ code_parts = value.split(':')
3469+ if len(code_parts) > 1:
3470+ try:
3471+ from_port = int(code_parts[0])
3472+ to_port = int(code_parts[1])
3473+ except ValueError:
3474+ print 'port must be an integer.'
3475+ sys.exit(1)
3476+ elif name in ('-h', '--help'):
3477+ usage(0)
3478+ elif name == '--version':
3479+ version()
3480+
3481+ if source_group_name:
3482+ from_port = None
3483+ to_port = None
3484+ protocol = None
3485+
3486+ for arg in euca.args:
3487+ group_name = arg
3488+ break
3489+
3490+ if group_name:
3491+ if cidr_ip:
3492+ try:
3493+ euca.validate_address(cidr_ip)
3494+ except AddressValidationError:
3495+ print 'Invalid address', cidr_ip
3496+ sys.exit(1)
3497+ if protocol:
3498+ try:
3499+ euca.validate_protocol(protocol)
3500+ except ProtocolValidationError:
3501+ print 'Invalid protocol', protocol
3502+ sys.exit(1)
3503+
3504+ try:
3505+ euca_conn = euca.make_connection()
3506+ except ConnectionFailed, e:
3507+ print e.message
3508+ sys.exit(1)
3509+ try:
3510+ return_code = euca_conn.revoke_security_group(
3511+ group_name=group_name,
3512+ src_security_group_name=source_group_name,
3513+ src_security_group_owner_id=source_group_owner_id,
3514+ ip_protocol=protocol,
3515+ from_port=from_port,
3516+ to_port=to_port,
3517+ cidr_ip=cidr_ip,
3518+ )
3519+ except Exception, ex:
3520+ euca.display_error_and_exit('%s' % ex)
3521+
3522+ if return_code:
3523+ print 'GROUP\t%s' % group_name
3524+ permission_string = 'PERMISSION\t%s\tALLOWS' % group_name
3525+ if protocol:
3526+ permission_string += '\t%s' % protocol
3527+ if from_port:
3528+ permission_string += '\t%s' % from_port
3529+ if to_port:
3530+ permission_string += '\t%s' % to_port
3531+ if source_group_owner_id:
3532+ permission_string += '\tUSER\t%s' \
3533+ % source_group_owner_id
3534+ if source_group_name:
3535+ permission_string += '\tGRPNAME\t%s' % source_group_name
3536+ if cidr_ip:
3537+ permission_string += '\tFROM\tCIDR\t%s' % cidr_ip
3538+ print permission_string
3539+ else:
3540+
3541+ print 'group_name must be specified'
3542+ usage()
3543+
3544+
3545+if __name__ == '__main__':
3546+ main()
3547+
3548
3549=== added directory '.pc/print-instances-cleanup.patch'
3550=== added file '.pc/print-instances-cleanup.patch/.timestamp'
3551=== added directory '.pc/print-instances-cleanup.patch/bin'
3552=== added file '.pc/print-instances-cleanup.patch/bin/euca-describe-instances'
3553--- .pc/print-instances-cleanup.patch/bin/euca-describe-instances 1970-01-01 00:00:00 +0000
3554+++ .pc/print-instances-cleanup.patch/bin/euca-describe-instances 2010-11-17 22:00:42 +0000
3555@@ -0,0 +1,156 @@
3556+#!/usr/bin/python
3557+# -*- coding: utf-8 -*-
3558+
3559+# Software License Agreement (BSD License)
3560+#
3561+# Copyright (c) 2009, Eucalyptus Systems, Inc.
3562+# All rights reserved.
3563+#
3564+# Redistribution and use of this software in source and binary forms, with or
3565+# without modification, are permitted provided that the following conditions
3566+# are met:
3567+#
3568+# Redistributions of source code must retain the above
3569+# copyright notice, this list of conditions and the
3570+# following disclaimer.
3571+#
3572+# Redistributions in binary form must reproduce the above
3573+# copyright notice, this list of conditions and the
3574+# following disclaimer in the documentation and/or other
3575+# materials provided with the distribution.
3576+#
3577+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3578+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3579+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3580+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
3581+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3582+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3583+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3584+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3585+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3586+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3587+# POSSIBILITY OF SUCH DAMAGE.
3588+#
3589+# Author: Neil Soman neil@eucalyptus.com
3590+
3591+import getopt
3592+import sys
3593+import os
3594+from euca2ools import Euca2ool, InstanceValidationError, Util, \
3595+ ConnectionFailed
3596+
3597+usage_string = \
3598+ """
3599+Shows information about instances.
3600+
3601+euca-describe-instances [-h, --help] [--version] [--debug]
3602+[instance1... instanceN]
3603+
3604+OPTIONAL PARAMETERS
3605+
3606+instance1... instanceN instances to describe.
3607+
3608+"""
3609+
3610+
3611+def usage(status=1):
3612+ print usage_string
3613+ Util().usage()
3614+ sys.exit(status)
3615+
3616+
3617+def version():
3618+ print Util().version()
3619+ sys.exit()
3620+
3621+
3622+def display_reservations(reservations, instance_ids):
3623+ check_instance_ids = False
3624+ if len(instance_ids) > 0:
3625+ check_instance_ids = True
3626+ for reservation in reservations:
3627+ instances = []
3628+ if check_instance_ids:
3629+ for instance in reservation.instances:
3630+ if instance.id in instance_ids:
3631+ instances.append(instance)
3632+ else:
3633+ instances = reservation.instances
3634+ if len(instances) == 0:
3635+ continue
3636+ reservation_string = '%s\t%s' % (reservation.id,
3637+ reservation.owner_id)
3638+ group_delim = '\t'
3639+ for group in reservation.groups:
3640+ reservation_string += '%s%s' % (group_delim, group.id)
3641+ group_delim = ', '
3642+ print 'RESERVATION\t%s' % reservation_string
3643+ for instance in instances:
3644+ if instance:
3645+ instance_string = '%s\t%s\t%s\t%s\t%s' % (instance.id,
3646+ instance.image_id, instance.public_dns_name,
3647+ instance.private_dns_name, instance.state)
3648+ if instance.key_name:
3649+ instance_string += ' \t%s' % instance.key_name
3650+ if instance.ami_launch_index:
3651+ instance_string += ' \t%s' \
3652+ % instance.ami_launch_index
3653+ if instance.product_codes:
3654+ first = True
3655+ for p in instance.product_codes:
3656+ if first:
3657+ instance_string += ' \t%s' % p
3658+ first = False
3659+ else:
3660+ instance_string += ',%s' % p
3661+ if instance.instance_type:
3662+ instance_string += ' \t%s' % instance.instance_type
3663+ if instance.launch_time:
3664+ instance_string += ' \t%s' % instance.launch_time
3665+ if instance.placement:
3666+ instance_string += ' \t%s' % instance.placement
3667+ if instance.kernel:
3668+ instance_string += ' \t%s' % instance.kernel
3669+ if instance.ramdisk:
3670+ instance_string += ' \t%s' % instance.ramdisk
3671+ print 'INSTANCE\t%s' % instance_string
3672+
3673+
3674+def main():
3675+ euca = None
3676+ try:
3677+ euca = Euca2ool()
3678+ except Exception, e:
3679+ print e
3680+ usage()
3681+
3682+ for (name, value) in euca.opts:
3683+ if name in ('-h', '--help'):
3684+ usage(0)
3685+ elif name == '--version':
3686+ version()
3687+
3688+ instance_ids = euca.process_args()
3689+ try:
3690+ for id in instance_ids:
3691+ euca.validate_instance_id(id)
3692+ except InstanceValidationError:
3693+ print 'Invalid instance id'
3694+ sys.exit(1)
3695+
3696+ try:
3697+ euca_conn = euca.make_connection()
3698+ except ConnectionFailed, e:
3699+ print e.message
3700+ sys.exit(1)
3701+ try:
3702+ reservations = euca_conn.get_all_instances(instance_ids)
3703+ except Exception, ex:
3704+ euca.display_error_and_exit('%s' % ex)
3705+
3706+ display_reservations(reservations, instance_ids)
3707+
3708+
3709+if __name__ == '__main__':
3710+ main()
3711+
3712
3713=== added file '.pc/print-instances-cleanup.patch/bin/euca-run-instances'
3714--- .pc/print-instances-cleanup.patch/bin/euca-run-instances 1970-01-01 00:00:00 +0000
3715+++ .pc/print-instances-cleanup.patch/bin/euca-run-instances 2010-11-17 22:00:42 +0000
3716@@ -0,0 +1,260 @@
3717+#!/usr/bin/python
3718+# -*- coding: utf-8 -*-
3719+
3720+# Software License Agreement (BSD License)
3721+#
3722+# Copyright (c) 2009, Eucalyptus Systems, Inc.
3723+# All rights reserved.
3724+#
3725+# Redistribution and use of this software in source and binary forms, with or
3726+# without modification, are permitted provided that the following conditions
3727+# are met:
3728+#
3729+# Redistributions of source code must retain the above
3730+# copyright notice, this list of conditions and the
3731+# following disclaimer.
3732+#
3733+# Redistributions in binary form must reproduce the above
3734+# copyright notice, this list of conditions and the
3735+# following disclaimer in the documentation and/or other
3736+# materials provided with the distribution.
3737+#
3738+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3739+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3740+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3741+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
3742+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3743+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3744+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3745+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3746+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3747+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3748+# POSSIBILITY OF SUCH DAMAGE.
3749+#
3750+# Author: Neil Soman neil@eucalyptus.com
3751+
3752+import getopt
3753+import sys
3754+import os
3755+from euca2ools import Euca2ool, Util, ConnectionFailed
3756+
3757+usage_string = \
3758+ """
3759+Starts instances.
3760+
3761+euca-run-instances [-n, --instance-count count] [-g, --group group_name] [-k, --key keyname]
3762+[-d user_data] [-f user_data_file] [--addressing addressing] [-t, --instance-type instance_type]
3763+[-z, --availability-zone zone] [--kernel kernel_id] [--ramdisk ramdisk_id] [-b block_device_mapping]
3764+[--monitor] [-s, --subnet subnet_id]
3765+[-h, --help] [--version] [--debug] image_id
3766+
3767+REQUIRED PARAMETERS
3768+
3769+image_id identifier for the image to run.
3770+
3771+OPTIONAL PARAMETERS
3772+
3773+-n, --instance-count Number of instances to run.
3774+
3775+-g, --group Security group to run the instance under.
3776+
3777+-k, --key Name of a (previously created) keypair to associate with this reservation.
3778+-d, --user-data User data for instances read from the command line.
3779+
3780+-f, --user-data-file User data for instances as a filename.
3781+
3782+--addressing Addressing mode (e.g., private).
3783+
3784+-t, --instance-type VM Image type to run the instance(s) as (default: m1.small).
3785+
3786+-z, --availability-zone Availability zone to run the instance(s) in.
3787+
3788+--kernel Id of the kernel to be used to launch instance(s).
3789+
3790+--ramdisk Id of the ramdisk to be used to launch instance(s).
3791+
3792+-b, --block-device-mapping Block device mapping for the instance(s). Option may be used multiple times.
3793+
3794+--monitor Enable monitoring for instance.
3795+
3796+-s, --subnet Amazon VPC subnet ID for the instance.
3797+
3798+"""
3799+
3800+
3801+def usage(status=1):
3802+ print usage_string
3803+ Util().usage()
3804+ sys.exit(status)
3805+
3806+
3807+def version():
3808+ print Util().version()
3809+ sys.exit()
3810+
3811+
3812+def display_reservations(reservation):
3813+ reservation_string = '%s\t%s' % (reservation.id,
3814+ reservation.owner_id)
3815+ group_delim = '\t'
3816+ for group in reservation.groups:
3817+ reservation_string += '%s%s' % (group_delim, group.id)
3818+ group_delim = ', '
3819+ print 'RESERVATION\t%s' % reservation_string
3820+ for instance in reservation.instances:
3821+ instance_string = '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s' % (
3822+ instance.id,
3823+ instance.image_id,
3824+ instance.public_dns_name,
3825+ instance.private_dns_name,
3826+ instance.state,
3827+ instance.key_name,
3828+ instance.launch_time,
3829+ instance.kernel,
3830+ instance.ramdisk,
3831+ )
3832+ print 'INSTANCE\t%s' % instance_string
3833+
3834+
3835+def read_user_data(user_data_filename):
3836+ USER_DATA_CHUNK_SIZE = 512
3837+ user_data = ''
3838+ user_data_file = open(user_data_filename, 'r')
3839+ while 1:
3840+ data = user_data_file.read(USER_DATA_CHUNK_SIZE)
3841+ if not data:
3842+ break
3843+ user_data += data
3844+ user_data_file.close()
3845+ return user_data
3846+
3847+
3848+def main():
3849+ euca = None
3850+ try:
3851+ euca = Euca2ool('k:n:t:g:d:f:z:b:', [
3852+ 'key=',
3853+ 'kernel=',
3854+ 'ramdisk=',
3855+ 'instance-count=',
3856+ 'instance-type=',
3857+ 'group=',
3858+ 'user-data=',
3859+ 'user-data-file=',
3860+ 'addressing=',
3861+ 'availability-zone=',
3862+ 'block-device-mapping=',
3863+ 'monitor',
3864+ 'subnet_id=',
3865+ ])
3866+ except Exception, e:
3867+ print e
3868+ usage()
3869+
3870+ image_id = None
3871+ keyname = None
3872+ kernel_id = None
3873+ ramdisk_id = None
3874+ min_count = 1
3875+ max_count = 1
3876+ instance_type = 'm1.small'
3877+ group_names = []
3878+ user_data = None
3879+ user_data_file = None
3880+ addressing_type = None
3881+ zone = None
3882+ block_device_map_args = []
3883+ block_device_map = None
3884+ monitor = False
3885+ subnet_id = None
3886+ for (name, value) in euca.opts:
3887+ if name in ('-k', '--key'):
3888+ keyname = value
3889+ elif name == '--kernel':
3890+ kernel_id = value
3891+ elif name == '--ramdisk':
3892+ ramdisk_id = value
3893+ elif name in ('-n', '--instance-count'):
3894+ counts = value.split('-')
3895+ try:
3896+ if (len(counts) > 1):
3897+ min_count = int(counts[0])
3898+ max_count = int(counts[1])
3899+ else:
3900+ min_count = max_count = int(counts[0])
3901+ except ValueError:
3902+ print "Invalid value for --instance-count: ", value
3903+ sys.exit(1)
3904+ elif name in ('-t', '--instance-type'):
3905+ instance_type = value
3906+ elif name in ('-g', '--group'):
3907+ group_names.append(value)
3908+ elif name in ('-d', '--user-data'):
3909+ user_data = value
3910+ elif name in ('-f', '--user-data-file'):
3911+ user_data_file = value
3912+ elif name == '--addressing':
3913+ addressing_type = value
3914+ elif name in ('-z', '--availability-zone'):
3915+ zone = value
3916+ elif name in ('-b', '--block-device-mapping'):
3917+ block_device_map_args.append(value)
3918+ elif name == '--monitor':
3919+ monitor = True
3920+ elif name in ('-s', '--subnet'):
3921+ subnet_id = value
3922+ elif name in ('-h', '--help'):
3923+ usage(0)
3924+ elif name == '--version':
3925+ version()
3926+
3927+ for arg in euca.args:
3928+ image_id = arg
3929+ break
3930+
3931+ if image_id:
3932+ if not user_data:
3933+ if user_data_file:
3934+ try:
3935+ euca.validate_file(user_data_file)
3936+ except FileValidationError:
3937+ print 'Invalid user data file path'
3938+ sys.exit(1)
3939+ user_data = read_user_data(user_data_file)
3940+ try:
3941+ euca_conn = euca.make_connection()
3942+ except ConnectionFailed, e:
3943+ print e.message
3944+ sys.exit(1)
3945+ if block_device_map_args:
3946+ block_device_map = \
3947+ euca.parse_block_device_args(block_device_map_args)
3948+ try:
3949+ reservation = euca_conn.run_instances(
3950+ image_id=image_id,
3951+ min_count=min_count,
3952+ max_count=max_count,
3953+ key_name=keyname,
3954+ security_groups=group_names,
3955+ user_data=user_data,
3956+ addressing_type=addressing_type,
3957+ instance_type=instance_type,
3958+ placement=zone,
3959+ kernel_id=kernel_id,
3960+ ramdisk_id=ramdisk_id,
3961+ block_device_map=block_device_map,
3962+ monitoring_enabled=monitor,
3963+ subnet_id=subnet_id
3964+ )
3965+ except Exception, ex:
3966+ euca.display_error_and_exit('%s' % ex)
3967+
3968+ display_reservations(reservation)
3969+ else:
3970+ print 'image_id must be specified'
3971+ usage()
3972+
3973+
3974+if __name__ == '__main__':
3975+ main()
3976+
3977
3978=== added directory '.pc/print-instances-cleanup.patch/euca2ools'
3979=== added directory '.pc/print-instances-cleanup.patch/euca2ools/euca2ools'
3980=== added file '.pc/print-instances-cleanup.patch/euca2ools/euca2ools/__init__.py'
3981--- .pc/print-instances-cleanup.patch/euca2ools/euca2ools/__init__.py 1970-01-01 00:00:00 +0000
3982+++ .pc/print-instances-cleanup.patch/euca2ools/euca2ools/__init__.py 2010-11-17 22:00:42 +0000
3983@@ -0,0 +1,1458 @@
3984+#!/usr/bin/python
3985+# -*- coding: utf-8 -*-
3986+# Software License Agreement (BSD License)
3987+#
3988+# Copyright (c) 2009, Eucalyptus Systems, Inc.
3989+# All rights reserved.
3990+#
3991+# Redistribution and use of this software in source and binary forms, with or
3992+# without modification, are permitted provided that the following conditions
3993+# are met:
3994+#
3995+# Redistributions of source code must retain the above
3996+# copyright notice, this list of conditions and the
3997+# following disclaimer.
3998+#
3999+# Redistributions in binary form must reproduce the above
4000+# copyright notice, this list of conditions and the
4001+# following disclaimer in the documentation and/or other
4002+# materials provided with the distribution.
4003+#
4004+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4005+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4006+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4007+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
4008+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4009+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
4010+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
4011+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
4012+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4013+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4014+# POSSIBILITY OF SUCH DAMAGE.
4015+#
4016+# Author: Neil Soman neil@eucalyptus.com
4017+
4018+import boto
4019+import getopt
4020+import sys
4021+import os
4022+import tarfile
4023+from xml.dom.minidom import Document
4024+from xml.dom import minidom
4025+from hashlib import sha1 as sha
4026+from M2Crypto import BN, EVP, RSA, X509
4027+from binascii import hexlify, unhexlify
4028+from subprocess import *
4029+import platform
4030+import urllib
4031+import re
4032+import shutil
4033+from boto.ec2.regioninfo import RegionInfo
4034+from boto.ec2.blockdevicemapping import BlockDeviceMapping
4035+from boto.ec2.blockdevicemapping import EBSBlockDeviceType
4036+from boto.ec2.connection import EC2Connection
4037+from boto.resultset import ResultSet
4038+import logging
4039+import base64
4040+
4041+BUNDLER_NAME = 'euca-tools'
4042+BUNDLER_VERSION = '1.3'
4043+VERSION = '2007-10-10'
4044+RELEASE = '31337'
4045+AES = 'AES-128-CBC'
4046+
4047+IP_PROTOCOLS = ['tcp', 'udp', 'icmp']
4048+
4049+IMAGE_IO_CHUNK = 10 * 1024
4050+IMAGE_SPLIT_CHUNK = IMAGE_IO_CHUNK * 1024
4051+MAX_LOOP_DEVS = 256
4052+
4053+METADATA_URL = 'http://169.254.169.254/latest/meta-data/'
4054+
4055+#
4056+# Monkey patch the SAX endElement handler in boto's
4057+# BlockDeviceMapping class to not break on Eucalyptus's
4058+# DescribeImageAttribute output. It's impossible to test
4059+# this against EC2 because EC2 will not let you run a
4060+# DescribeImageAttribute on the blockDeviceMapping attribute,
4061+# even for an image you own.
4062+#
4063+def endElement(self, name, value, connection):
4064+ if name == 'virtualName':
4065+ self.current_vname = value
4066+ elif name == 'device' or name == 'deviceName':
4067+ if hasattr(self, 'current_vname') and self.current_vname:
4068+ self[self.current_vname] = value
4069+ self.current_vname = None
4070+ else:
4071+ self.current_name = value
4072+
4073+BlockDeviceMapping.endElement = endElement
4074+
4075+#
4076+# Monkey patch the register_image method from EC2Connection
4077+# The one in 1.9b required a value for the "name" parameter
4078+# but in fact that parameter is only required for EBS-backed
4079+# images. So, an EBS image needs a name but not a location
4080+# and the S3 image needs a location but not a name.
4081+#
4082+def register_image(self, name=None, description=None, image_location=None,
4083+ architecture=None, kernel_id=None, ramdisk_id=None,
4084+ root_device_name=None, block_device_map=None):
4085+ """
4086+ Register an image.
4087+
4088+ :type name: string
4089+ :param name: The name of the AMI. Valid only for EBS-based images.
4090+
4091+ :type description: string
4092+ :param description: The description of the AMI.
4093+
4094+ :type image_location: string
4095+ :param image_location: Full path to your AMI manifest in Amazon S3 storage.
4096+ Only used for S3-based AMI's.
4097+
4098+ :type architecture: string
4099+ :param architecture: The architecture of the AMI. Valid choices are:
4100+ i386 | x86_64
4101+
4102+ :type kernel_id: string
4103+ :param kernel_id: The ID of the kernel with which to launch the instances
4104+
4105+ :type root_device_name: string
4106+ :param root_device_name: The root device name (e.g. /dev/sdh)
4107+
4108+ :type block_device_map: :class:`boto.ec2.blockdevicemapping.BlockDeviceMapping`
4109+ :param block_device_map: A BlockDeviceMapping data structure
4110+ describing the EBS volumes associated
4111+ with the Image.
4112+
4113+ :rtype: string
4114+ :return: The new image id
4115+ """
4116+ params = {}
4117+ if name:
4118+ params['Name'] = name
4119+ if description:
4120+ params['Description'] = description
4121+ if architecture:
4122+ params['Architecture'] = architecture
4123+ if kernel_id:
4124+ params['KernelId'] = kernel_id
4125+ if ramdisk_id:
4126+ params['RamdiskId'] = ramdisk_id
4127+ if image_location:
4128+ params['ImageLocation'] = image_location
4129+ if root_device_name:
4130+ params['RootDeviceName'] = root_device_name
4131+ if block_device_map:
4132+ block_device_map.build_list_params(params)
4133+ rs = self.get_object('RegisterImage', params, ResultSet)
4134+ image_id = getattr(rs, 'imageId', None)
4135+ return image_id
4136+
4137+EC2Connection.register_image = register_image
4138+
4139+class LinuxImage:
4140+
4141+ ALLOWED_FS_TYPES = ['ext2', 'ext3', 'xfs', 'jfs', 'reiserfs']
4142+ BANNED_MOUNTS = [
4143+ '/dev',
4144+ '/media',
4145+ '/mnt',
4146+ '/proc',
4147+ '/sys',
4148+ '/cdrom',
4149+ '/tmp',
4150+ ]
4151+ ESSENTIAL_DIRS = ['proc', 'tmp', 'dev', 'mnt', 'sys']
4152+ ESSENTIAL_DEVS = [
4153+ [os.path.join('dev', 'console'), 'c', '5', '1'],
4154+ [os.path.join('dev', 'full'), 'c', '1', '7'],
4155+ [os.path.join('dev', 'null'), 'c', '1', '3'],
4156+ [os.path.join('dev', 'zero'), 'c', '1', '5'],
4157+ [os.path.join('dev', 'tty'), 'c', '5', '0'],
4158+ [os.path.join('dev', 'tty0'), 'c', '4', '0'],
4159+ [os.path.join('dev', 'tty1'), 'c', '4', '1'],
4160+ [os.path.join('dev', 'tty2'), 'c', '4', '2'],
4161+ [os.path.join('dev', 'tty3'), 'c', '4', '3'],
4162+ [os.path.join('dev', 'tty4'), 'c', '4', '4'],
4163+ [os.path.join('dev', 'tty5'), 'c', '4', '5'],
4164+ [os.path.join('dev', 'xvc0'), 'c', '204', '191'],
4165+ ]
4166+ MAKEFS_CMD = 'mkfs.ext3'
4167+ NEW_FSTAB = \
4168+ """
4169+/dev/sda1 / ext3 defaults 1 1
4170+/dev/sdb /mnt ext3 defaults 0 0
4171+none /dev/pts devpts gid=5,mode=620 0 0
4172+none /proc proc defaults 0 0
4173+none /sys sysfs defaults 0 0
4174+ """
4175+
4176+ OLD_FSTAB = \
4177+ """/dev/sda1 / ext3 defaults,errors=remount-ro 0 0
4178+/dev/sda2 /mnt ext3 defaults 0 0
4179+/dev/sda3 swap swap defaults 0 0
4180+proc /proc proc defaults 0 0
4181+devpts /dev/pts devpts gid=5,mode=620 0 0"""
4182+
4183+ def __init__(self, debug=False):
4184+ self.debug = debug
4185+
4186+ def create_image(self, size_in_MB, image_path):
4187+ dd_cmd = ['dd']
4188+ dd_cmd.append('if=/dev/zero')
4189+ dd_cmd.append('of=%s' % image_path)
4190+ dd_cmd.append('count=1')
4191+ dd_cmd.append('bs=1M')
4192+ dd_cmd.append('seek=%s' % (size_in_MB - 1))
4193+ if self.debug:
4194+ print 'Creating disk image...', image_path
4195+ Popen(dd_cmd, PIPE).communicate()[0]
4196+
4197+ def make_fs(self, image_path):
4198+ Util().check_prerequisite_command(self.MAKEFS_CMD)
4199+
4200+ if self.debug:
4201+ print 'Creating filesystem...'
4202+ makefs_cmd = Popen([self.MAKEFS_CMD, '-F', image_path],
4203+ PIPE).communicate()[0]
4204+
4205+ def add_fstab(
4206+ self,
4207+ mount_point,
4208+ generate_fstab,
4209+ fstab_path,
4210+ ):
4211+ if not fstab_path:
4212+ return
4213+ fstab = None
4214+ if fstab_path == 'old':
4215+ if not generate_fstab:
4216+ return
4217+ fstab = self.OLD_FSTAB
4218+ elif fstab_path == 'new':
4219+ if not generate_fstab:
4220+ return
4221+ fstab = self.NEW_FSTAB
4222+
4223+ etc_file_path = os.path.join(mount_point, 'etc')
4224+ fstab_file_path = os.path.join(etc_file_path, 'fstab')
4225+ if not os.path.exists(etc_file_path):
4226+ os.mkdir(etc_file_path)
4227+ else:
4228+ if os.path.exists(fstab_file_path):
4229+ fstab_copy_path = fstab_file_path + '.old'
4230+ shutil.copyfile(fstab_file_path, fstab_copy_path)
4231+
4232+ if self.debug:
4233+ print 'Updating fstab entry'
4234+ fstab_file = open(fstab_file_path, 'w')
4235+ if fstab:
4236+ fstab_file.write(fstab)
4237+ else:
4238+ orig_fstab_file = open(fstab_path, 'r')
4239+ while 1:
4240+ data = orig_fstab_file.read(IMAGE_IO_CHUNK)
4241+ if not data:
4242+ break
4243+ fstab_file.write(data)
4244+ orig_fstab_file.close()
4245+ fstab_file.close()
4246+
4247+ def make_essential_devs(self, image_path):
4248+ for entry in self.ESSENTIAL_DEVS:
4249+ cmd = ['mknod']
4250+ entry[0] = os.path.join(image_path, entry[0])
4251+ cmd.extend(entry)
4252+ Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
4253+
4254+
4255+class SolarisImage:
4256+
4257+ ALLOWED_FS_TYPES = ['ext2', 'ext3', 'xfs', 'jfs', 'reiserfs']
4258+ BANNED_MOUNTS = [
4259+ '/dev',
4260+ '/media',
4261+ '/mnt',
4262+ '/proc',
4263+ '/sys',
4264+ '/cdrom',
4265+ '/tmp',
4266+ ]
4267+ ESSENTIAL_DIRS = ['proc', 'tmp', 'dev', 'mnt', 'sys']
4268+
4269+ def __init__(self, debug=False):
4270+ self.debug = debug
4271+
4272+ def create_image(self, size_in_MB, image_path):
4273+ print 'Sorry. Solaris not supported yet'
4274+ raise UnsupportedException
4275+
4276+ def make_fs(self, image_path):
4277+ print 'Sorry. Solaris not supported yet'
4278+ raise UnsupportedException
4279+
4280+ def make_essential_devs(self, image_path):
4281+ print 'Sorry. Solaris not supported yet'
4282+ raise UnsupportedException
4283+
4284+
4285+class Util:
4286+
4287+ usage_string = \
4288+ """
4289+-a, --access-key User's Access Key ID.
4290+
4291+-s, --secret-key User's Secret Key.
4292+
4293+-U, --url URL of the Cloud to connect to.
4294+
4295+--config Read credentials and cloud settings from the
4296+ specified config file (defaults to $HOME/.eucarc or /etc/euca2ools/eucarc).
4297+
4298+-h, --help Display this help message.
4299+
4300+--version Display the version of this tool.
4301+
4302+--debug Turn on debugging.
4303+
4304+Euca2ools will use the environment variables EC2_URL, EC2_ACCESS_KEY, EC2_SECRET_KEY, EC2_CERT, EC2_PRIVATE_KEY, S3_URL, EUCALYPTUS_CERT by default.
4305+ """
4306+
4307+ version_string = """ Version: 1.2 (BSD)"""
4308+
4309+ def version(self):
4310+ return self.version_string
4311+
4312+ def usage(self, compat=False):
4313+ if compat:
4314+ self.usage_string = self.usage_string.replace('-s,', '-S,')
4315+ self.usage_string = self.usage_string.replace('-a,', '-A,')
4316+ print self.usage_string
4317+
4318+ def check_prerequisite_command(self, command):
4319+ cmd = [command]
4320+ try:
4321+ output = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
4322+ except OSError, e:
4323+ error_string = '%s' % e
4324+ if 'No such' in error_string:
4325+ print 'Command %s not found. Is it installed?' % command
4326+ raise NotFoundError
4327+ else:
4328+ raise OSError(e)
4329+
4330+
4331+class AddressValidationError:
4332+
4333+ def __init__(self):
4334+ self.message = 'Invalid address'
4335+
4336+
4337+class InstanceValidationError:
4338+
4339+ def __init__(self):
4340+ self.message = 'Invalid instance id'
4341+
4342+
4343+class VolumeValidationError:
4344+
4345+ def __init__(self):
4346+ self.message = 'Invalid volume id'
4347+
4348+
4349+class SizeValidationError:
4350+
4351+ def __init__(self):
4352+ self.message = 'Invalid size'
4353+
4354+
4355+class SnapshotValidationError:
4356+
4357+ def __init__(self):
4358+ self.message = 'Invalid snapshot id'
4359+
4360+
4361+class ProtocolValidationError:
4362+
4363+ def __init__(self):
4364+ self.message = 'Invalid protocol'
4365+
4366+
4367+class FileValidationError:
4368+
4369+ def __init__(self):
4370+ self.message = 'Invalid file'
4371+
4372+
4373+class DirValidationError:
4374+
4375+ def __init__(self):
4376+ self.message = 'Invalid directory'
4377+
4378+
4379+class BundleValidationError:
4380+
4381+ def __init__(self):
4382+ self.message = 'Invalid bundle id'
4383+
4384+
4385+class CopyError:
4386+
4387+ def __init__(self):
4388+ self.message = 'Unable to copy'
4389+
4390+
4391+class MetadataReadError:
4392+
4393+ def __init__(self):
4394+ self.message = 'Unable to read metadata'
4395+
4396+
4397+class NullHandler(logging.Handler):
4398+
4399+ def emit(self, record):
4400+ pass
4401+
4402+
4403+class NotFoundError:
4404+
4405+ def __init__(self):
4406+ self.message = 'Unable to find'
4407+
4408+
4409+class UnsupportedException:
4410+
4411+ def __init__(self):
4412+ self.message = 'Not supported'
4413+
4414+
4415+class CommandFailed:
4416+
4417+ def __init__(self):
4418+ self.message = 'Command failed'
4419+
4420+
4421+class ConnectionFailed:
4422+
4423+ def __init__(self):
4424+ self.message = 'Connection failed'
4425+
4426+
4427+class ParseError:
4428+
4429+ def __init__(self, msg):
4430+ self.message = msg
4431+
4432+
4433+class Euca2ool:
4434+
4435+ def process_args(self):
4436+ ids = []
4437+ for arg in self.args:
4438+ ids.append(arg)
4439+ return ids
4440+
4441+ def __init__(
4442+ self,
4443+ short_opts=None,
4444+ long_opts=None,
4445+ is_s3=False,
4446+ compat=False,
4447+ ):
4448+ self.ec2_user_access_key = None
4449+ self.ec2_user_secret_key = None
4450+ self.ec2_url = None
4451+ self.s3_url = None
4452+ self.config_file_path = None
4453+ self.is_s3 = is_s3
4454+ if compat:
4455+ self.secret_key_opt = 'S'
4456+ self.access_key_opt = 'A'
4457+ else:
4458+ self.secret_key_opt = 's'
4459+ self.access_key_opt = 'a'
4460+ if not short_opts:
4461+ short_opts = ''
4462+ if not long_opts:
4463+ long_opts = ['']
4464+ short_opts += 'hU:'
4465+ short_opts += '%s:' % self.secret_key_opt
4466+ short_opts += '%s:' % self.access_key_opt
4467+ long_opts += [
4468+ 'access-key=',
4469+ 'secret-key=',
4470+ 'url=',
4471+ 'help',
4472+ 'version',
4473+ 'debug',
4474+ 'config=',
4475+ ]
4476+ (opts, args) = getopt.gnu_getopt(sys.argv[1:], short_opts,
4477+ long_opts)
4478+ self.opts = opts
4479+ self.args = args
4480+ self.debug = False
4481+ for (name, value) in opts:
4482+ if name in ('-%s' % self.access_key_opt, '--access-key'):
4483+ self.ec2_user_access_key = value
4484+ elif name in ('-%s' % self.secret_key_opt, '--secret-key'):
4485+ try:
4486+ self.ec2_user_secret_key = int(value)
4487+ self.ec2_user_secret_key = None
4488+ except ValueError:
4489+ self.ec2_user_secret_key = value
4490+ elif name in ('-U', '--url'):
4491+ self.ec2_url = value
4492+ elif name == '--debug':
4493+ self.debug = True
4494+ elif name == '--config':
4495+ self.config_file_path = value
4496+ system_string = platform.system()
4497+ if system_string == 'Linux':
4498+ self.img = LinuxImage(self.debug)
4499+ elif system_string == 'SunOS':
4500+ self.img = SolarisImage(self.debug)
4501+ else:
4502+ self.img = 'Unsupported'
4503+ self.setup_environ()
4504+
4505+ h = NullHandler()
4506+ logging.getLogger('boto').addHandler(h)
4507+
4508+ SYSTEM_EUCARC_PATH = os.path.join('/etc', 'euca2ools', 'eucarc')
4509+
4510+ def setup_environ(self):
4511+ envlist = (
4512+ 'EC2_ACCESS_KEY',
4513+ 'EC2_SECRET_KEY',
4514+ 'S3_URL',
4515+ 'EC2_URL',
4516+ 'EC2_CERT',
4517+ 'EC2_PRIVATE_KEY',
4518+ 'EUCALYPTUS_CERT',
4519+ 'EC2_USER_ID',
4520+ )
4521+ self.environ = {}
4522+ user_eucarc = None
4523+ if 'HOME' in os.environ:
4524+ user_eucarc = os.path.join(os.getenv('HOME'), '.eucarc')
4525+ read_config = False
4526+ if self.config_file_path \
4527+ and os.path.exists(self.config_file_path):
4528+ read_config = self.config_file_path
4529+ elif user_eucarc is not None and os.path.exists(user_eucarc):
4530+ read_config = user_eucarc
4531+ elif os.path.exists(self.SYSTEM_EUCARC_PATH):
4532+ read_config = self.SYSTEM_EUCARC_PATH
4533+ if read_config:
4534+ parse_config(read_config, self.environ, envlist)
4535+ else:
4536+ for v in envlist:
4537+ self.environ[v] = os.getenv(v)
4538+
4539+ def get_environ(self, name):
4540+ if self.environ.has_key(name):
4541+ return self.environ[name]
4542+ else:
4543+ print '%s not found' % name
4544+ raise NotFoundError
4545+
4546+ def make_connection(self):
4547+ if not self.ec2_user_access_key:
4548+ self.ec2_user_access_key = self.environ['EC2_ACCESS_KEY']
4549+ if not self.ec2_user_access_key:
4550+ print 'EC2_ACCESS_KEY environment variable must be set.'
4551+ raise ConnectionFailed
4552+
4553+ if not self.ec2_user_secret_key:
4554+ self.ec2_user_secret_key = self.environ['EC2_SECRET_KEY']
4555+ if not self.ec2_user_secret_key:
4556+ print 'EC2_SECRET_KEY environment variable must be set.'
4557+ raise ConnectionFailed
4558+
4559+ if not self.is_s3:
4560+ if not self.ec2_url:
4561+ self.ec2_url = self.environ['EC2_URL']
4562+ if not self.ec2_url:
4563+ self.ec2_url = \
4564+ 'http://localhost:8773/services/Eucalyptus'
4565+ print 'EC2_URL not specified. Trying %s' \
4566+ % self.ec2_url
4567+ else:
4568+ if not self.ec2_url:
4569+ self.ec2_url = self.environ['S3_URL']
4570+ if not self.ec2_url:
4571+ self.ec2_url = \
4572+ 'http://localhost:8773/services/Walrus'
4573+ print 'S3_URL not specified. Trying %s' \
4574+ % self.ec2_url
4575+
4576+ self.port = None
4577+ self.service_path = '/'
4578+ if self.ec2_url.find('https://') >= 0:
4579+ self.ec2_url = self.ec2_url.replace('https://', '')
4580+ self.is_secure = True
4581+ else:
4582+ self.ec2_url = self.ec2_url.replace('http://', '')
4583+ self.is_secure = False
4584+ self.host = self.ec2_url
4585+ url_parts = self.ec2_url.split(':')
4586+ if len(url_parts) > 1:
4587+ self.host = url_parts[0]
4588+ path_parts = url_parts[1].split('/', 1)
4589+ if len(path_parts) > 1:
4590+ self.port = int(path_parts[0])
4591+ self.service_path = self.service_path + path_parts[1]
4592+ else:
4593+ self.port = int(url_parts[1])
4594+
4595+ if not self.is_s3:
4596+ return EC2Connection(
4597+ aws_access_key_id=self.ec2_user_access_key,
4598+ aws_secret_access_key=self.ec2_user_secret_key,
4599+ is_secure=self.is_secure,
4600+ region=RegionInfo(None, 'eucalyptus', self.host),
4601+ port=self.port,
4602+ path=self.service_path,
4603+ )
4604+ else:
4605+ return boto.s3.Connection(
4606+ aws_access_key_id=self.ec2_user_access_key,
4607+ aws_secret_access_key=self.ec2_user_secret_key,
4608+ is_secure=self.is_secure,
4609+ host=self.host,
4610+ port=self.port,
4611+ calling_format=boto.s3.connection.OrdinaryCallingFormat(),
4612+ path=self.service_path,
4613+ )
4614+
4615+ def validate_address(self, address):
4616+ if not re.match("[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(\/[0-9]+)?$",
4617+ address):
4618+ raise AddressValidationError
4619+
4620+ def validate_instance_id(self, id):
4621+ if not re.match('i-', id):
4622+ raise InstanceValidationError
4623+
4624+ def validate_volume_id(self, id):
4625+ if not re.match('vol-', id):
4626+ raise VolumeValidationError
4627+
4628+ def validate_volume_size(self, size):
4629+ if size < 0 or size > 1024:
4630+ raise SizeValidationError
4631+
4632+ def validate_snapshot_id(self, id):
4633+ if not re.match('snap-', id):
4634+ raise SnapshotValidationError
4635+
4636+ def validate_protocol(self, proto):
4637+ if not proto in IP_PROTOCOLS:
4638+ raise ProtocolValidationError
4639+
4640+ def validate_file(self, path):
4641+ if not os.path.exists(path) or not os.path.isfile(path):
4642+ raise FileValidationError
4643+
4644+ def validate_dir(self, path):
4645+ if not os.path.exists(path) or not os.path.isdir(path):
4646+ raise DirValidationError
4647+
4648+ def validate_bundle_id(self, id):
4649+ if not re.match('bun-', id):
4650+ raise BundleValidationError
4651+
4652+ def get_relative_filename(self, filename):
4653+ f_parts = filename.split('/')
4654+ return f_parts[len(f_parts) - 1]
4655+
4656+ def get_file_path(self, filename):
4657+ relative_filename = self.get_relative_filename(filename)
4658+ file_path = os.path.dirname(filename)
4659+ if len(file_path) == 0:
4660+ file_path = '.'
4661+ return file_path
4662+
4663+ def split_file(self, file, chunk_size):
4664+ parts = []
4665+ parts_digest = []
4666+ file_size = os.path.getsize(file)
4667+ in_file = open(file, 'rb')
4668+ number_parts = int(file_size / chunk_size)
4669+ number_parts += 1
4670+ bytes_read = 0
4671+ for i in range(0, number_parts, 1):
4672+ filename = '%s.%d' % (file, i)
4673+ part_digest = sha()
4674+ file_part = open(filename, 'wb')
4675+ print 'Part:', self.get_relative_filename(filename)
4676+ part_bytes_written = 0
4677+ while part_bytes_written < IMAGE_SPLIT_CHUNK:
4678+ data = in_file.read(IMAGE_IO_CHUNK)
4679+ file_part.write(data)
4680+ part_digest.update(data)
4681+ data_len = len(data)
4682+ part_bytes_written += data_len
4683+ bytes_read += data_len
4684+ if bytes_read >= file_size:
4685+ break
4686+ file_part.close()
4687+ parts.append(filename)
4688+ parts_digest.append(hexlify(part_digest.digest()))
4689+
4690+ in_file.close()
4691+ return (parts, parts_digest)
4692+
4693+ def check_image(self, image_file, path):
4694+ print 'Checking image'
4695+ if not os.path.exists(path):
4696+ os.makedirs(path)
4697+ image_size = os.path.getsize(image_file)
4698+ if self.debug:
4699+ print 'Image Size:', image_size, 'bytes'
4700+ in_file = open(image_file, 'rb')
4701+ sha_image = sha()
4702+ while 1:
4703+ buf = in_file.read(IMAGE_IO_CHUNK)
4704+ if not buf:
4705+ break
4706+ sha_image.update(buf)
4707+ return (image_size, hexlify(sha_image.digest()))
4708+
4709+ def tarzip_image(
4710+ self,
4711+ prefix,
4712+ file,
4713+ path,
4714+ ):
4715+ Util().check_prerequisite_command('tar')
4716+
4717+ print 'Tarring image'
4718+ tar_file = '%s.tar.gz' % os.path.join(path, prefix)
4719+ outfile = open(tar_file, 'wb')
4720+ file_path = self.get_file_path(file)
4721+ tar_cmd = ['tar', 'ch', '-S']
4722+ if file_path:
4723+ tar_cmd.append('-C')
4724+ tar_cmd.append(file_path)
4725+ tar_cmd.append(self.get_relative_filename(file))
4726+ else:
4727+ tar_cmd.append(file)
4728+ p1 = Popen(tar_cmd, stdout=PIPE)
4729+ p2 = Popen(['gzip'], stdin=p1.stdout, stdout=outfile)
4730+ p2.communicate()
4731+ outfile.close
4732+ if os.path.getsize(tar_file) <= 0:
4733+ print 'Could not tar image'
4734+ raise CommandFailed
4735+ return tar_file
4736+
4737+ def hexToBytes(self, hexString):
4738+ bytes = []
4739+ hexString = ''.join(hexString.split(' '))
4740+ for i in range(0, len(hexString), 2):
4741+ bytes.append(chr(int(hexString[i:i + 2], 16)))
4742+
4743+ return ''.join(bytes)
4744+
4745+ def crypt_file(
4746+ self,
4747+ cipher,
4748+ in_file,
4749+ out_file,
4750+ ):
4751+ while 1:
4752+ buf = in_file.read(IMAGE_IO_CHUNK)
4753+ if not buf:
4754+ break
4755+ out_file.write(cipher.update(buf))
4756+ out_file.write(cipher.final())
4757+
4758+ def encrypt_image(self, file):
4759+ print 'Encrypting image'
4760+ enc_file = '%s.part' % file.replace('.tar.gz', '')
4761+
4762+ key = hex(BN.rand(16 * 8))[2:34].replace('L', 'c')
4763+ if self.debug:
4764+ print 'Key: %s' % key
4765+ iv = hex(BN.rand(16 * 8))[2:34].replace('L', 'c')
4766+ if self.debug:
4767+ print 'IV: %s' % iv
4768+
4769+ k = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(key),
4770+ iv=unhexlify(iv), op=1)
4771+
4772+ in_file = open(file)
4773+ out_file = open(enc_file, 'wb')
4774+ self.crypt_file(k, in_file, out_file)
4775+ in_file.close()
4776+ out_file.close()
4777+ bundled_size = os.path.getsize(enc_file)
4778+ return (enc_file, key, iv, bundled_size)
4779+
4780+ def split_image(self, file):
4781+ print 'Splitting image...'
4782+ return self.split_file(file, IMAGE_SPLIT_CHUNK)
4783+
4784+ def get_verification_string(self, manifest_string):
4785+ start_mc = manifest_string.find('<machine_configuration>')
4786+ end_mc = manifest_string.find('</machine_configuration>')
4787+ mc_config_string = manifest_string[start_mc:end_mc
4788+ + len('</machine_configuration>')]
4789+ start_image = manifest_string.find('<image>')
4790+ end_image = manifest_string.find('</image>')
4791+ image_string = manifest_string[start_image:end_image
4792+ + len('</image>')]
4793+
4794+ return mc_config_string + image_string
4795+
4796+ def parse_manifest(self, manifest_filename):
4797+ parts = []
4798+ encrypted_key = None
4799+ encrypted_iv = None
4800+ dom = minidom.parse(manifest_filename)
4801+ manifest_elem = dom.getElementsByTagName('manifest')[0]
4802+ parts_list = manifest_elem.getElementsByTagName('filename')
4803+ for part_elem in parts_list:
4804+ nodes = part_elem.childNodes
4805+ for node in nodes:
4806+ if node.nodeType == node.TEXT_NODE:
4807+ parts.append(node.data)
4808+ encrypted_key_elem = \
4809+ manifest_elem.getElementsByTagName('user_encrypted_key')[0]
4810+ nodes = encrypted_key_elem.childNodes
4811+ for node in nodes:
4812+ if node.nodeType == node.TEXT_NODE:
4813+ encrypted_key = node.data
4814+ encrypted_iv_elem = \
4815+ manifest_elem.getElementsByTagName('user_encrypted_iv')[0]
4816+ nodes = encrypted_iv_elem.childNodes
4817+ for node in nodes:
4818+ if node.nodeType == node.TEXT_NODE:
4819+ encrypted_iv = node.data
4820+ return (parts, encrypted_key, encrypted_iv)
4821+
4822+ def assemble_parts(
4823+ self,
4824+ src_directory,
4825+ directory,
4826+ manifest_path,
4827+ parts,
4828+ ):
4829+ manifest_filename = self.get_relative_filename(manifest_path)
4830+ encrypted_filename = os.path.join(directory,
4831+ manifest_filename.replace('.manifest.xml', '.enc.tar.gz'
4832+ ))
4833+ if len(parts) > 0:
4834+ if not os.path.exists(directory):
4835+ os.makedirs(directory)
4836+ encrypted_file = open(encrypted_filename, 'wb')
4837+ for part in parts:
4838+ print 'Part:', self.get_relative_filename(part)
4839+ part_filename = os.path.join(src_directory, part)
4840+ part_file = open(part_filename, 'rb')
4841+ while 1:
4842+ data = part_file.read(IMAGE_IO_CHUNK)
4843+ if not data:
4844+ break
4845+ encrypted_file.write(data)
4846+ part_file.close()
4847+ encrypted_file.close()
4848+ return encrypted_filename
4849+
4850+ def decrypt_image(
4851+ self,
4852+ encrypted_filename,
4853+ encrypted_key,
4854+ encrypted_iv,
4855+ private_key_path,
4856+ ):
4857+ user_priv_key = RSA.load_key(private_key_path)
4858+ key = user_priv_key.private_decrypt(unhexlify(encrypted_key),
4859+ RSA.pkcs1_padding)
4860+ iv = user_priv_key.private_decrypt(unhexlify(encrypted_iv),
4861+ RSA.pkcs1_padding)
4862+ k = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(key),
4863+ iv=unhexlify(iv), op=0)
4864+
4865+ decrypted_filename = encrypted_filename.replace('.enc', '')
4866+ decrypted_file = open(decrypted_filename, 'wb')
4867+ encrypted_file = open(encrypted_filename, 'rb')
4868+ self.crypt_file(k, encrypted_file, decrypted_file)
4869+ encrypted_file.close()
4870+ decrypted_file.close()
4871+ return decrypted_filename
4872+
4873+ def decrypt_string(
4874+ self,
4875+ encrypted_string,
4876+ private_key_path,
4877+ encoded=False,
4878+ ):
4879+ user_priv_key = RSA.load_key(private_key_path)
4880+ string_to_decrypt = encrypted_string
4881+ if encoded:
4882+ string_to_decrypt = base64.b64decode(encrypted_string)
4883+ return user_priv_key.private_decrypt(string_to_decrypt,
4884+ RSA.pkcs1_padding)
4885+
4886+ def untarzip_image(self, path, file):
4887+ untarred_filename = file.replace('.tar.gz', '')
4888+ tar_file = tarfile.open(file, 'r|gz')
4889+ tar_file.extractall(path)
4890+ untarred_names = tar_file.getnames()
4891+ tar_file.close()
4892+ return untarred_names
4893+
4894+ def get_block_devs(self, mapping):
4895+ virtual = []
4896+ devices = []
4897+
4898+ vname = None
4899+ for m in mapping:
4900+ if not vname:
4901+ vname = m
4902+ virtual.append(vname)
4903+ else:
4904+ devices.append(m)
4905+ vname = None
4906+
4907+ return (virtual, devices)
4908+
4909+ def generate_manifest(
4910+ self,
4911+ path,
4912+ prefix,
4913+ parts,
4914+ parts_digest,
4915+ file,
4916+ key,
4917+ iv,
4918+ cert_path,
4919+ ec2cert_path,
4920+ private_key_path,
4921+ target_arch,
4922+ image_size,
4923+ bundled_size,
4924+ image_digest,
4925+ user,
4926+ kernel,
4927+ ramdisk,
4928+ mapping=None,
4929+ product_codes=None,
4930+ ancestor_ami_ids=None,
4931+ ):
4932+ user_pub_key = X509.load_cert(cert_path).get_pubkey().get_rsa()
4933+ cloud_pub_key = \
4934+ X509.load_cert(ec2cert_path).get_pubkey().get_rsa()
4935+
4936+ user_encrypted_key = hexlify(user_pub_key.public_encrypt(key,
4937+ RSA.pkcs1_padding))
4938+ user_encrypted_iv = hexlify(user_pub_key.public_encrypt(iv,
4939+ RSA.pkcs1_padding))
4940+
4941+ cloud_encrypted_key = hexlify(cloud_pub_key.public_encrypt(key,
4942+ RSA.pkcs1_padding))
4943+ cloud_encrypted_iv = hexlify(cloud_pub_key.public_encrypt(iv,
4944+ RSA.pkcs1_padding))
4945+
4946+ user_priv_key = RSA.load_key(private_key_path)
4947+
4948+ manifest_file = '%s.manifest.xml' % os.path.join(path, prefix)
4949+ if self.debug:
4950+ print 'Manifest: ', manifest_file
4951+
4952+ print 'Generating manifest %s' % manifest_file
4953+
4954+ manifest_out_file = open(manifest_file, 'wb')
4955+ doc = Document()
4956+
4957+ manifest_elem = doc.createElement('manifest')
4958+ doc.appendChild(manifest_elem)
4959+
4960+ # version
4961+
4962+ version_elem = doc.createElement('version')
4963+ version_value = doc.createTextNode(VERSION)
4964+ version_elem.appendChild(version_value)
4965+ manifest_elem.appendChild(version_elem)
4966+
4967+ # bundler info
4968+
4969+ bundler_elem = doc.createElement('bundler')
4970+ bundler_name_elem = doc.createElement('name')
4971+ bundler_name_value = doc.createTextNode(BUNDLER_NAME)
4972+ bundler_name_elem.appendChild(bundler_name_value)
4973+ bundler_version_elem = doc.createElement('version')
4974+ bundler_version_value = doc.createTextNode(BUNDLER_VERSION)
4975+ bundler_version_elem.appendChild(bundler_version_value)
4976+ bundler_elem.appendChild(bundler_name_elem)
4977+ bundler_elem.appendChild(bundler_version_elem)
4978+
4979+ # release
4980+
4981+ release_elem = doc.createElement('release')
4982+ release_value = doc.createTextNode(RELEASE)
4983+ release_elem.appendChild(release_value)
4984+ bundler_elem.appendChild(release_elem)
4985+ manifest_elem.appendChild(bundler_elem)
4986+
4987+ # machine config
4988+
4989+ machine_config_elem = doc.createElement('machine_configuration')
4990+ manifest_elem.appendChild(machine_config_elem)
4991+
4992+ target_arch_elem = doc.createElement('architecture')
4993+ target_arch_value = doc.createTextNode(target_arch)
4994+ target_arch_elem.appendChild(target_arch_value)
4995+ machine_config_elem.appendChild(target_arch_elem)
4996+
4997+ # block device mapping
4998+
4999+ if mapping:
5000+ block_dev_mapping_elem = \
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: