[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:29:41 UTC 2013
The following commit has been merged in the master branch:
commit 882ffeb8e4048ebb74f28f8f0ca686d1499e8ffe
Author: Garrett Holmstrom <gholms at fedoraproject.org>
Date: Sat Apr 14 14:02:26 2012 -0700
Add base euca- command classes
diff --git a/euca2ools/commands/euca/__init__.py b/euca2ools/commands/euca/__init__.py
index d901b8d..9c72769 100644
--- a/euca2ools/commands/euca/__init__.py
+++ b/euca2ools/commands/euca/__init__.py
@@ -1,6 +1,6 @@
# Software License Agreement (BSD License)
#
-# Copyright (c) 2009-2011, Eucalyptus Systems, Inc.
+# Copyright (c) 2009-2012, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
@@ -27,9 +27,220 @@
# 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 argparse
+import os.path
+from requestbuilder import Arg, CONNECTION
+from requestbuilder.mixins import TabifyingCommand
+import requestbuilder.service
+import shlex
+from string import Template
+from .. import Euca2oolsRequest
+
+class Eucalyptus(requestbuilder.service.BaseService):
+ Description = 'Eucalyptus compute cloud controller'
+ APIVersion = '2009-11-30'
+ EnvURL = 'EC2_URL'
+
+ def __init__(self, configfile=None, **kwargs):
+ self.configfile_name = configfile
+ requestbuilder.service.BaseService.__init__(self, **kwargs)
+
+ def find_credentials(self):
+ # CLI-given env-style config file
+ if os.path.isfile(self.configfile_name or ''):
+ config = _parse_configfile(self.configfile_name)
+ self._populate_init_args_from_env_config(config)
+ # AWS credential file (path is in the environment)
+ requestbuilder.service.BaseService.find_credentials(self)
+ # Environment
+ config = self._get_env_config_from_env()
+ self._populate_init_args_from_env_config(config)
+ # User, systemwide env-style config files
+ for configfile_name in (self.configfile_name or '',
+ '~/.eucarc', '~/.eucarc/eucarc'):
+ configfile_name = os.path.expandvars(configfile_name)
+ configfile_name = os.path.expanduser(configfile_name)
+ if os.path.isfile(configfile_name):
+ config = _parse_configfile(configfile_name)
+ self._populate_init_args_from_env_config(config)
+
+ _init_args_key_map = {'EC2_ACCESS_KEY': 'aws_access_key_id',
+ 'EC2_SECRET_KEY': 'aws_secret_access_key',
+ 'EC2_URL': 'url'}
+
+ def _get_env_config_from_env(self):
+ envconfig = {}
+ for key in self._init_args_key_map:
+ if key in os.environ:
+ envconfig[key] = os.getenv(key)
+ return envconfig
+
+ def _populate_init_args_from_env_config(self, envconfig):
+ '''
+ Populate self._init_args from the contents of an environment
+ variable-like dict.
+ '''
+ for (env_key, initargs_key) in self._init_args_key_map.iteritems():
+ if env_key in envconfig and not self._init_args.get(initargs_key):
+ self._init_args[initargs_key] = envconfig[env_key]
+
+def _parse_configfile(configfile_name):
+ def sourcehook(filename):
+ filename = filename.strip('"\'')
+ filename = Template(filename).safe_substitute(config)
+ filename = os.path.expandvars(filename)
+ filename = os.path.expanduser(filename)
+ return (filename, open(filename))
+
+ config = {}
+ configfile_name = os.path.expandvars(configfile_name)
+ configfile_name = os.path.expanduser(configfile_name)
+ with open(configfile_name) as configfile:
+ lexer = shlex.shlex(configfile)
+ lexer.whitespace_split = True
+ lexer.source = 'source'
+ lexer.sourcehook = sourcehook
+ for token in lexer:
+ if '=' in token:
+ (key, val) = token.split('=', 1)
+ val = val.strip('"\'')
+ if not config.get(key):
+ config[key] = Template(val).safe_substitute(config)
+ return config
+
+## TODO: regions
+class EucalyptusRequest(Euca2oolsRequest, TabifyingCommand):
+ ServiceClass = Eucalyptus
+
+ Args = [Arg('-I', '-a', '--access-key-id', '--access-key',
+ metavar='KEY_ID', dest='aws_access_key_id',
+ route_to=CONNECTION),
+ Arg('-S', '-s', '--secret-key', metavar='KEY',
+ dest='aws_secret_access_key', route_to=CONNECTION),
+ Arg('-U', '--url', route_to=CONNECTION,
+ help='cloud controller URL'),
+ Arg('--config', dest='configfile', metavar='CFGFILE',
+ route_to=CONNECTION)]
+
+ def __init__(self, **kwargs):
+ Euca2oolsRequest.__init__(self, **kwargs)
+ # Resolve short arg conflicts
+ a_args = [arg for arg in self.Args if '-a' in arg.pargs]
+ if len(a_args) > 1:
+ for arg in a_args:
+ if '--access-key' in arg.pargs:
+ arg[arg.index('-a')] = '-A'
+ s_args = [arg for arg in self.Args if '-s' in arg.pargs]
+ if len(s_args) > 1:
+ for arg in s_args:
+ if '--secret-key' in arg.pargs:
+ arg.pargs.remove('-s')
+
+ def parse_http_response(self, response_body):
+ response = Euca2oolsRequest.parse_http_response(self, response_body)
+ # Compute cloud controller responses enclose their useful data inside
+ # FooResponse # elements. If that's all we have after stripping out
+ # RequestId then just return its contents.
+ useful_keys = filter(lambda x: x != 'RequestId', response.keys())
+ if len(useful_keys) == 1:
+ return response[useful_keys[0]]
+ else:
+ return response
+
+ def print_instance(self, instance):
+ instance_line = ['INSTANCE']
+ for key in ['instanceId', 'imageId', 'dnsName', 'privateDnsName']:
+ instance_line.append(instance.get(key))
+ instance_line.append(instance.get('instanceState', {})
+ .get('name'))
+ instance_line.append(instance.get('keyName'))
+ instance_line.append(instance.get('amiLaunchIndex'))
+ instance_line.append(','.join([code['productCode'] for code in
+ instance.get('productCodes', [])]))
+ instance_line.append(instance.get('instanceType'))
+ instance_line.append(instance.get('launchTime'))
+ instance_line.append(instance.get('placement', {}).get('availabilityZone'))
+ instance_line.append(instance.get('kernelId'))
+ instance_line.append(instance.get('ramdiskId'))
+ if instance.get('monitoring'):
+ instance_line.append('monitoring-' +
+ instance['monitoring'].get('state'))
+ else:
+ instance_line.append(None)
+ instance_line.append(instance.get('ipAddress'))
+ instance_line.append(instance.get('privateIpAddress'))
+ instance_line.append(instance.get('rootDeviceType'))
+ instance_line.append(instance.get('virtualizationType'))
+ instance_line.append(instance.get('hypervisor'))
+ instance_line.append(instance.get('subnetId'))
+ instance_line.append(instance.get('vpcId'))
+ instance_line.append(instance.get('placement', {}).get('groupName'))
+ instance_line.append(','.join([group['groupId'] for group in
+ instance.get('groupSet', [])]))
+ instance_line.append(instance.get('placement', {}).get('tenancy'))
+ print self.tabify(instance_line)
+
+ for blockdev in instance.get('blockDeviceMapping', []):
+ self.print_blockdevice(blockdev)
+
+ for tag in instance.get('tagSet', []):
+ print self.tabify(['TAG', 'instance', instance.get('instanceId'),
+ tag.get('key'), tag.get('value')])
+
+ def print_blockdevice(self, blockdev):
+ print self.tabify(['BLOCKDEVICE', blockdev.get('deviceName'),
+ blockdev.get('ebs', {}).get('volumeId'),
+ blockdev.get('ebs', {}).get('attachTime'),
+ blockdev.get('ebs', {}).get('deleteOnTermination')])
+ def print_volume(self, volume):
+ print 'VOLUME', self.tabify([volume.get(attr) for attr in
+ ('volumeId', 'size', 'snapshotId', 'availabilityZone',
+ 'status', 'createTime')])
+ for attachment in volume.get('attachmentSet', []):
+ print 'ATTACHMENT', self.tabify([volume.get('volumeId')] +
+ [attachment.get(attr) for attr in
+ ('instanceId', 'device', 'status', 'attachTime')])
+## TODO: test this
+class BlockDeviceMapping(dict):
+ '''
+ A block device mapping as given on the image registration command line
+ '''
+ def __init__(self, map_as_str):
+ dict.__init__(self)
+ try:
+ (device, mapping) = map_as_str.split('=')
+ except ValueError:
+ raise argparse.ArgumentTypeError('block device mapping {0} must '
+ 'have form KEY=VALUE'.format(map_as_str))
+ if mapping.lower() == 'none':
+ ## FIXME: NoDevice should be an empty element
+ self['Ebs'] = {'NoDevice': 'true'}
+ elif mapping.startswith('ephemeral'):
+ self['VirtualName'] = mapping
+ elif (mapping.startswith('snap-') or mapping.startswith('vol-') or
+ mapping.startswith(':')):
+ map_bits = mapping.split(':')
+ if len(map_bits) == 1:
+ map_bits.append(None)
+ if len(map_bits) == 2:
+ map_bits.append('true')
+ if len(map_bits) != 3:
+ raise argparse.ArgumentTypeError(
+ 'EBS block device mapping {0} must have form '
+ '[snap-id]:[size]:[true|false]'.format(map_as_str))
+ try:
+ int(map_bits[1])
+ except TypeError:
+ raise argparse.ArgumentTypeError(
+ 'second element of EBS block device mapping {0} '
+ 'must be an integer')
+ if map_bits[2] not in ('true', 'false'):
+ raise argparse.ArgumentTypeError(
+ 'third element of EBS block device mapping {0} '
+ "must be 'true' or 'false'".format(map_as_str))
+ self['Ebs'] = {'SnapshotId': map_bits[0],
+ 'VolumeSize': map_bits[1],
+ 'DeleteOnTermination': map_bits[2]}
--
managing cloud instances for Eucalyptus
More information about the pkg-eucalyptus-commits
mailing list