[pkg-eucalyptus-commits] [SCM] managing cloud instances for Eucalyptus branch, master, updated. 3.0.0-alpha3-257-g1da8e3a
Garrett Holmstrom
gholms at fedoraproject.org
Sun Jun 16 02:30:02 UTC 2013
The following commit has been merged in the master branch:
commit 39e2192750afedc8a60ffe5d19df10ea94ddb174
Merge: 93fc062a48d20d4958a8be78f86fab05be2c3ccf f766711d6f9b2f0e834ba346ed8488f39ac1d3c4
Author: Garrett Holmstrom <gholms at fedoraproject.org>
Date: Sat Feb 2 21:25:09 2013 -0800
Merge branch 'master' into requestbuilder
Conflicts:
euca2ools/commands/euca/bundleinstance.py
euca2ools/commands/euca/describeimages.py
euca2ools/commands/euca/describesnapshots.py
euca2ools/commands/euca/describevolumes.py
euca2ools/commands/euca/getconsoleoutput.py
euca2ools/commands/euca/rebootinstances.py
euca2ools/commands/euca/register.py
euca2ools/commands/euca/runinstances.py
euca2ools/commands/euca/startinstances.py
euca2ools/commands/euca/stopinstances.py
euca2ools/commands/euca/terminateinstances.py
diff --combined euca2ools/commands/bundle/bundlevol.py
index f6452d0,9da891c..9da891c
--- a/euca2ools/commands/bundle/bundlevol.py
+++ b/euca2ools/commands/bundle/bundlevol.py
@@@ -118,7 -118,7 +118,7 @@@ class BundleVol(euca2ools.commands.euca
if os.geteuid() == 0:
return
else:
- print 'Must be superuser to execute this command.'
+ print >> sys.stderr, 'Must be superuser to execute this command.'
sys.exit()
def parse_excludes(self, excludes_string):
@@@ -137,34 -137,34 +137,34 @@@
try:
ramdisk_id = md.get_instance_ramdisk()
except MetadataReadError:
- print 'Unable to read ramdisk id'
+ print >> sys.stderr, 'Unable to read ramdisk id'
if not kernel_id:
try:
kernel_id = md.get_instance_kernel()
except MetadataReadError:
- print 'Unable to read kernel id'
+ print >> sys.stderr, 'Unable to read kernel id'
if not block_dev_mapping:
try:
block_dev_mapping = \
md.get_instance_block_device_mappings()
except MetadataReadError:
- print 'Unable to read block device mapping'
+ print >> sys.stderr, 'Unable to read block device mapping'
try:
product_codes = md.get_instance_product_codes().split('\n'
)
except MetadataReadError:
- print 'Unable to read product codes'
+ print >> sys.stderr, 'Unable to read product codes'
try:
ancestor_ami_ids = md.get_ancestor_ami_ids().split('\n')
except MetadataReadError:
- print 'Unable to read ancestor ids'
+ print >> sys.stderr, 'Unable to read ancestor ids'
except IOError:
- print 'Unable to read instance metadata. Pass the --no-inherit option if you wish to exclude instance metadata.'
+ print >> sys.stderr, 'Unable to read instance metadata. Pass the --no-inherit option if you wish to exclude instance metadata.'
sys.exit()
return (ramdisk_id, kernel_id, block_dev_mapping, product_codes,
@@@ -244,7 -244,7 +244,7 @@@
try:
fsinfo = bundler.get_fs_info(self.volume_path)
except UnsupportedException, e:
- print e
+ print >> sys.stderr, e
sys.exit(1)
try:
image_path = bundler.make_image(self.size, excludes, self.prefix,
@@@ -270,7 -270,7 +270,7 @@@
bundler.copy_volume(image_path, self.volume_path, excludes,
self.generate_fstab, self.fstab_path)
except CopyError:
- print 'Unable to copy files'
+ print >> sys.stderr, 'Unable to copy files'
self.cleanup(image_path)
sys.exit(1)
except (NotFoundError, CommandFailed, UnsupportedException):
diff --combined euca2ools/commands/bundle/deletebundle.py
index 5f6201b,f54dbe8..f54dbe8
--- a/euca2ools/commands/bundle/deletebundle.py
+++ b/euca2ools/commands/bundle/deletebundle.py
@@@ -77,7 -77,7 +77,7 @@@ class DeleteBundle(euca2ools.commands.e
try:
bucket_instance = s3conn.get_bucket(bucket)
except S3ResponseError, s3error:
- print 'Unable to get bucket %s' % bucket
+ print >> sys.stderr, 'Unable to get bucket %s' % bucket
sys.exit()
return bucket_instance
@@@ -93,7 -93,7 +93,7 @@@
if node.nodeType == node.TEXT_NODE:
parts.append(node.data)
except:
- print 'problem parsing: %s' % manifest_filename
+ print >> sys.stderr, 'problem parsing: %s' % manifest_filename
return parts
def get_manifests(self, bucket):
@@@ -119,8 -119,8 +119,8 @@@
except S3ResponseError, s3error:
s3error_string = '%s' % s3error
if s3error_string.find('200') < 0:
- print s3error_string
- print 'unable to download manifest %s' % manifest
+ print >> sys.stderr, s3error_string
+ print >> sys.stderr, 'unable to download manifest %s' % manifest
if os.path.exists(manifest_filename):
os.remove(manifest_filename)
return False
@@@ -139,8 -139,8 +139,8 @@@
except S3ResponseError, s3error:
s3error_string = '%s' % s3error
if s3error_string.find('200') < 0:
- print s3error_string
- print 'unable to delete part %s' % part
+ print >> sys.stderr, s3error_string
+ print >> sys.stderr, 'unable to delete part %s' % part
sys.exit()
@@@ -153,12 -153,12 +153,12 @@@
except Exception, s3error:
s3error_string = '%s' % s3error
if s3error_string.find('200') < 0:
- print s3error_string
- print 'unable to delete manifest %s' % manifest
+ print >> sys.stderr, s3error_string
+ print >> sys.stderr, 'unable to delete manifest %s' % manifest
try:
bucket = self.ensure_bucket(bucket_name)
except ConnectionFailed, e:
- print e.message
+ print >> sys.stderr, e.message
sys.exit(1)
if clear:
try:
@@@ -166,8 -166,8 +166,8 @@@
except Exception, s3error:
s3error_string = '%s' % s3error
if s3error_string.find('200') < 0:
- print s3error_string
- print 'unable to delete bucket %s' % bucket.name
+ print >> sys.stderr, s3error_string
+ print >> sys.stderr, 'unable to delete bucket %s' % bucket.name
def remove_manifests(self, manifests, directory):
for manifest in manifests:
@@@ -179,9 -179,9 +179,9 @@@
directory = os.path.abspath('/tmp')
if not self.manifest_path and not self.prefix:
- print 'Neither a manifestpath nor a prefix was specified.'
- print 'All bundles in bucket', self.bucket, 'will be deleted.'
- print ('If this is not what you want, press Ctrl+C in the next '
+ print >> sys.stderr, 'Neither a manifestpath nor a prefix was specified.'
+ print >> sys.stderr, 'All bundles in bucket', self.bucket, 'will be deleted.'
+ print >> sys.stderr, ('If this is not what you want, press Ctrl+C in the next '
'10 seconds'),
for __ in range(10):
sys.stdout.write('.')
diff --combined euca2ools/commands/bundle/downloadbundle.py
index 92d87ba,8eea990..8eea990
--- a/euca2ools/commands/bundle/downloadbundle.py
+++ b/euca2ools/commands/bundle/downloadbundle.py
@@@ -63,7 -63,7 +63,7 @@@ class DownloadBundle(euca2ools.commands
try:
bucket_instance = s3conn.get_bucket(bucket)
except S3ResponseError, s3error:
- print 'Unable to get bucket %s' % bucket
+ print >> sys.stderr, 'Unable to get bucket %s' % bucket
sys.exit()
return bucket_instance
diff --combined euca2ools/commands/euca/describeinstances.py
index f75c3ad,f53aebe..6621b4e
--- a/euca2ools/commands/euca/describeinstances.py
+++ b/euca2ools/commands/euca/describeinstances.py
@@@ -1,6 -1,6 +1,6 @@@
# Software License Agreement (BSD License)
#
-# Copyright (c) 2009-2011, Eucalyptus Systems, Inc.
+# Copyright (c) 2009-2013, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
@@@ -27,80 -27,146 +27,81 @@@
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
-#
-# Author: Neil Soman neil at eucalyptus.com
-# Mitch Garnaat mgarnaat at eucalyptus.com
-
-import euca2ools.commands.eucacommand
-from boto.roboto.param import Param
-import euca2ools.utils
-
-class DescribeInstances(euca2ools.commands.eucacommand.EucaCommand):
-
- APIVersion = '2010-08-31'
- Description = 'Shows information about instances.'
- Args = [Param(name='instance', ptype='string',
- cardinality='+', optional=True)]
- Filters = [Param(name='architecture', ptype='string',
- doc="""Instance architecture.
- Valid values are i386 | x86_64 | armhf"""),
- Param(name='availability-zone', ptype='string',
- doc="Instance's Availability Zone"),
- Param(name='block-device-mapping.attach-time',
- ptype='datetime',
- doc="""Attach time for an Amazon EBS volume mapped
- to the instance"""),
- Param(name='block-device-mapping.delete-on-termination',
- ptype='boolean',
- doc="""Whether the Amazon EBS volume is deleted on
- instance termination."""),
- Param(name='block-device-mapping.device-name', ptype='string',
- doc="""Device name (e.g., /dev/sdh) for an Amazon EBS volume
- mapped to the image."""),
- Param(name='block-device-mapping.status', ptype='string',
- doc="""Status for an Amazon EBS volume mapped to the instance.
- Valid Values: attaching | attached | detaching | detached"""),
- Param(name='block-device-mapping.volume-id', ptype='string',
- doc="""ID for an Amazon EBS volume mapped to the instance."""),
- Param(name='client-token', ptype='string',
- doc="""Idempotency token you provided when you launched
- the instance."""),
- Param(name='dns-name', ptype='string',
- doc='Public DNS name of the instance.'),
- Param(name='group-id', ptype='string',
- doc='A security group the instance is in.'),
- Param(name='hypervisor', ptype='string',
- doc="""Hypervisor type of the instance.
- Valid values are ovm | xen."""),
- Param(name='image-id', ptype='string',
- doc='ID of the imageID used to launch the instance'),
- Param(name='instance-id', ptype='string',
- doc='ID of the instance'),
- Param(name='instance-lifecycle', ptype='string',
- doc='Whether this is a Spot Instance.'),
- Param(name='instance-state-code', ptype='integer',
- doc='Code identifying the state of the instance'),
- Param(name='instance-state-name', ptype='string',
- doc='State of the instance.'),
- Param(name='instance-type', ptype='string',
- doc="""Type of the instance."""),
- Param(name='ip-address', ptype='string',
- doc='Public IP address of the instance.'),
- Param(name='kernel-id', ptype='string',
- doc='Kernel ID.'),
- Param(name='key-name', ptype='string',
- doc="""Name of the key pair used when the
- instance was launched."""),
- Param(name='launch-index', ptype='string',
- doc="""When launching multiple instances at once,
- this is the index for the instance in the launch group"""),
- Param(name='launch-time', ptype='string',
- doc='Time instance was launched'),
- Param(name='monitoring-state', ptype='string',
- doc='Whether monitoring is enabled for the instance.'),
- Param(name='owner-id', ptype='string',
- doc='AWS account ID of the image owner.'),
- Param(name='placement-group-name', ptype='string',
- doc='Name of the placement group the instance is in'),
- Param(name='platform', ptype='string',
- doc="""Use windows if you have Windows based AMIs;
- otherwise leave blank."""),
- Param(name='private-dns-name', ptype='string',
- doc='Private DNS name of the instance.'),
- Param(name='private-ip-address', ptype='string',
- doc='Private ip address of the instance.'),
- Param(name='product-code', ptype='string',
- doc='Product code associated with the AMI.'),
- Param(name='ramdisk-id', ptype='string',
- doc='The ramdisk ID.'),
- Param(name='reason', ptype='string',
- doc="""Reason for the instance's current state."""),
- Param(name='requestor-id', ptype='string',
- doc="""ID of the entity that launched the instance
- on your behalf."""),
- Param(name='reservation-id', ptype='string',
- doc="""ID of the instance's reservation."""),
- Param(name='root-device-name', ptype='string',
- doc='Root device name of the AMI (e.g., /dev/sda1).'),
- Param(name='root-device-type', ptype='string',
- doc="""Root device type the AMI uses.
- Valid Values: ebs | instance-store."""),
- Param(name='spot-instance-request-id', ptype='string',
- doc='ID of the Spot Instance request.'),
- Param(name='state-reason-code', ptype='string',
- doc='Reason code for the state change.'),
- Param(name='state-reason-message', ptype='string',
- doc='Message for the state change.'),
- Param(name='subnet-id', ptype='string',
- doc='ID of the subnet the instance is in (VPC).'),
- Param(name='tag-key', ptype='string',
- doc='Key of a tag assigned to the resource.'),
- Param(name='tag-value', ptype='string',
- doc='Value of a tag assigned to the resource.'),
- Param(name='tag:key', ptype='string',
- doc="""Filters the results based on a specific
- tag/value combination."""),
- Param(name='virtualization-type', ptype='string',
- doc="""Virtualization type of the instance.
- Valid values: paravirtual | hvm"""),
- Param(name='vpc-id', ptype='string',
- doc='ID of the VPC the instance is in.')]
-
- def display_reservations(self, reservations):
- for reservation in reservations:
- instances = []
- instances = reservation.instances
- if len(instances) == 0:
- continue
- reservation_string = '%s\t%s' % (reservation.id,
- reservation.owner_id)
- group_delim = '\t'
- for group in reservation.groups:
- reservation_string += '%s%s' % (group_delim, group.id)
- group_delim = ', '
- print 'RESERVATION\t%s' % reservation_string
- euca2ools.utils.print_instances(instances)
- def main(self):
- conn = self.make_connection_cli()
- return self.make_request_cli(conn, 'get_all_instances',
- instance_ids=self.instance)
+from requestbuilder import Arg, Filter, GenericTagFilter
+from . import EucalyptusRequest
- def main_cli(self):
- reservations = self.main()
- self.display_reservations(reservations)
+class DescribeInstances(EucalyptusRequest):
+ API_VERSION = '2010-08-31'
+ DESCRIPTION = 'Show information about instances'
+ ARGS = [Arg('InstanceId', metavar='INSTANCE', nargs='*',
+ help='Limit results to one or more instances')]
- FILTERS = [Filter('architecture', help='CPU architecture'),
++ FILTERS = [Filter('architecture', choices=('i386', 'x86_64', 'armhf'),
++ help='CPU architecture'),
+ Filter('availability-zone'),
+ Filter('block-device-mapping.attach-time',
+ help='volume attachment time'),
+ Filter('block-device-mapping.delete-on-termination', type=bool,
+ help='''whether a volume is deleted upon instance
+ termination'''),
+ Filter('block-device-mapping.device-name',
+ help='volume device name (e.g. /dev/sdf)'),
+ Filter('block-device-mapping.status', help='volume status'),
+ Filter('block-device-mapping.volume-id', help='volume ID'),
+ Filter('client-token',
+ help='idempotency token provided at instance run time'),
+ Filter('dns-name', help='public DNS name'),
+ Filter('group-id', help='security group membership'),
+ Filter('hypervisor', help='hypervisor type'),
+ Filter('image-id', help='machine image ID'),
+ Filter('instance-id'),
+ Filter('instance-lifecycle', choices=['spot'],
+ help='whether this is a spot instance'),
+ Filter('instance-state-code', type=int,
+ help='numeric code identifying instance state'),
+ Filter('instance-state-name', help='instance state'),
+ Filter('instance-type',),
+ Filter('ip-address', help='public IP address'),
+ Filter('kernel-id', help='kernel image ID'),
+ Filter('key-name',
+ help='key pair name provided at instance launch time'),
+ Filter('launch-index', help='launch index within a reservation'),
+ Filter('launch-time', help='instance launch time'),
+ Filter('monitoring-state', help='whether monitoring is enabled'),
+ Filter('owner-id', help='instance owner\'s account ID'),
+ Filter('placement-group-name'),
+ Filter('platform', choices=['windows'],
+ help='whether this is a Windows instance'),
+ Filter('private-dns-name'),
+ Filter('private-ip-address'),
+ Filter('product-code'),
+ Filter('ramdisk-id', help='ramdisk image ID'),
+ Filter('reason', help='reason for the more recent state change'),
+ Filter('requestor-id',
+ help='ID of the entity that launched an instance'),
+ Filter('reservation-id'),
+ Filter('root-device-name',
+ help='root device name (e.g. /dev/sda1)'),
+ Filter('root-device-type', choices=['ebs', 'instance-store'],
+ help='root device type (ebs or instance-store)'),
+ Filter('spot-instance-request-id'),
+ Filter('state-reason-code',
+ help='reason code for the most recent state change'),
+ Filter('state-reason-message',
+ help='message for the most recent state change'),
+ Filter('subnet-id',
+ help='ID of the VPC subnet the instance is in'),
+ Filter('tag-key',
+ help='name of any tag assigned to the instance'),
+ Filter('tag-value',
+ help='value of any tag assigned to the instance'),
+ GenericTagFilter('tag:KEY',
+ help='specific tag key/value combination'),
+ Filter('virtualization-type', choices=['paravirtual', 'hvm']),
+ Filter('vpc-id', help='ID of the VPC the instance is in')]
+ LIST_MARKERS = ['reservationSet', 'instancesSet', 'groupSet', 'tagSet',
+ 'blockDeviceMapping', 'productCodes']
+ def print_result(self, result):
+ for reservation in result.get('reservationSet'):
+ self.print_reservation(reservation)
diff --combined euca2ools/commands/euca/getconsoleoutput.py
index 415e16d,a5f235b..541be6b
--- a/euca2ools/commands/euca/getconsoleoutput.py
+++ b/euca2ools/commands/euca/getconsoleoutput.py
@@@ -1,6 -1,6 +1,6 @@@
# Software License Agreement (BSD License)
#
-# Copyright (c) 2009-2011, Eucalyptus Systems, Inc.
+# Copyright (c) 2009-2013, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
@@@ -27,17 -27,43 +27,38 @@@
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
-#
-# Author: Neil Soman neil at eucalyptus.com
-# Mitch Garnaat mgarnaat at eucalyptus.com
-import euca2ools.commands.eucacommand
-from boto.roboto.param import Param
+import base64
+from requestbuilder import Arg
+from . import EucalyptusRequest
-class GetConsoleOutput(euca2ools.commands.eucacommand.EucaCommand):
++CHAR_ESCAPES = {
++ u'\x00': u'^@', u'\x0c': u'^L', u'\x17': u'^W',
++ u'\x01': u'^A', u'\x0e': u'^N', u'\x18': u'^X',
++ u'\x02': u'^B', u'\x0f': u'^O', u'\x19': u'^Y',
++ u'\x03': u'^C', u'\x10': u'^P', u'\x1a': u'^Z',
++ u'\x04': u'^D', u'\x11': u'^Q', u'\x1b': u'^[',
++ u'\x05': u'^E', u'\x12': u'^R', u'\x1c': u'^\\',
++ u'\x06': u'^F', u'\x13': u'^S', u'\x1d': u'^]',
++ u'\x07': u'^G', u'\x14': u'^T', u'\x1e': u'^^',
++ u'\x08': u'^H', u'\x15': u'^U', u'\x1f': u'^_',
++ u'\x0b': u'^K', u'\x16': u'^V', u'\x7f': u'^?',
++}
+
- Description = 'Prints console output from a running instance.'
- Args = [Param(name='instance_id', ptype='string', optional=False,
- doc="""unique identifier for instance
- to show the console output for.""")]
- Options = [Param(name='raw', long_name='raw', ptype='boolean',
- default=False, optional=True,
- doc='''Display raw output without escaping control
- characters''')]
+class GetConsoleOutput(EucalyptusRequest):
+ DESCRIPTION = 'Retrieve console output for the specified instance'
+ ARGS = [Arg('InstanceId', metavar='INSTANCE',
- help='instance to obtain console output from')]
++ help='instance to obtain console output from'),
++ Arg('--raw', action='store_true', route_to=None,
++ help='Display raw output without escaping control characters')]
- def display_console_output(self, console_output):
- print console_output.instance_id
- print console_output.timestamp
- output = console_output.output
- if not self.raw:
+ def print_result(self, result):
+ print result.get('instanceId', '')
+ print result.get('timestamp', '')
- print base64.b64decode(result.get('output', ''))
++ output = base64.b64decode(result.get('output', ''))
++ output = output.decode()
++ if not self.args['raw']:
+ # Escape control characters
- esc_ords = (list(range(0x00, 0x09)) + list(range(0x0e, 0x1f)) +
- [0x0b, 0x0c, 0x7f])
- for esc_ord in esc_ords:
- # Small assumption: we aren't translating ' or "
- output = output.replace(chr(esc_ord),
- repr(chr(esc_ord)).strip('\'"'))
++ for char, escape in CHAR_ESCAPES.iteritems():
++ output = output.replace(char, escape)
+ print output
-
- def main(self):
- conn = self.make_connection_cli()
- return self.make_request_cli(conn, 'get_console_output',
- instance_id=self.instance_id)
-
- def main_cli(self):
- co = self.main()
- self.display_console_output(co)
diff --combined euca2ools/commands/euca/rebootinstances.py
index 5a8c134,f80de2c..56e1b46
--- a/euca2ools/commands/euca/rebootinstances.py
+++ b/euca2ools/commands/euca/rebootinstances.py
@@@ -1,6 -1,6 +1,6 @@@
# Software License Agreement (BSD License)
#
-# Copyright (c) 2009-2011, Eucalyptus Systems, Inc.
+# Copyright (c) 2009-2013, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
@@@ -27,14 -27,26 +27,11 @@@
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
-#
-# Author: Neil Soman neil at eucalyptus.com
-# Mitch Garnaat mgarnaat at eucalyptus.com
-
-import euca2ools.commands.eucacommand
-from boto.roboto.param import Param
-
-class RebootInstances(euca2ools.commands.eucacommand.EucaCommand):
-
- Description = 'Reboots specified instances.'
- Args = [Param(name='instance_id', ptype='string',
- optional=False, cardinality='+',
- doc='unique identifier for instance to reboot')]
- def main(self):
- conn = self.make_connection_cli()
- return self.make_request_cli(conn, 'reboot_instances',
- instance_ids=self.instance_id)
+from requestbuilder import Arg
+from . import EucalyptusRequest
- def main_cli(self):
- status = self.main()
- if not status:
- self.error_exit()
+class RebootInstances(EucalyptusRequest):
+ DESCRIPTION = 'Reboot one or more instances'
+ ARGS = [Arg('InstanceId', metavar='INSTANCE', nargs='+',
+ help='instance(s) to reboot')]
-
- def print_result(self, result):
- pass
diff --combined euca2ools/commands/euca/registerimage.py
index fecba87,0000000..8efe1ea
mode 100644,000000..100644
--- a/euca2ools/commands/euca/registerimage.py
+++ b/euca2ools/commands/euca/registerimage.py
@@@ -1,101 -1,0 +1,101 @@@
+# Software License Agreement (BSD License)
+#
+# Copyright (c) 2009-2013, Eucalyptus Systems, Inc.
+# All rights reserved.
+#
+# Redistribution and use of this software in source and binary forms, with or
+# without modification, are permitted provided that the following conditions
+# are met:
+#
+# Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the
+# following disclaimer.
+#
+# Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the
+# following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from requestbuilder import Arg
+from . import EucalyptusRequest
+from .argtypes import block_device_mapping
+
+class RegisterImage(EucalyptusRequest):
+ DESCRIPTION = 'Register a new image'
+ ARGS = [Arg('ImageLocation', metavar='MANIFEST', nargs='?',
+ help='''location of the image manifest in S3 storage
+ (required for instance-store images)'''),
+ Arg('-n', '--name', dest='Name', required=True,
+ help='name of the new image (required)'),
+ Arg('-d', '--description', dest='Description',
+ help='description of the new image'),
+ Arg('-a', '--architecture', dest='Architecture',
- choices=('i386', 'x86_64'),
++ choices=('i386', 'x86_64', 'armhf'),
+ help='CPU architecture of the new image'),
+ Arg('--kernel', dest='KernelId', metavar='KERNEL',
+ help='kernel to associate with the new image'),
+ Arg('--ramdisk', dest='RamdiskId', metavar='RAMDISK',
+ help='ramdisk to associate with the new image'),
+ Arg('--root-device-name', dest='RootDeviceName', metavar='DEVICE',
+ help='root device name (default: /dev/sda1)'),
+ # ^ default is added by main()
+ Arg('--snapshot', route_to=None,
+ help='snapshot to use for the root device'),
+ Arg('-b', '--block-device-mapping', metavar='DEVICE=MAPPED',
+ dest='BlockDeviceMapping', action='append',
+ type=block_device_mapping, default=[],
+ help='''define a block device mapping for the image, in the
+ form DEVICE=MAPPED, where "MAPPED" is "none", "ephemeral(0-3)",
+ or "[SNAP-ID]:[SIZE]:[true|false]"''')]
+
+ def preprocess(self):
+ if self.args.get('ImageLocation'):
+ # instance-store image
+ if self.args.get('RootDeviceName'):
+ self._cli_parser.error('argument --root-device-name: not '
+ 'allowed with argument MANIFEST')
+ if self.args.get('snapshot'):
+ self._cli_parser.error('argument --snapshot: not allowed '
+ 'with argument MANIFEST')
+ else:
+ # Try for an EBS image
+ if not self.args.get('RootDeviceName'):
+ self.args['RootDeviceName'] = '/dev/sda1'
+ snapshot = self.args.get('snapshot')
+ # Look for a mapping for the root device
+ for mapping in self.args['BlockDeviceMapping']:
+ if mapping.get('DeviceName') == self.args['RootDeviceName']:
+ if (snapshot and
+ snapshot != mapping.get('Ebs', {}).get('SnapshotId')):
+ # The mapping's snapshot differs or doesn't exist
+ self._cli_parser.error('snapshot ID supplied with '
+ '--snapshot conflicts with block device '
+ 'mapping for root device ' +
+ mapping['DeviceName'])
+ else:
+ # No need to apply --snapshot since the mapping is
+ # already there
+ break
+ else:
+ if snapshot:
+ self.args['BlockDeviceMapping'].append(
+ {'DeviceName': self.args['RootDeviceName'],
+ 'Ebs': {'SnapshotId': snapshot}})
+ else:
+ self._cli_parser.error('either a manifest location or a '
+ 'root device snapshot mapping must be specified')
+
+ def print_result(self, result):
+ print self.tabify(('IMAGE', result.get('imageId')))
diff --combined euca2ools/commands/euca/runinstances.py
index a92c4f0,e3f3629..2ef1f59
--- a/euca2ools/commands/euca/runinstances.py
+++ b/euca2ools/commands/euca/runinstances.py
@@@ -1,6 -1,6 +1,6 @@@
# Software License Agreement (BSD License)
#
-# Copyright (c) 20092011, Eucalyptus Systems, Inc.
+# Copyright (c) 2009-2013, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
@@@ -27,102 -27,134 +27,108 @@@
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
-#
-# Author: Neil Soman neil at eucalyptus.com
-# Mitch Garnaat mgarnaat at eucalyptus.com
-import euca2ools.commands.eucacommand
-from boto.roboto.param import Param
-import euca2ools.utils
+import argparse
+import base64
import os.path
+from requestbuilder import Arg, MutuallyExclusiveArgList
+import sys
+from . import EucalyptusRequest
+from .argtypes import b64encoded_file_contents, block_device_mapping
-class RunInstances(euca2ools.commands.eucacommand.EucaCommand):
-
- Description = 'Starts instances.'
- Options = [Param(name='count', short_name='n', long_name='instance-count',
- optional=True, ptype='string', default='1',
- doc='Number of instances to run.'),
- Param(name='group_name', short_name='g', long_name='group',
- optional=True, ptype='string', cardinality='*',
- doc='Security group to run the instance in.'),
- Param(name='keyname', short_name='k', long_name='key',
- optional=True, ptype='string',
- doc='Name of a keypair.'),
- Param(name='user_data', short_name='d', long_name='user-data',
- optional=True, doc='User data to pass to the instance.'),
- Param(name='user_data_force', long_name='user-data-force',
- optional=True,
- doc='Just like --user-data, but ignore any checks.'),
- Param(name='user_data_file',
- short_name='f', long_name='user-data-file',
- optional=True, ptype='file',
- doc='File containing user data to pass to the instance.'),
- Param(name='addressing', long_name='addressing',
- optional=True, ptype='string',
- doc=('[Eucalyptus extension] Address assignment method. '
- 'Use "private" to run an instance with no public '
- 'address.')),
- Param(name='instance_type',
- short_name='t', long_name='instance-type',
- optional=True, ptype='string', default='m1.small',
- doc='VM Image type to run the instance as.'),
- Param(name='kernel', long_name='kernel',
- optional=True, ptype='string',
- doc='ID of the kernel to be used.'),
- Param(name='ramdisk', long_name='ramdisk',
- optional=True, ptype='string',
- doc='ID of the ramdisk to be used.'),
- Param(name='block_device_mapping',
- short_name='b', long_name='block-device-mapping',
- optional=True, ptype='string', cardinality='*',
- doc="""Block device mapping for the instance(s).
- Option may be used multiple times"""),
- Param(name='monitor', long_name='monitor',
- optional=True, ptype='boolean', default=False,
- doc='Enable monitoring for the instance.'),
- Param(name='subnet', short_name='s', long_name='subnet',
- optional=True, ptype='string',
- doc='Amazon VPC subnet ID for the instance.'),
- Param(name='zone', short_name='z', long_name='availability-zone',
- optional=True, ptype='string',
- doc='availability zone to run the instance in'),
- Param(name='instance_initiated_shutdown_behavior',
- long_name='instance-initiated-shutdown-behavior',
- optional=True, ptype='string',
- doc='Whether to "stop" (default) or "terminate" instance when it is shut down')]
- Args = [Param(name='image_id', ptype='string',
- optional=False,
- doc='ID of the image to run.')]
+class RunInstances(EucalyptusRequest):
+ DESCRIPTION = 'Launch instances of a machine image'
+ ARGS = [Arg('ImageId', metavar='IMAGE', help='image to instantiate'),
+ Arg('-n', '--instance-count', dest='count', metavar='MIN[-MAX]',
+ default='1', route_to=None,
+ help='''number of instances to launch. If this number of
+ instances cannot be launched, no instances will launch.
+ If specified as a range (min-max), the server will
+ attempt to launch the maximum number, but no fewer
+ than the minimum number.'''),
+ Arg('-g', '--group', action='append', default=[], route_to=None,
+ help='security group(s) in which to launch the instances'),
+ Arg('-k', '--key', dest='KeyName', metavar='KEYPAIR',
+ help='name of the key pair to use'),
+ MutuallyExclusiveArgList(
+ Arg('-d', '--user-data', dest='UserData', metavar='DATA',
+ type=base64.b64encode,
+ help='''user data to make available to instances in this
+ reservation'''),
+ Arg('--user-data-force', dest='UserData',
+ type=base64.b64encode, help=argparse.SUPPRESS),
+ # ^ deprecated ## TODO: decide if that should remain the case
+ Arg('-f', '--user-data-file', dest='UserData',
+ metavar='DATA-FILE', type=b64encoded_file_contents,
+ help='''file containing user data to make available to the
+ instances in this reservation''')),
+ Arg('--addressing', dest='AddressingType',
+ choices=('public', 'private'),
- help='addressing scheme to launch the instance with'),
++ help=('addressing scheme to launch the instance with. Use '
++ '"private" to run an instance with no public address.')),
+ Arg('-t', '--instance-type', dest='InstanceType',
+ help='type of instance to launch'),
+ Arg('--kernel', dest='KernelId', metavar='KERNEL',
+ help='kernel to launch the instance(s) with'),
+ Arg('--ramdisk', dest='RamdiskId', metavar='RAMDISK',
+ help='ramdisk to launch the instance(s) with'),
+ Arg('-b', '--block-device-mapping', metavar='DEVICE=MAPPED',
+ dest='BlockDeviceMapping', action='append',
+ type=block_device_mapping, default=[],
+ help='''define a block device mapping for the instances, in the
+ form DEVICE=MAPPED, where "MAPPED" is "none",
+ "ephemeral(0-3)", or
+ "[SNAP-ID]:[SIZE]:[true|false]"'''),
+ Arg('-m', '--monitor', dest='Monitoring.Enabled',
+ action='store_const', const='true',
+ help='enable detailed monitoring for the instance(s)'),
+ Arg('--subnet', dest='SubnetId', metavar='SUBNET',
+ help='VPC subnet in which to launch the instance(s)'),
+ Arg('-z', '--availability-zone', metavar='ZONE',
- dest='Placement.AvailabilityZone')]
++ dest='Placement.AvailabilityZone'),
++ Arg('--instance-initiated-shutdown-behavior',
++ dest='InstanceInitiatedShutdownBehavior',
++ choices=('stop', 'terminate'),
++ help=('whether to "stop" (default) or terminate EBS instances '
++ 'when they shut down'))]
+ LIST_MARKERS = ['reservationSet', 'instancesSet', 'groupSet', 'tagSet',
+ 'blockDeviceMapping', 'productCodes']
- def display_reservations(self, reservation):
- reservation_string = '%s\t%s' % (reservation.id,
- reservation.owner_id)
- group_delim = '\t'
- for group in reservation.groups:
- reservation_string += '%s%s' % (group_delim, group.id)
- group_delim = ', '
- print 'RESERVATION\t%s' % reservation_string
- euca2ools.utils.print_instances(reservation.instances)
+ def preprocess(self):
+ counts = self.args['count'].split('-')
+ if len(counts) == 1:
+ try:
+ self.params['MinCount'] = int(counts[0])
+ self.params['MaxCount'] = int(counts[0])
+ except ValueError:
+ self._cli_parser.error('argument -n/--instance-count: '
+ 'instance count must be an integer')
+ elif len(counts) == 2:
+ try:
+ self.params['MinCount'] = int(counts[0])
+ self.params['MaxCount'] = int(counts[1])
+ except ValueError:
+ self._cli_parser.error('argument -n/--instance-count: '
+ 'instance count range must be must be comprised of '
+ 'integers')
+ else:
+ self._cli_parser.error('argument -n/--instance-count: value must '
+ 'have format "1" or "1-2"')
+ if self.params['MinCount'] < 1 or self.params['MaxCount'] < 1:
+ self._cli_parser.error('argument -n/--instance-count: instance '
+ 'count must be positive')
+ if self.params['MinCount'] > self.params['MaxCount']:
+ self.log.debug('MinCount > MaxCount; swapping')
+ self.params.update({'MinCount': self.params['MaxCount'],
+ 'MaxCount': self.params['MinCount']})
- def read_user_data(self, user_data_filename):
- fp = open(user_data_filename)
- user_data = fp.read()
- fp.close()
- return user_data
-
- def main(self):
- t = self.count.split('-')
- try:
- if len(t) > 1:
- min_count = int(t[0])
- max_count = int(t[1])
+ for group in self.args['group']:
+ if group.startswith('sg-'):
+ self.params.setdefault('SecurityGroupId', [])
+ self.params['SecurityGroupId'].append(group)
else:
- min_count = max_count = int(t[0])
- except ValueError:
- msg = 'Invalid value for --instance-count: %s' % count
- self.display_error_and_exit(msg)
-
- if self.user_data and os.path.isfile(self.user_data):
- msg = ('string provided as user-data [%s] is a file.\nTry %s or %s'
- % (self.user_data, '--user-data-file', '--user-data-force'))
- self.display_error_and_exit(msg)
-
- if self.user_data_force:
- self.user_data = self.user_data_force
-
- if not self.user_data:
- if self.user_data_file:
- self.user_data = self.read_user_data(self.user_data_file)
-
- if self.block_device_mapping:
- self.block_device_mapping = self.parse_block_device_args(self.block_device_mapping)
- conn = self.make_connection_cli()
- return self.make_request_cli(conn, 'run_instances',
- image_id=self.image_id,
- min_count=min_count,
- max_count=max_count,
- key_name=self.keyname,
- security_groups=self.group_name,
- user_data=self.user_data,
- addressing_type=self.addressing,
- instance_type=self.instance_type,
- placement=self.zone,
- kernel_id=self.kernel,
- ramdisk_id=self.ramdisk,
- block_device_map=self.block_device_mapping,
- monitoring_enabled=self.monitor,
- subnet_id=self.subnet,
- instance_initiated_shutdown_behavior=self.instance_initiated_shutdown_behavior)
-
- def main_cli(self):
- reservation = self.main()
- self.display_reservations(reservation)
+ self.params.setdefault('SecurityGroup', [])
+ self.params['SecurityGroup'].append(group)
+ def print_result(self, result):
+ self.print_reservation(result)
diff --combined euca2ools/commands/eustore/installimage.py
index d2f8e42,de877aa..373fd31
--- a/euca2ools/commands/eustore/installimage.py
+++ b/euca2ools/commands/eustore/installimage.py
@@@ -38,6 -38,7 +38,7 @@@ import tarfil
import hashlib
import re
import zlib
+ import shutil
import tempfile
import urllib2
import boto
@@@ -48,8 -49,8 +49,8 @@@ from boto.s3.connection import Locatio
import euca2ools.bundler
import euca2ools.commands.eustore
import euca2ools.utils
-from euca2ools.commands.euca.bundleimage import BundleImage
-from euca2ools.commands.euca.uploadbundle import UploadBundle
+from euca2ools.commands.bundle.bundleimage import BundleImage
+from euca2ools.commands.bundle.uploadbundle import UploadBundle
from euca2ools.commands.euca.register import Register
from euca2ools.exceptions import NotFoundError, CommandFailed
@@@ -184,15 -185,15 +185,15 @@@ class InstallImage(AWSQueryRequest)
if name_match:
if kernel_id=='true' and img.type=='kernel':
if self.promptReplace("Kernel", img.name):
- ret_id=img.name
+ ret_id=img.id
break
elif ramdisk_id=='true' and img.type=='ramdisk':
if self.promptReplace("Ramdisk", img.name):
- ret_id=img.name
+ ret_id=img.id
break
elif kernel_id!='true' and ramdisk_id!='true' and img.type=='machine':
if self.promptReplace("Image", img.name):
- ret_id=img.name
+ ret_id=img.id
break
if ret_id:
@@@ -247,10 -248,10 +248,10 @@@
try:
names = bundler.untarzip_image(self.destination, file)
except OSError:
- print "Error: cannot unbundle image, possibly corrupted file"
+ print >> sys.stderr, "Error: cannot unbundle image, possibly corrupted file"
sys.exit(-1)
except IOError:
- print "Error: cannot unbundle image, possibly corrupted file"
+ print >> sys.stderr, "Error: cannot unbundle image, possibly corrupted file"
sys.exit(-1)
kernel_dir=None
if not(self.cli_options.kernel_type==None):
@@@ -285,14 -286,15 +286,15 @@@
print ramdisk_id
if not(kernel_found):
if not(kernel_dir):
- print "Error: couldn't find kernel. Check your parameters or specify an existing kernel/ramdisk"
+ print >> sys.stderr, "Error: couldn't find kernel. Check your parameters or specify an existing kernel/ramdisk"
sys.exit(-1);
elif i==0:
- print "Error: couldn't find kernel. Check your parameters or specify an existing kernel/ramdisk"
+ print >> sys.stderr, "Error: couldn't find kernel. Check your parameters or specify an existing kernel/ramdisk"
sys.exit(-1);
else:
break
#now, install the image, referencing the kernel/ramdisk
+ image_id = None
for path in names:
name = os.path.basename(path)
if not name.startswith('.'):
@@@ -303,7 -305,10 +305,10 @@@
else:
name = name[:-len('.img')]
id = self.bundleFile(path, name, description, arch, kernel_id, ramdisk_id)
- return id
+ image_id = id
+ # make good faith attempt to remove working directory and all files within
+ shutil.rmtree(self.destination, True)
+ return image_id
def main(self, **args):
self.process_args()
@@@ -314,30 -319,30 +319,30 @@@
# tarball and image option are mutually exclusive
if (not(self.cli_options.image_name) and not(self.cli_options.tarball)):
- print "Error: one of -i or -t must be specified"
+ print >> sys.stderr, "Error: one of -i or -t must be specified"
sys.exit(-1)
if (self.cli_options.image_name and self.cli_options.tarball):
- print "Error: -i and -t cannot be specified together"
+ print >> sys.stderr, "Error: -i and -t cannot be specified together"
sys.exit(-1)
if (self.cli_options.tarball and \
(not(self.cli_options.description) or not(self.cli_options.architecture))):
- print "Error: when -t is specified, -s and -a are required"
+ print >> sys.stderr, "Error: when -t is specified, -s and -a are required"
sys.exit(-1)
if (self.cli_options.architecture and \
not(self.cli_options.architecture == 'i386' or self.cli_options.architecture == 'x86_64')):
- print "Error: architecture must be either 'i386' or 'x86_64'"
+ print >> sys.stderr, "Error: architecture must be either 'i386' or 'x86_64'"
sys.exit(-1)
if (self.cli_options.kernel and not(self.cli_options.ramdisk)) or \
(not(self.cli_options.kernel) and self.cli_options.ramdisk):
- print "Error: kernel and ramdisk must both be overridden"
+ print >> sys.stderr, "Error: kernel and ramdisk must both be overridden"
sys.exit(-1)
if (self.cli_options.architecture and self.cli_options.image_name):
- print "Warning: you may be overriding the default architecture of this image!"
+ print >> sys.stderr, "Warning: you may be overriding the default architecture of this image!"
euare_svc = EuareService()
@@@ -348,7 -353,7 +353,7 @@@
is_secure=euare_svc.args['is_secure'])
userinfo = conn.get_user().arn.split(':')
if not(userinfo[4]=='eucalyptus') and not(self.cli_options.kernel):
- print "Error: must be cloud admin to upload kernel/ramdisk. try specifying existing ones with --kernel and --ramdisk"
+ print >> sys.stderr, "Error: must be cloud admin to upload kernel/ramdisk. try specifying existing ones with --kernel and --ramdisk"
sys.exit(-1)
self.eustore_url = self.ServiceClass.StoreBaseURL
@@@ -356,6 -361,8 +361,8 @@@
ec2_conn = boto.connect_euca(host=euare_svc.args['host'], \
aws_access_key_id=euare_svc.args['aws_access_key_id'],\
aws_secret_access_key=euare_svc.args['aws_secret_access_key'])
+ ec2_conn.APIVersion = '2012-03-01'
+
self.ImageList = ec2_conn.get_all_images()
if os.environ.has_key('EUSTORE_URL'):
@@@ -388,10 -395,12 +395,12 @@@
# more param checking now
if image['single-kernel']=='True':
if self.cli_options.kernel_type:
- print "The -k option will be ignored because the image is single-kernel"
+ print >> sys.stderr, "The -k option will be ignored because the image is single-kernel"
else:
- if not(self.cli_options.kernel_type):
- print "Error: The -k option must be specified because this image has separate kernels"
+ # Warn about kernel type for multi-kernel images, but not if already installed
+ # kernel/ramdisk have been specified.
+ if not(self.cli_options.kernel_type) and not(self.cli_options.kernel):
+ print >> sys.stderr, "Error: The -k option must be specified because this image has separate kernels"
sys.exit(-1)
print "Downloading Image : ",image['description']
imageURL = self.eustore_url+image['url']
@@@ -419,10 -428,9 +428,9 @@@
if image['name'] == crc.rjust(10,"0"):
print "Installed image: "+self.bundleAll(fp.name, None, image['description'], image['architecture'])
else:
- print "Error: Downloaded image was incomplete or corrupt, please try again"
- os.remove(fp.name)
+ print >> sys.stderr, "Error: Downloaded image was incomplete or corrupt, please try again"
else:
- print "Image name not found, please run eustore-describe-images"
+ print >> sys.stderr, "Image name not found, please run eustore-describe-images"
def main_cli(self):
euca2ools.utils.print_version_if_necessary()
diff --combined setup.py
index e1d2633,f8c190d..1c541c7
--- a/setup.py
+++ b/setup.py
@@@ -34,10 -34,21 +34,21 @@@
from distutils.core import setup
from distutils.command.build_scripts import build_scripts
from distutils.command.install_scripts import install_scripts
+ from distutils.command.sdist import sdist
import os.path
+ import re
+ import subprocess
from euca2ools import __version__
+ def get_version():
+ try:
+ popen = subprocess.Popen(['git', 'describe'], stdout=subprocess.PIPE)
+ popen.wait()
+ return popen.stdout.read().strip()
+ except:
+ return __version__
+
# Cheap hack: install symlinks separately from regular files.
# cmd.copy_tree accepts a preserve_symlinks option, but when we call
# ``setup.py install'' more than once the method fails when it encounters
@@@ -64,8 -75,35 +75,35 @@@ class install_scripts_and_symlinks(inst
if not os.path.exists(newlink):
os.symlink(target, newlink)
+ class sdist_with_git_version(sdist):
+ '''Like sdist, but using the output of ``git describe'' to fill in
+ __init__.__version__'''
+ def make_release_tree(self, base_dir, files):
+ sdist.make_release_tree(self, base_dir, files)
+
+ try:
+ popen = subprocess.Popen(['git', 'describe'],
+ stdout=subprocess.PIPE)
+ popen.wait()
+ version = popen.stdout.read().strip()
+ version_line = '__version__ = \'{0}\'\n'.format(version)
+ old_init_file_name = os.path.join(base_dir, 'euca2ools/__init__.py')
+ new_init_file_name = old_init_file_name + '.new'
+ with open(new_init_file_name, 'w') as new_init_file:
+ with open(old_init_file_name) as old_init_file:
+ for line in old_init_file:
+ if re.match("__version__ *= *'.*'", line):
+ new_init_file.write(version_line)
+ else:
+ new_init_file.write(line)
+ new_init_file.flush()
+ os.rename(new_init_file_name, old_init_file_name)
+ except:
+ # Not really a problem; we'll just leave it as-is
+ pass
+
setup(name = "euca2ools",
- version = __version__,
+ version = get_version(),
description = "Elastic Utility Computing Architecture Command Line Tools",
long_description="Elastic Utility Computing Architecture Command Line Tools",
author = "Mitch Garnaat",
@@@ -195,12 -233,11 +233,12 @@@
"bin/eustore-install-image"],
url = "http://open.eucalyptus.com",
packages = ["euca2ools", "euca2ools.nc", "euca2ools.commands",
- "euca2ools.commands.euca", "euca2ools.commands.euare",
- "euca2ools.commands.eustore"],
+ "euca2ools.commands.bundle", "euca2ools.commands.euca",
+ "euca2ools.commands.euare", "euca2ools.commands.eustore",
+ "euca2ools.commands.walrus"],
license = 'BSD (Simplified)',
platforms = 'Posix; MacOS X; Windows',
- classifiers = ['Development Status :: 5 - Production/Stable',
+ classifiers = ['Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Users',
'License :: OSI Approved :: Simplified BSD License',
'Operating System :: OS Independent',
@@@ -210,4 -247,5 +248,5 @@@
'Programming Language :: Python :: 2.7',
'Topic :: Internet'],
cmdclass = {'build_scripts': build_scripts_except_symlinks,
- 'install_scripts': install_scripts_and_symlinks})
+ 'install_scripts': install_scripts_and_symlinks,
+ 'sdist': sdist_with_git_version})
--
managing cloud instances for Eucalyptus
More information about the pkg-eucalyptus-commits
mailing list