From b344877bdf24985dea5342060c989a9d06fe0964 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Fri, 25 Feb 2011 13:01:32 -0800 Subject: add a caching layer to the has_role call to increase performance --- nova/api/ec2/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 5adc2c075..7a9c4f957 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -46,8 +46,6 @@ flags.DEFINE_integer('lockout_minutes', 15, 'Number of minutes to lockout if triggered.') flags.DEFINE_integer('lockout_window', 15, 'Number of minutes for lockout window.') -flags.DEFINE_list('lockout_memcached_servers', None, - 'Memcached servers or None for in process cache.') class RequestLogging(wsgi.Middleware): @@ -104,11 +102,11 @@ class Lockout(wsgi.Middleware): def __init__(self, application): """middleware can use fake for testing.""" - if FLAGS.lockout_memcached_servers: + if FLAGS.memcached_servers: import memcache else: from nova import fakememcache as memcache - self.mc = memcache.Client(FLAGS.lockout_memcached_servers, + self.mc = memcache.Client(FLAGS.memcached_servers, debug=0) super(Lockout, self).__init__(application) -- cgit From 5a9d2eb44ced0affe143e6274c9c9326f1c2d7da Mon Sep 17 00:00:00 2001 From: John Tran Date: Fri, 18 Mar 2011 11:49:11 -0700 Subject: created api endpoint to allow uploading of public key --- nova/api/ec2/cloud.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index cadda97db..6fe01b0e9 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -302,6 +302,18 @@ class CloudController(object): 'keyMaterial': data['private_key']} # TODO(vish): when context is no longer an object, pass it here + def import_public_key(self, context, key_name, public_key, + fingerprint=None): + LOG.audit(_("Import key %s"), key_name, context=context) + key = {} + key['user_id'] = context.user_id + key['name'] = key_name + key['public_key'] = public_key + if fingerprint: + key['fingerprint'] = fingerprint + db.key_pair_create(context, key) + return True + def delete_key_pair(self, context, key_name, **kwargs): LOG.audit(_("Delete key pair %s"), key_name, context=context) try: -- cgit From a105fd449a0b91cde3ab86cc552705dfe50e3f6d Mon Sep 17 00:00:00 2001 From: John Tran Date: Mon, 21 Mar 2011 14:35:19 -0700 Subject: if fingerprint data not provided, added logic to calculate it using the pub key. --- nova/api/ec2/cloud.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 6fe01b0e9..8ec74fbe0 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -27,6 +27,8 @@ import datetime import IPy import os import urllib +import tempfile +import shutil from nova import compute from nova import context @@ -309,8 +311,17 @@ class CloudController(object): key['user_id'] = context.user_id key['name'] = key_name key['public_key'] = public_key - if fingerprint: - key['fingerprint'] = fingerprint + if fingerprint is None: + tmpdir = tempfile.mkdtemp() + pubfile = os.path.join(tmpdir, 'temp.pub') + fh = open(pubfile, 'w') + fh.write(public_key) + fh.close() + (out, err) = utils.execute('ssh-keygen', '-q', '-l', '-f', + '%s' % (pubfile)) + fingerprint = out.split(' ')[1] + shutil.rmtree(tmpdir) + key['fingerprint'] = fingerprint db.key_pair_create(context, key) return True -- cgit From 00fad85ac9cacf71f069ec6b9c9c7e974a9d9edd Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 30 Mar 2011 13:18:47 -0400 Subject: Implement quotas for the new v1.1 server metadata controller. Modified the compute API so that metadata is a dict (not an array) to ensure we are using unique key values for metadata. This is isn't explicit in the SPECs but it is implied by the new v1.1 spec since PUT requests modify individual items. Re-enabled the metadata integration test. --- nova/api/openstack/server_metadata.py | 30 +++++++++++++++++++++++------- nova/api/openstack/servers.py | 12 +----------- 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/server_metadata.py b/nova/api/openstack/server_metadata.py index 45bbac99d..2a1249b10 100644 --- a/nova/api/openstack/server_metadata.py +++ b/nova/api/openstack/server_metadata.py @@ -18,6 +18,7 @@ from webob import exc from nova import compute +from nova import quota from nova import wsgi from nova.api.openstack import faults @@ -43,10 +44,13 @@ class Controller(wsgi.Controller): def create(self, req, server_id): context = req.environ['nova.context'] - body = self._deserialize(req.body, req.get_content_type()) - self.compute_api.update_or_create_instance_metadata(context, - server_id, - body['metadata']) + data = self._deserialize(req.body, req.get_content_type())['metadata'] + try: + self.compute_api.update_or_create_instance_metadata(context, + server_id, + data) + except quota.QuotaError as error: + self._handle_quota_error(error) return req.body def update(self, req, server_id, id): @@ -58,9 +62,13 @@ class Controller(wsgi.Controller): if len(body) > 1: expl = _('Request body contains too many items') raise exc.HTTPBadRequest(explanation=expl) - self.compute_api.update_or_create_instance_metadata(context, - server_id, - body) + try: + self.compute_api.update_or_create_instance_metadata(context, + server_id, + body) + except quota.QuotaError as error: + self._handle_quota_error(error) + return req.body def show(self, req, server_id, id): @@ -76,3 +84,11 @@ class Controller(wsgi.Controller): """ Deletes an existing metadata """ context = req.environ['nova.context'] self.compute_api.delete_instance_metadata(context, server_id, id) + + def _handle_quota_error(self, error): + """ + Reraise quota errors as api-specific http exceptions + """ + if error.code == "MetadataLimitExceeded": + raise exc.HTTPBadRequest(explanation=error.message) + raise error diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 6bd173bb8..966680c41 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -134,16 +134,6 @@ class Controller(wsgi.Controller): kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image( req, image_id) - # Metadata is a list, not a Dictionary, because we allow duplicate keys - # (even though JSON can't encode this) - # In future, we may not allow duplicate keys. - # However, the CloudServers API is not definitive on this front, - # and we want to be compatible. - metadata = [] - if env['server'].get('metadata'): - for k, v in env['server']['metadata'].items(): - metadata.append({'key': k, 'value': v}) - personality = env['server'].get('personality') injected_files = [] if personality: @@ -161,7 +151,7 @@ class Controller(wsgi.Controller): display_description=env['server']['name'], key_name=key_name, key_data=key_data, - metadata=metadata, + metadata=env['server'].get('metadata', {}), injected_files=injected_files) except quota.QuotaError as error: self._handle_quota_error(error) -- cgit From 323eb60884cf8736448d997068d32f252d22e7f3 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 30 Mar 2011 12:05:25 -0700 Subject: Key type values in ec2_api off of container format --- nova/api/ec2/cloud.py | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 7ba8dfbea..1e6c4d1db 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -146,7 +146,7 @@ class CloudController(object): floating_ip = db.instance_get_floating_address(ctxt, instance_ref['id']) ec2_id = ec2utils.id_to_ec2_id(instance_ref['id']) - image_ec2_id = self._image_ec2_id(instance_ref['image_id'], 'machine') + image_ec2_id = self._image_ec2_id(instance_ref['image_id'], 'ami') data = { 'user-data': base64.b64decode(instance_ref['user_data']), 'meta-data': { @@ -176,7 +176,7 @@ class CloudController(object): for image_type in ['kernel', 'ramdisk']: if '%s_id' % image_type in instance_ref: ec2_id = self._image_ec2_id(instance_ref['%s_id' % image_type], - image_type) + self._image_type(image_type)) data['meta-data']['%s-id' % image_type] = ec2_id if False: # TODO(vish): store ancestor ids @@ -862,13 +862,27 @@ class CloudController(object): self.compute_api.update(context, instance_id=instance_id, **kwargs) return True - _type_prefix_map = {'machine': 'ami', - 'kernel': 'aki', - 'ramdisk': 'ari'} + @staticmethod + def _image_type(image_type): + """Converts to a three letter image type. - def _image_ec2_id(self, image_id, image_type='machine'): - prefix = self._type_prefix_map[image_type] - template = prefix + '-%08x' + aki, kernel => aki + ari, ramdisk => ari + anything else => ami + + """ + if image_type == 'kernel': + return 'aki' + if image_type == 'ramdisk': + return 'ari' + if image_type not in ['aki', 'ari']: + return 'ami' + return image_type + + @staticmethod + def _image_ec2_id(image_id, image_type='ami'): + """Returns image ec2_id using id and three letter type""" + template = image_type + '-%08x' return ec2utils.id_to_ec2_id(int(image_id), template=template) def _get_image(self, context, ec2_id): @@ -881,7 +895,7 @@ class CloudController(object): def _format_image(self, image): """Convert from format defined by BaseImageService to S3 format.""" i = {} - image_type = image['properties'].get('type') + image_type = self._image_type(image.get('container_format')) ec2_id = self._image_ec2_id(image.get('id'), image_type) name = image.get('name') if name: @@ -890,16 +904,19 @@ class CloudController(object): i['imageId'] = ec2_id kernel_id = image['properties'].get('kernel_id') if kernel_id: - i['kernelId'] = self._image_ec2_id(kernel_id, 'kernel') + i['kernelId'] = self._image_ec2_id(kernel_id, 'aki') ramdisk_id = image['properties'].get('ramdisk_id') if ramdisk_id: - i['ramdiskId'] = self._image_ec2_id(ramdisk_id, 'ramdisk') + i['ramdiskId'] = self._image_ec2_id(ramdisk_id, 'ari') i['imageOwnerId'] = image['properties'].get('owner_id') i['imageLocation'] = image['properties'].get('image_location') i['imageState'] = image['properties'].get('image_state') i['displayName'] = image.get('name') i['description'] = image.get('description') - i['type'] = image_type + display_mapping = {'aki': 'kernel', + 'ari': 'ramdisk', + 'ami': 'machine'} + i['type'] = display_mapping.get(image_type) i['isPublic'] = str(image['properties'].get('is_public', '')) == 'True' i['architecture'] = image['properties'].get('architecture') return i @@ -932,8 +949,9 @@ class CloudController(object): image_location = kwargs['name'] metadata = {'properties': {'image_location': image_location}} image = self.image_service.create(context, metadata) + image_type = self._image_type(image.get('container_format')) image_id = self._image_ec2_id(image['id'], - image['properties']['type']) + image_type) msg = _("Registered image %(image_location)s with" " id %(image_id)s") % locals() LOG.audit(msg, context=context) -- cgit From d224b0509273ca8a92c5c2b9abca69038835935c Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 30 Mar 2011 15:10:40 -0400 Subject: adding v1.0 support for rebuild; adding compute api rebuild support --- nova/api/openstack/servers.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index f7696d918..4b2703549 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -317,9 +317,6 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPBadRequest()) return exc.HTTPAccepted() - def _action_rebuild(self, input_dict, req, id): - return faults.Fault(exc.HTTPNotImplemented()) - def _action_resize(self, input_dict, req, id): """ Resizes a given instance to the flavor size requested """ try: @@ -606,6 +603,19 @@ class ControllerV10(Controller): except exception.TimeoutException: return exc.HTTPRequestTimeout() + def _action_rebuild(self, input_dict, req, id): + context = req.environ['nova.context'] + if (not 'rebuild' in input_dict + or not 'imageId' in input_dict['rebuild']): + msg = _("No imageId was specified") + return faults.Fault(exc.HTTPBadRequest(msg)) + + image_id = input_dict['rebuild']['imageId'] + + self.compute_api.rebuild(context, id, image_id) + + return exc.HTTPAccepted() + class ControllerV11(Controller): def _image_id_from_req_data(self, data): @@ -632,6 +642,9 @@ class ControllerV11(Controller): def _limit_items(self, items, req): return common.limited_by_marker(items, req) + def _action_rebuild(self, input_dict, req, id): + return faults.Fault(exc.HTTPNotImplemented()) + class ServerCreateRequestXMLDeserializer(object): """ -- cgit From 1703592992ebdd5bbf19952f79f05022a4cdc849 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 30 Mar 2011 12:34:10 -0700 Subject: remove all references to image_type and change nova-manage upload to set container format more intelligently --- nova/api/openstack/servers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index f7696d918..d640e8684 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -562,7 +562,7 @@ class Controller(wsgi.Controller): _("Cannot build from image %(image_id)s, status not active") % locals()) - if image_meta['properties']['disk_format'] != 'ami': + if image_meta.get('container_format') != 'ami': return None, None try: -- cgit From 176d98aa179b174c4e4a5621f723ef7b9145e3cb Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 30 Mar 2011 15:47:12 -0400 Subject: Update docstrings and spacing. --- nova/api/openstack/server_metadata.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/server_metadata.py b/nova/api/openstack/server_metadata.py index 2a1249b10..618665082 100644 --- a/nova/api/openstack/server_metadata.py +++ b/nova/api/openstack/server_metadata.py @@ -86,9 +86,7 @@ class Controller(wsgi.Controller): self.compute_api.delete_instance_metadata(context, server_id, id) def _handle_quota_error(self, error): - """ - Reraise quota errors as api-specific http exceptions - """ + """Reraise quota errors as api-specific http exceptions""" if error.code == "MetadataLimitExceeded": raise exc.HTTPBadRequest(explanation=error.message) raise error -- cgit From cee0e90c058c3e50a3388eb4960afeb21b441f6a Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 30 Mar 2011 16:17:07 -0400 Subject: adding initial v1.1 rebuild action support --- nova/api/openstack/servers.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4b2703549..edf98fe93 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -611,9 +611,7 @@ class ControllerV10(Controller): return faults.Fault(exc.HTTPBadRequest(msg)) image_id = input_dict['rebuild']['imageId'] - self.compute_api.rebuild(context, id, image_id) - return exc.HTTPAccepted() @@ -643,7 +641,27 @@ class ControllerV11(Controller): return common.limited_by_marker(items, req) def _action_rebuild(self, input_dict, req, id): - return faults.Fault(exc.HTTPNotImplemented()) + context = req.environ['nova.context'] + if (not 'rebuild' in input_dict + or not 'imageRef' in input_dict['rebuild']): + msg = _("No imageRef was specified") + return faults.Fault(exc.HTTPBadRequest(msg)) + + image_ref = input_dict['rebuild']['imageRef'] + image_id = common.get_id_from_href(image_ref) + + metadata = [] + if 'metadata' in input_dict['rebuild']: + try: + for k, v in input_dict['rebuild']['metadata'].items(): + metadata.append({'key': k, 'value': v}) + + except Exception: + msg = _("Improperly formatted metadata provided") + return exc.HTTPBadRequest(msg) + + self.compute_api.rebuild(context, id, image_id, metadata) + return exc.HTTPAccepted() class ServerCreateRequestXMLDeserializer(object): -- cgit From b8173ba9fe80045665064208e66f46cca75fd3ba Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 30 Mar 2011 13:48:07 -0700 Subject: review cleanup --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 1e6c4d1db..3541e49ca 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -881,7 +881,7 @@ class CloudController(object): @staticmethod def _image_ec2_id(image_id, image_type='ami'): - """Returns image ec2_id using id and three letter type""" + """Returns image ec2_id using id and three letter type.""" template = image_type + '-%08x' return ec2utils.id_to_ec2_id(int(image_id), template=template) -- cgit From 7f98416fdba59c4305f88a30a457bbf6c68ef372 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 31 Mar 2011 09:20:47 -0400 Subject: Limit image metadata to the configured metadata quota for a project. --- nova/api/openstack/image_metadata.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index c9d6ac532..76abdaa7e 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -18,6 +18,7 @@ from webob import exc from nova import flags +from nova import quota from nova import utils from nova import wsgi from nova.api.openstack import faults @@ -39,6 +40,15 @@ class Controller(wsgi.Controller): metadata = image.get('properties', {}) return metadata + def _check_quota_limit(self, context, metadata): + if metadata is None: + return + num_metadata = len(metadata) + quota_metadata = quota.allowed_metadata_items(context, num_metadata) + if quota_metadata < num_metadata: + expl = ("Image metadata limit exceeded") + raise exc.HTTPBadRequest(explanation=expl) + def index(self, req, image_id): """Returns the list of metadata for a given instance""" context = req.environ['nova.context'] @@ -61,6 +71,7 @@ class Controller(wsgi.Controller): if 'metadata' in body: for key, value in body['metadata'].iteritems(): metadata[key] = value + self._check_quota_limit(context, metadata) img['properties'] = metadata self.image_service.update(context, image_id, img, None) return dict(metadata=metadata) @@ -77,6 +88,7 @@ class Controller(wsgi.Controller): img = self.image_service.show(context, image_id) metadata = self._get_metadata(context, image_id, img) metadata[id] = body[id] + self._check_quota_limit(context, metadata) img['properties'] = metadata self.image_service.update(context, image_id, img, None) -- cgit From 1ecd9b3d00f002799a9eab92f0179dcbea8b8c37 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 31 Mar 2011 14:15:42 -0400 Subject: adding 'building' power state; testing for 409 from OSAPI when rebuild requested on server being rebuild --- nova/api/openstack/servers.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index edf98fe93..fc33a8257 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -611,7 +611,13 @@ class ControllerV10(Controller): return faults.Fault(exc.HTTPBadRequest(msg)) image_id = input_dict['rebuild']['imageId'] - self.compute_api.rebuild(context, id, image_id) + + try: + self.compute_api.rebuild(context, id, image_id) + except exception.BuildInProgress: + msg = _("Unable to rebuild server that is being rebuilt") + return faults.Fault(exc.HTTPConflict(msg)) + return exc.HTTPAccepted() @@ -660,7 +666,12 @@ class ControllerV11(Controller): msg = _("Improperly formatted metadata provided") return exc.HTTPBadRequest(msg) - self.compute_api.rebuild(context, id, image_id, metadata) + try: + self.compute_api.rebuild(context, id, image_id, metadata) + except exception.BuildInProgress: + msg = _("Unable to rebuild server that is being rebuilt") + return faults.Fault(exc.HTTPConflict(msg)) + return exc.HTTPAccepted() -- cgit From 600dc802e3775ea6b4b940e03c82e8b8ac40191c Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 31 Mar 2011 15:34:33 -0400 Subject: adding servers view mapping for BUILDING power state --- nova/api/openstack/views/servers.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index 4e7f62eb3..b74c8d409 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -67,6 +67,8 @@ class ViewBuilder(object): power_state.SHUTOFF: 'active', power_state.CRASHED: 'error', power_state.FAILED: 'error'} + power_state.BUILDING: 'build', + } inst_dict = { 'id': int(inst['id']), -- cgit From 29396c4c739b6b0a26a1b24beb86aa2e7e2bc474 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 31 Mar 2011 15:37:44 -0400 Subject: Didn't run my code. Syntax error :( --- nova/api/openstack/views/servers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index b74c8d409..6496f0ee5 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -66,7 +66,7 @@ class ViewBuilder(object): power_state.SHUTDOWN: 'active', power_state.SHUTOFF: 'active', power_state.CRASHED: 'error', - power_state.FAILED: 'error'} + power_state.FAILED: 'error', power_state.BUILDING: 'build', } -- cgit From f37edcb18d27585ce6a2074a5f35eb7a84454dcf Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 31 Mar 2011 15:41:18 -0400 Subject: Adding explanation keyword to HTTPConflict --- nova/api/openstack/servers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index fc33a8257..563acc59e 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -616,7 +616,7 @@ class ControllerV10(Controller): self.compute_api.rebuild(context, id, image_id) except exception.BuildInProgress: msg = _("Unable to rebuild server that is being rebuilt") - return faults.Fault(exc.HTTPConflict(msg)) + return faults.Fault(exc.HTTPConflict(explanation=msg)) return exc.HTTPAccepted() @@ -670,7 +670,7 @@ class ControllerV11(Controller): self.compute_api.rebuild(context, id, image_id, metadata) except exception.BuildInProgress: msg = _("Unable to rebuild server that is being rebuilt") - return faults.Fault(exc.HTTPConflict(msg)) + return faults.Fault(exc.HTTPConflict(explanation=msg)) return exc.HTTPAccepted() -- cgit From 38b4cd9e68d7e1c262b08474b277573440ec3e87 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 4 Apr 2011 16:17:04 -0400 Subject: Refactor so that instances.instance_type is now instances.instance_type_id. Update the Openstack API to return the correct flavor_id. --- nova/api/ec2/cloud.py | 7 +++++-- nova/api/openstack/servers.py | 6 ++++-- nova/api/openstack/views/servers.py | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 7ba8dfbea..cd1195502 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -722,7 +722,10 @@ class CloudController(object): instance['project_id'], instance['host']) i['productCodesSet'] = self._convert_to_set([], 'product_codes') - i['instanceType'] = instance['instance_type'] + if instance['instance_type']: + i['instanceType'] = instance['instance_type'].get('name', None) + else: + i['instanceType'] = None i['launchTime'] = instance['created_at'] i['amiLaunchIndex'] = instance['launch_index'] i['displayName'] = instance['display_name'] @@ -805,7 +808,7 @@ class CloudController(object): ramdisk = self._get_image(context, kwargs['ramdisk_id']) kwargs['ramdisk_id'] = ramdisk['id'] instances = self.compute_api.create(context, - instance_type=instance_types.get_by_type( + instance_type=instance_types.get_instance_type_by_name( kwargs.get('instance_type', None)), image_id=self._get_image(context, kwargs['image_id'])['id'], min_count=int(kwargs.get('min_count', max_count)), diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4e2ebb2bd..327911f6f 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -160,9 +160,11 @@ class Controller(wsgi.Controller): name = name.strip() try: + inst_type = \ + instance_types.get_instance_type_by_flavor_id(flavor_id) (inst,) = self.compute_api.create( context, - instance_types.get_by_flavor_id(flavor_id), + inst_type, image_id, kernel_id=kernel_id, ramdisk_id=ramdisk_id, @@ -175,7 +177,7 @@ class Controller(wsgi.Controller): except quota.QuotaError as error: self._handle_quota_error(error) - inst['instance_type'] = flavor_id + inst['instance_type'] = inst_type inst['image_id'] = requested_image_id builder = self._get_view_builder(req) diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index 4e7f62eb3..2f400eef6 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -115,7 +115,7 @@ class ViewBuilderV10(ViewBuilder): def _build_flavor(self, response, inst): if 'instance_type' in dict(inst): - response['flavorId'] = inst['instance_type'] + response['flavorId'] = inst['instance_type']['flavorid'] class ViewBuilderV11(ViewBuilder): @@ -134,7 +134,7 @@ class ViewBuilderV11(ViewBuilder): def _build_flavor(self, response, inst): if "instance_type" in dict(inst): - flavor_id = inst["instance_type"] + flavor_id = inst["instance_type"]['flavorid'] flavor_ref = self.flavor_builder.generate_href(flavor_id) response["flavorRef"] = flavor_ref -- cgit From 5c67809e4b9a1546c48316ea52676dfeba8f1a75 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Mon, 4 Apr 2011 15:58:41 -0700 Subject: openstack api requires uppercase image format status responses --- nova/api/openstack/views/images.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 16195b050..9dec8a355 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -34,11 +34,11 @@ class ViewBuilder(object): def _format_status(self, image): """Update the status field to standardize format.""" status_mapping = { - 'pending': 'queued', - 'decrypting': 'preparing', - 'untarring': 'saving', - 'available': 'active', - 'killed': 'failed', + 'pending': 'QUEUED', + 'decrypting': 'PREPARING', + 'untarring': 'SAVING', + 'available': 'ACTIVE', + 'killed': 'FAILED', } try: -- cgit From a6c283f00d67a5172d8271d7e48bd58484ac6b96 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Mon, 4 Apr 2011 16:00:59 -0700 Subject: openstack api metadata responses must be strings --- nova/api/openstack/views/servers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index d24c025be..baa911590 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -82,7 +82,8 @@ class ViewBuilder(object): # Return the metadata as a dictionary metadata = {} for item in inst.get('metadata', []): - metadata[item['key']] = item['value'] + # metadata values must be strings per API + metadata[item['key']] = str(item['value']) inst_dict['metadata'] = metadata inst_dict['hostId'] = '' -- cgit From 7702affdbf09127e3e7cdfafcb6382673914438e Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Tue, 5 Apr 2011 18:43:11 +0900 Subject: Remove and from AllocateAddress response, and fix bug #751176. --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 425784e8a..3b333437b 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -777,7 +777,7 @@ class CloudController(object): def allocate_address(self, context, **kwargs): LOG.audit(_("Allocate address"), context=context) public_ip = self.network_api.allocate_floating_ip(context) - return {'addressSet': [{'publicIp': public_ip}]} + return {'publicIp': public_ip} def release_address(self, context, public_ip, **kwargs): LOG.audit(_("Release address %s"), public_ip, context=context) -- cgit From d8ab404fd74facd181eaaee7cbc78b39a82afd1c Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 5 Apr 2011 08:26:16 -0400 Subject: Add missing underscore. --- nova/api/openstack/image_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index 76abdaa7e..c733172ae 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -46,7 +46,7 @@ class Controller(wsgi.Controller): num_metadata = len(metadata) quota_metadata = quota.allowed_metadata_items(context, num_metadata) if quota_metadata < num_metadata: - expl = ("Image metadata limit exceeded") + expl = _("Image metadata limit exceeded") raise exc.HTTPBadRequest(explanation=expl) def index(self, req, image_id): -- cgit From affb632be0c0054a7b0a4858c6e0a585cc1afd0d Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 5 Apr 2011 08:49:44 -0400 Subject: Nits. --- nova/api/openstack/server_metadata.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/server_metadata.py b/nova/api/openstack/server_metadata.py index 618665082..2f7f6bc82 100644 --- a/nova/api/openstack/server_metadata.py +++ b/nova/api/openstack/server_metadata.py @@ -44,11 +44,12 @@ class Controller(wsgi.Controller): def create(self, req, server_id): context = req.environ['nova.context'] - data = self._deserialize(req.body, req.get_content_type())['metadata'] + data = self._deserialize(req.body, req.get_content_type()) + metadata = data.get('metadata') try: self.compute_api.update_or_create_instance_metadata(context, server_id, - data) + metadata) except quota.QuotaError as error: self._handle_quota_error(error) return req.body -- cgit From e6505fd78cc28a5e91ec6fbf55e2e8de07679c7c Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Tue, 5 Apr 2011 10:56:24 -0400 Subject: Fixed the addresses and metadata collections in xml responses. Added corresponding tests. --- nova/api/openstack/servers.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 6704a68ae..cada92813 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -55,6 +55,13 @@ class Controller(wsgi.Controller): "imageRef"], "link": ["rel", "type", "href"], }, + "dict_collections": { + "metadata": {"item_name": "meta", "item_key": "key"}, + }, + "list_collections": { + "public": {"item_name": "ip", "item_key": "addr"}, + "private": {"item_name": "ip", "item_key": "addr"}, + }, }, } -- cgit From 24c2da40549e882be716e1897fd81aef8f172e53 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 5 Apr 2011 14:47:06 -0400 Subject: adding support for OSAPI v1.1 limits resource --- nova/api/openstack/__init__.py | 9 ++++++--- nova/api/openstack/limits.py | 26 ++++++++++++++++++-------- 2 files changed, 24 insertions(+), 11 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 7545eb0c9..0e0a0646e 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -111,9 +111,6 @@ class APIRouter(wsgi.Router): parent_resource=dict(member_name='server', collection_name='servers')) - _limits = limits.LimitsController() - mapper.resource("limit", "limits", controller=_limits) - super(APIRouter, self).__init__(mapper) @@ -144,6 +141,9 @@ class APIRouterV10(APIRouter): parent_resource=dict(member_name='server', collection_name='servers')) + mapper.resource("limit", "limits", + controller=limits.LimitsControllerV10()) + class APIRouterV11(APIRouter): """Define routes specific to OpenStack API V1.1.""" @@ -172,3 +172,6 @@ class APIRouterV11(APIRouter): mapper.resource("flavor", "flavors", controller=flavors.ControllerV11(), collection={'detail': 'GET'}) + + mapper.resource("limit", "limits", + controller=limits.LimitsControllerV11()) diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index efc7d193d..f9e047e97 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -32,6 +32,7 @@ from webob.dec import wsgify from nova import wsgi from nova.api.openstack import faults +from nova.api.openstack.views import limits as limits_views from nova.wsgi import Controller from nova.wsgi import Middleware @@ -51,8 +52,8 @@ class LimitsController(Controller): _serialization_metadata = { "application/xml": { "attributes": { - "limit": ["verb", "URI", "regex", "value", "unit", - "resetTime", "remaining", "name"], + "limit": ["verb", "URI", "uri", "regex", "value", "unit", + "resetTime", "next-available", "remaining", "name"], }, "plurals": { "rate": "limit", @@ -67,12 +68,21 @@ class LimitsController(Controller): abs_limits = {} rate_limits = req.environ.get("nova.limits", []) - return { - "limits": { - "rate": rate_limits, - "absolute": abs_limits, - }, - } + builder = self._get_view_builder(req) + return builder.build(rate_limits, abs_limits) + + def _get_view_builder(self, req): + raise NotImplementedError() + + +class LimitsControllerV10(LimitsController): + def _get_view_builder(self, req): + return limits_views.ViewBuilderV10() + + +class LimitsControllerV11(LimitsController): + def _get_view_builder(self, req): + return limits_views.ViewBuilderV11() class Limit(object): -- cgit From 2468743697faf81851bef1cafba95337dbd57153 Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Tue, 5 Apr 2011 15:55:49 -0400 Subject: add support for specifying adminPass for JSON only in openstack api 1.1 --- nova/api/openstack/servers.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 6704a68ae..c19b53b5e 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -180,7 +180,7 @@ class Controller(wsgi.Controller): builder = self._get_view_builder(req) server = builder.build(inst, is_detail=True) - password = utils.generate_password(16) + password = self._get_admin_password_from_request_server(env['server']) server['server']['adminPass'] = password self.compute_api.set_admin_password(context, server['server']['id'], password) @@ -242,6 +242,9 @@ class Controller(wsgi.Controller): # if the original error is okay, just reraise it raise error + def _get_admin_password_from_request_server(self, server): + return utils.generate_password(16) + @scheduler_api.redirect_handler def update(self, req, id): """ Updates the server name or password """ @@ -648,6 +651,12 @@ class ControllerV11(Controller): def _limit_items(self, items, req): return common.limited_by_marker(items, req) + def _get_admin_password_from_request_server(self, server): + password = server.get('adminPass') + if password: + return password + return utils.generate_password(16) + class ServerCreateRequestXMLDeserializer(object): """ -- cgit From b59f7e2b9ed0f08ac033cd839a6996a1931ccec6 Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Tue, 5 Apr 2011 16:30:30 -0400 Subject: refactor to handle invalid adminPass --- nova/api/openstack/servers.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index c19b53b5e..8f5adaad5 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -120,6 +120,11 @@ class Controller(wsgi.Controller): context = req.environ['nova.context'] + password = self._get_admin_password_from_request_server(env['server']) + if not isinstance(password, basestring) or password == '': + msg = _("Invalid adminPass") + return exc.HTTPBadRequest(msg) + key_name = None key_data = None key_pairs = auth_manager.AuthManager.get_key_pairs(context) @@ -180,7 +185,6 @@ class Controller(wsgi.Controller): builder = self._get_view_builder(req) server = builder.build(inst, is_detail=True) - password = self._get_admin_password_from_request_server(env['server']) server['server']['adminPass'] = password self.compute_api.set_admin_password(context, server['server']['id'], password) @@ -652,10 +656,7 @@ class ControllerV11(Controller): return common.limited_by_marker(items, req) def _get_admin_password_from_request_server(self, server): - password = server.get('adminPass') - if password: - return password - return utils.generate_password(16) + return server.get('adminPass', utils.generate_password(16)) class ServerCreateRequestXMLDeserializer(object): -- cgit From 7ed00acea541dc4cf3b70ecf923b649e9ee7ae11 Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Tue, 5 Apr 2011 16:46:44 -0400 Subject: move error handling down into get_password function --- nova/api/openstack/servers.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 8f5adaad5..40aca64b4 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -120,10 +120,7 @@ class Controller(wsgi.Controller): context = req.environ['nova.context'] - password = self._get_admin_password_from_request_server(env['server']) - if not isinstance(password, basestring) or password == '': - msg = _("Invalid adminPass") - return exc.HTTPBadRequest(msg) + password = self._get_server_admin_password(env['server']) key_name = None key_data = None @@ -246,7 +243,7 @@ class Controller(wsgi.Controller): # if the original error is okay, just reraise it raise error - def _get_admin_password_from_request_server(self, server): + def _get_server_admin_password(self, server): return utils.generate_password(16) @scheduler_api.redirect_handler @@ -655,8 +652,14 @@ class ControllerV11(Controller): def _limit_items(self, items, req): return common.limited_by_marker(items, req) - def _get_admin_password_from_request_server(self, server): - return server.get('adminPass', utils.generate_password(16)) + def _get_server_admin_password(self, server): + password = server.get('adminPass') + if password is None: + return utils.generate_password(16) + if not isinstance(password, basestring) or password == '': + msg = _("Invalid adminPass") + raise exc.HTTPBadRequest(msg) + return password class ServerCreateRequestXMLDeserializer(object): -- cgit From 56eb682a169c20a9a8275b3b9bfd423f0d562cbc Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Apr 2011 15:01:33 -0700 Subject: unite the filtering done by glance client and s3 --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 02a30220a..b4705820e 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -927,7 +927,7 @@ class CloudController(object): 'ari': 'ramdisk', 'ami': 'machine'} i['imageType'] = display_mapping.get(image_type) - i['isPublic'] = str(image['properties'].get('is_public', '')) == 'True' + i['isPublic'] = image.get('is_public') == True i['architecture'] = image['properties'].get('architecture') return i -- cgit From 5f414311fb581ba612cf152f3ec9983d5f39c2e4 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Apr 2011 15:45:01 -0700 Subject: fallback to status if image_state is not set --- nova/api/ec2/cloud.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index b4705820e..4e5b8bfc6 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -920,7 +920,11 @@ class CloudController(object): get('image_location'), name) else: i['imageLocation'] = image['properties'].get('image_location') - i['imageState'] = image['properties'].get('image_state') + # NOTE(vish): fallback status if image_state isn't set + state = image.get('status') + if state == 'active': + state = 'available' + i['imageState'] = image['properties'].get('image_state', state) i['displayName'] = name i['description'] = image.get('description') display_mapping = {'aki': 'kernel', -- cgit From dfcdafde2dc202aa3325cd1cea8d809f56fdde57 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Tue, 5 Apr 2011 19:21:05 -0700 Subject: return image create response as image dict --- nova/api/openstack/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index e77100d7b..e3f93f635 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -130,7 +130,7 @@ class Controller(wsgi.Controller): raise webob.exc.HTTPBadRequest() image = self._compute_service.snapshot(context, server_id, image_name) - return self.get_builder(req).build(image, detail=True) + return dict(image=self.get_builder(req).build(image, detail=True)) def get_builder(self, request): """Indicates that you must use a Controller subclass.""" -- cgit From 3e120e52fcb8fca1b97b496c618c3b9e2b459598 Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Wed, 6 Apr 2011 13:42:04 -0400 Subject: add docstrings --- nova/api/openstack/servers.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 40aca64b4..3b6d14ae1 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -244,6 +244,7 @@ class Controller(wsgi.Controller): raise error def _get_server_admin_password(self, server): + """ Determine the admin password for a server on creation """ return utils.generate_password(16) @scheduler_api.redirect_handler @@ -653,6 +654,7 @@ class ControllerV11(Controller): return common.limited_by_marker(items, req) def _get_server_admin_password(self, server): + """ Determine the admin password for a server on creation """ password = server.get('adminPass') if password is None: return utils.generate_password(16) -- cgit From cb51075ceeb17d43bd53617a3dc8a561e7608722 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 6 Apr 2011 14:31:54 -0400 Subject: Added logging statements for generic WSGI and specific OpenStack API requests. --- nova/api/openstack/auth.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index f3a9bdeca..42c23785a 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -55,6 +55,9 @@ class AuthMiddleware(wsgi.Middleware): user = self.get_user_by_authentication(req) accounts = self.auth.get_projects(user=user) if not user: + token = req.headers["X-Auth-Token"] + msg = _("%(user)s could not be found with token '%(token)s'") + LOG.warn(msg % locals()) return faults.Fault(webob.exc.HTTPUnauthorized()) if accounts: @@ -66,6 +69,8 @@ class AuthMiddleware(wsgi.Middleware): if not self.auth.is_admin(user) and \ not self.auth.is_project_member(user, account): + msg = _("%(user)s must be an admin or a member of %(account)s") + LOG.warn(msg % locals()) return faults.Fault(webob.exc.HTTPUnauthorized()) req.environ['nova.context'] = context.RequestContext(user, account) @@ -82,12 +87,15 @@ class AuthMiddleware(wsgi.Middleware): # honor it path_info = req.path_info if len(path_info) > 1: + msg = _("Authentication requests must be made against /") + LOG.warn(msg) return faults.Fault(webob.exc.HTTPUnauthorized()) try: username = req.headers['X-Auth-User'] key = req.headers['X-Auth-Key'] - except KeyError: + except KeyError as ex: + LOG.warn(_("Could not find %s in request.") % ex) return faults.Fault(webob.exc.HTTPUnauthorized()) token, user = self._authorize_user(username, key, req) @@ -100,6 +108,7 @@ class AuthMiddleware(wsgi.Middleware): res.headers['X-CDN-Management-Url'] = token.cdn_management_url res.content_type = 'text/plain' res.status = '204' + LOG.debug(_("Successfully authenticated '%s'") % username) return res else: return faults.Fault(webob.exc.HTTPUnauthorized()) @@ -139,6 +148,7 @@ class AuthMiddleware(wsgi.Middleware): try: user = self.auth.get_user_from_access_key(key) except exception.NotFound: + LOG.warn(_("User not found with provided API key.")) user = None if user and user.name == username: @@ -153,4 +163,9 @@ class AuthMiddleware(wsgi.Middleware): token_dict['user_id'] = user.id token = self.db.auth_token_create(ctxt, token_dict) return token, user + elif user and user.name != username: + msg = _("Provided API key is valid, but not for user " + "'%(username)s'") % locals() + LOG.warn(msg) + return None, None -- cgit From 5534113f65cc578dcdf93432981b836bf4e3dfaf Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 6 Apr 2011 16:12:32 -0400 Subject: Added support for listing addresses of a server in the openstack api. Now you can GET * /servers/1/ips * /servers/1/ips/public * /servers/1/ips/private Supports v1.0 json and xml. Added corresponding tests. --- nova/api/openstack/__init__.py | 6 +++ nova/api/openstack/ips.py | 71 +++++++++++++++++++++++++++++++++++ nova/api/openstack/servers.py | 9 ----- nova/api/openstack/views/addresses.py | 10 ++++- 4 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 nova/api/openstack/ips.py (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 7545eb0c9..5e76a06f7 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -34,6 +34,7 @@ from nova.api.openstack import consoles from nova.api.openstack import flavors from nova.api.openstack import images from nova.api.openstack import image_metadata +from nova.api.openstack import ips from nova.api.openstack import limits from nova.api.openstack import servers from nova.api.openstack import server_metadata @@ -144,6 +145,11 @@ class APIRouterV10(APIRouter): parent_resource=dict(member_name='server', collection_name='servers')) + mapper.resource("ip", "ips", controller=ips.Controller(), + collection=dict(public='GET', private='GET'), + parent_resource=dict(member_name='server', + collection_name='servers')) + class APIRouterV11(APIRouter): """Define routes specific to OpenStack API V1.1.""" diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py new file mode 100644 index 000000000..89b0936d5 --- /dev/null +++ b/nova/api/openstack/ips.py @@ -0,0 +1,71 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import time + +from webob import exc + +import nova +import nova.api.openstack.views.addresses +from nova.api.openstack import faults + + +class Controller(nova.wsgi.Controller): + """The servers addresses API controller for the Openstack API.""" + + _serialization_metadata = { + 'application/xml': { + 'list_collections': { + 'public': {'item_name': 'ip', 'item_key': 'addr'}, + 'private': {'item_name': 'ip', 'item_key': 'addr'}, + }, + }, + } + + def __init__(self): + self.compute_api = nova.compute.API() + self.builder = nova.api.openstack.views.addresses.ViewBuilderV10() + + def index(self, req, server_id): + try: + instance = self.compute_api.get(req.environ['nova.context'], id) + except nova.exception.NotFound: + return faults.Fault(exc.HTTPNotFound()) + return {'addresses': self.builder.build(instance)} + + def public(self, req, server_id): + try: + instance = self.compute_api.get(req.environ['nova.context'], id) + except nova.exception.NotFound: + return faults.Fault(exc.HTTPNotFound()) + return {'public': self.builder.build_public_parts(instance)} + + def private(self, req, server_id): + try: + instance = self.compute_api.get(req.environ['nova.context'], id) + except nova.exception.NotFound: + return faults.Fault(exc.HTTPNotFound()) + return {'private': self.builder.build_private_parts(instance)} + + def show(self, req, server_id, id): + return faults.Fault(exc.HTTPNotImplemented()) + + def create(self, req, server_id): + return faults.Fault(exc.HTTPNotImplemented()) + + def delete(self, req, server_id, id): + return faults.Fault(exc.HTTPNotImplemented()) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index cada92813..67e6eefd8 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -70,15 +70,6 @@ class Controller(wsgi.Controller): self._image_service = utils.import_object(FLAGS.image_service) super(Controller, self).__init__() - def ips(self, req, id): - try: - instance = self.compute_api.get(req.environ['nova.context'], id) - except exception.NotFound: - return faults.Fault(exc.HTTPNotFound()) - - builder = self._get_addresses_view_builder(req) - return builder.build(instance) - def index(self, req): """ Returns a list of server names and ids for a given user """ return self._items(req, is_detail=False) diff --git a/nova/api/openstack/views/addresses.py b/nova/api/openstack/views/addresses.py index 90c77855b..2810cce39 100644 --- a/nova/api/openstack/views/addresses.py +++ b/nova/api/openstack/views/addresses.py @@ -28,10 +28,16 @@ class ViewBuilder(object): class ViewBuilderV10(ViewBuilder): def build(self, inst): - private_ips = utils.get_from_path(inst, 'fixed_ip/address') - public_ips = utils.get_from_path(inst, 'fixed_ip/floating_ips/address') + private_ips = self.build_private_parts(inst) + public_ips = self.build_public_parts(inst) return dict(public=public_ips, private=private_ips) + def build_public_parts(self, inst): + return utils.get_from_path(inst, 'fixed_ip/floating_ips/address') + + def build_private_parts(self, inst): + return utils.get_from_path(inst, 'fixed_ip/address') + class ViewBuilderV11(ViewBuilder): def build(self, inst): -- cgit From e16571671e4baab50521870ec64e4ab954c7d165 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 6 Apr 2011 17:50:11 -0400 Subject: Controllers now inherit from nova.api.openstack.common.OpenstackController. --- nova/api/openstack/ips.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py index 89b0936d5..778e9ba1a 100644 --- a/nova/api/openstack/ips.py +++ b/nova/api/openstack/ips.py @@ -21,10 +21,11 @@ from webob import exc import nova import nova.api.openstack.views.addresses +from nova.api.openstack import common from nova.api.openstack import faults -class Controller(nova.wsgi.Controller): +class Controller(common.OpenstackController): """The servers addresses API controller for the Openstack API.""" _serialization_metadata = { -- cgit From dc8b3cb3fa124755ed3e5282b2d11a811f1db2d5 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Wed, 6 Apr 2011 15:39:44 -0700 Subject: removed comment on API compliance --- nova/api/openstack/views/servers.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index baa911590..096bf70c6 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -82,7 +82,6 @@ class ViewBuilder(object): # Return the metadata as a dictionary metadata = {} for item in inst.get('metadata', []): - # metadata values must be strings per API metadata[item['key']] = str(item['value']) inst_dict['metadata'] = metadata -- cgit From 404feb59a829e24e026f793a362e54aad1aaa03f Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Thu, 7 Apr 2011 13:55:42 -0500 Subject: Renamed computeFault to cloudServersFault --- nova/api/openstack/faults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py index bc97639a0..87118ce19 100644 --- a/nova/api/openstack/faults.py +++ b/nova/api/openstack/faults.py @@ -47,7 +47,7 @@ class Fault(webob.exc.HTTPException): """Generate a WSGI response based on the exception passed to ctor.""" # Replace the body with fault details. code = self.wrapped_exc.status_int - fault_name = self._fault_names.get(code, "computeFault") + fault_name = self._fault_names.get(code, "cloudServersFault") fault_data = { fault_name: { 'code': code, -- cgit From c7fd470d7ff0df4b23664b6599e5ae5acdb21511 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 7 Apr 2011 15:52:14 -0400 Subject: Drop extra 'None' arg from dict.get call. --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index e4bcccb2b..c3124b89d 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -731,7 +731,7 @@ class CloudController(object): instance['host']) i['productCodesSet'] = self._convert_to_set([], 'product_codes') if instance['instance_type']: - i['instanceType'] = instance['instance_type'].get('name', None) + i['instanceType'] = instance['instance_type'].get('name') else: i['instanceType'] = None i['launchTime'] = instance['created_at'] -- cgit From 7badb6c0278c8cc51fc3e870fd3810ea3706f494 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 7 Apr 2011 23:39:29 -0400 Subject: Update the describe_image_attribute and modify_image_attribute functions in the ec2 API so they use the top level 'is_public' attribute of image objects. This brings these functions in line with the base image service. Added missing EC2 unit tests on describing and modifying image attributes. --- nova/api/ec2/cloud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4ed8a9ecf..651ec47f9 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -984,7 +984,7 @@ class CloudController(object): except exception.NotFound: raise exception.NotFound(_('Image %s not found') % image_id) result = {'imageId': image_id, 'launchPermission': []} - if image['properties']['is_public']: + if image['is_public']: result['launchPermission'].append({'group': 'all'}) return result @@ -1009,7 +1009,7 @@ class CloudController(object): internal_id = image['id'] del(image['id']) - image['properties']['is_public'] = (operation_type == 'add') + image['is_public'] = (operation_type == 'add') return self.image_service.update(context, internal_id, image) def update_image(self, context, image_id, **kwargs): -- cgit From 5752838917237e7b86a64117f46c71d1c2a356f3 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 11 Apr 2011 16:18:18 +0200 Subject: Replace instance ref from compute.api.get_all with one from instance_get. This should ensure it gets fully populated with all the relevant attributes. --- nova/api/ec2/cloud.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 651ec47f9..83c894bea 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -142,6 +142,11 @@ class CloudController(object): instance_ref = self.compute_api.get_all(ctxt, fixed_ip=address) if instance_ref is None: return None + + # This ensures that all attributes of the instance + # are populated. + instance_ref = db.instance_get(ctxt, instance_ref['id']) + mpi = self._get_mpi_data(ctxt, instance_ref['project_id']) if instance_ref['key_name']: keys = {'0': {'_name': instance_ref['key_name'], -- cgit From 6ac2b25d77ea71be0f9232b5502a75f255a6b2ec Mon Sep 17 00:00:00 2001 From: termie Date: Mon, 11 Apr 2011 11:34:19 -0500 Subject: docstring cleanup, direct api, part of compute --- nova/api/__init__.py | 2 -- nova/api/direct.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/__init__.py b/nova/api/__init__.py index 0fedbbfad..747015af5 100644 --- a/nova/api/__init__.py +++ b/nova/api/__init__.py @@ -15,5 +15,3 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. - -"""No-op __init__ for directory full of api goodies.""" diff --git a/nova/api/direct.py b/nova/api/direct.py index f487df7c7..8ceae299c 100644 --- a/nova/api/direct.py +++ b/nova/api/direct.py @@ -44,14 +44,33 @@ from nova import utils from nova import wsgi +# Global storage for registering modules. ROUTES = {} def register_service(path, handle): + """Register a service handle at a given path. + + Services registered in this way will be made available to any instances of + nova.api.direct.Router. + + :param path: `routes` path, can be a basic string like "/path" + :param handle: an object whose methods will be made available via the api + + """ ROUTES[path] = handle class Router(wsgi.Router): + """A simple WSGI router configured via `register_service`. + + This is a quick way to attach multiple services to a given endpoint. + It will automatically load the routes registered in the `ROUTES` global. + + TODO(termie): provide a paste-deploy version of this. + + """ + def __init__(self, mapper=None): if mapper is None: mapper = routes.Mapper() @@ -66,6 +85,24 @@ class Router(wsgi.Router): class DelegatedAuthMiddleware(wsgi.Middleware): + """A simple and naive authentication middleware. + + Designed mostly to provide basic support for alternative authentication + schemes, this middleware only desires the identity of the user and will + generate the appropriate nova.context.RequestContext for the rest of the + application. This allows any middleware above it in the stack to + authenticate however it would like while only needing to conform to a + minimal interface. + + Expects two headers to determine identity: + - X-OpenStack-User + - X-OpenStack-Project + + This middleware is tied to identity management and will need to be kept + in sync with any changes to the way identity is dealt with internally. + + """ + def process_request(self, request): os_user = request.headers['X-OpenStack-User'] os_project = request.headers['X-OpenStack-Project'] @@ -74,6 +111,20 @@ class DelegatedAuthMiddleware(wsgi.Middleware): class JsonParamsMiddleware(wsgi.Middleware): + """Middleware to allow method arguments to be passed as serialized JSON. + + Accepting arguments as JSON is useful for accepting data that may be more + complex than simple primitives. + + In this case we accept it as urlencoded data under the key 'json' as in + json= but this could be extended to accept raw JSON + in the POST body. + + Filters out the parameters `self`, `context` and anything beginning with + an underscore. + + """ + def process_request(self, request): if 'json' not in request.params: return @@ -92,6 +143,13 @@ class JsonParamsMiddleware(wsgi.Middleware): class PostParamsMiddleware(wsgi.Middleware): + """Middleware to allow method arguments to be passed as POST parameters. + + Filters out the parameters `self`, `context` and anything beginning with + an underscore. + + """ + def process_request(self, request): params_parsed = request.params params = {} @@ -106,12 +164,21 @@ class PostParamsMiddleware(wsgi.Middleware): class Reflection(object): - """Reflection methods to list available methods.""" + """Reflection methods to list available methods. + + This is an object that expects to be registered via register_service. + These methods allow the endpoint to be self-describing. They introspect + the exposed methods and provide call signatures and documentation for + them allowing quick experimentation. + + """ + def __init__(self): self._methods = {} self._controllers = {} def _gather_methods(self): + """Introspect available methods and generate documentation for them.""" methods = {} controllers = {} for route, handler in ROUTES.iteritems(): @@ -185,6 +252,16 @@ class Reflection(object): class ServiceWrapper(wsgi.Controller): + """Wrapper to dynamically povide a WSGI controller for arbitrary objects. + + With lightweight introspection allows public methods on the object to + be accesed via simple WSGI routing and parameters and serializes the + return values. + + Automatically used be nova.api.direct.Router to wrap registered instances. + + """ + def __init__(self, service_handle): self.service_handle = service_handle @@ -260,7 +337,16 @@ class Limited(object): class Proxy(object): - """Pretend a Direct API endpoint is an object.""" + """Pretend a Direct API endpoint is an object. + + This is mostly useful in testing at the moment though it should be easily + extendable to provide a basic API library functionality. + + In testing we use this to stub out internal objects to verify that results + from the API are serializable. + + """ + def __init__(self, app, prefix=None): self.app = app self.prefix = prefix -- cgit From 07c1f30225fb27cbc8e7cfeebc6a73ec67a7f2e5 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 12 Apr 2011 09:41:42 +0200 Subject: pep8 --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 83c894bea..5e81878c4 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -144,7 +144,7 @@ class CloudController(object): return None # This ensures that all attributes of the instance - # are populated. + # are populated. instance_ref = db.instance_get(ctxt, instance_ref['id']) mpi = self._get_mpi_data(ctxt, instance_ref['project_id']) -- cgit From cebc98176926f57016a508d5c59b11f55dfcf2b3 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 12 Apr 2011 10:19:37 -0400 Subject: Commit for merge of metadata_quotas preq. --- nova/api/openstack/servers.py | 103 ++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 30 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index c9f0e1b1c..61e08211d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -606,22 +606,32 @@ class ControllerV10(Controller): except exception.TimeoutException: return exc.HTTPRequestTimeout() - def _action_rebuild(self, input_dict, req, id): - context = req.environ['nova.context'] - if (not 'rebuild' in input_dict - or not 'imageId' in input_dict['rebuild']): - msg = _("No imageId was specified") - return faults.Fault(exc.HTTPBadRequest(msg)) + def _action_rebuild(self, info, request, instance_id): + context = request.environ['nova.context'] + instance_id = int(instance_id) - image_id = input_dict['rebuild']['imageId'] + try: + image_id = info["rebuild"]["imageId"] + except (KeyError, TypeError): + msg = _("Could not parse imageId from request.") + LOG.debug(msg) + return faults.Fault(exc.HTTPBadRequest(explanation=msg)) try: - self.compute_api.rebuild(context, id, image_id) + self.compute_api.rebuild(context, instance_id, image_id) except exception.BuildInProgress: - msg = _("Unable to rebuild server that is being rebuilt") + msg = _("Instance %d is currently being rebuilt.") % instance_id + LOG.debug(msg) return faults.Fault(exc.HTTPConflict(explanation=msg)) + except exception.Error as ex: + msg = _("Error encountered attempting to rebuild instance " + "%(instance_id): %(ex)") % locals() + LOG.error(msg) + raise - return exc.HTTPAccepted() + response = exc.HTTPAccepted() + response.empty_body = True + return response class ControllerV11(Controller): @@ -662,33 +672,66 @@ class ControllerV11(Controller): def _limit_items(self, items, req): return common.limited_by_marker(items, req) - def _action_rebuild(self, input_dict, req, id): - context = req.environ['nova.context'] - if (not 'rebuild' in input_dict - or not 'imageRef' in input_dict['rebuild']): - msg = _("No imageRef was specified") - return faults.Fault(exc.HTTPBadRequest(msg)) - - image_ref = input_dict['rebuild']['imageRef'] - image_id = common.get_id_from_href(image_ref) + def _check_metadata(self, metadata): + """Ensure that the metadata given is of the correct type.""" + try: + metadata.iteritems() + except AttributeError as ex: + msg = _("Unable to parse metadata key/value pairs.") + LOG.debug(msg) + raise faults.Fault(exc.HTTPBadRequest(explanation=msg)) + + def _check_personalities(self, personalities): + """Ensure the given personalities have valid paths and contents.""" + for personality in personalities: + try: + path = personality["path"] + contents = personality["contents"] + except (KeyError, TypeError): + msg = _("Unable to parse personality path/contents.") + LOG.info(msg) + raise faults.Fault(exc.HTTPBadRequest(explanation=msg)) - metadata = [] - if 'metadata' in input_dict['rebuild']: try: - for k, v in input_dict['rebuild']['metadata'].items(): - metadata.append({'key': k, 'value': v}) + base64.b64decode(contents) + except TypeError: + msg = _("Personality content could not be Base64 decoded.") + LOG.info(msg) + raise faults.Fault(exc.HTTPBadRequest(explanation=msg)) + + def _action_rebuild(self, info, request, instance_id): + context = request.environ['nova.context'] + instance_id = int(instance_id) + + try: + image_ref = info["rebuild"]["imageRef"] + except (KeyError, TypeError): + msg = _("Could not parse imageRef from request.") + return faults.Fault(exc.HTTPBadRequest(explanation=msg)) - except Exception: - msg = _("Improperly formatted metadata provided") - return exc.HTTPBadRequest(msg) + image_id = common.get_id_from_href(image_ref) + personalities = info["rebuild"].get("personality", []) + metadata = info["rebuild"].get("metadata", {}) + + self._check_metadata(metadata) + self._check_personalities(personalities) try: - self.compute_api.rebuild(context, id, image_id, metadata) + args = [context, instance_id, image_id, metadata, personalities] + self.compute_api.rebuild(*args) except exception.BuildInProgress: - msg = _("Unable to rebuild server that is being rebuilt") + msg = _("Instance %d is currently being rebuilt.") % instance_id + LOG.debug(msg) return faults.Fault(exc.HTTPConflict(explanation=msg)) - - return exc.HTTPAccepted() + except exception.Error as ex: + msg = _("Error encountered attempting to rebuild instance " + "%(instance_id): %(ex)") % locals() + LOG.error(msg) + raise + + response = exc.HTTPAccepted() + response.empty_body = True + return response def get_default_xmlns(self, req): return common.XML_NS_V11 -- cgit From baa129773c41f143237db992d90e1c681b3d33f8 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 12 Apr 2011 13:47:45 -0400 Subject: dots. --- nova/api/openstack/server_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/server_metadata.py b/nova/api/openstack/server_metadata.py index 01ca79eec..fd64ee4fb 100644 --- a/nova/api/openstack/server_metadata.py +++ b/nova/api/openstack/server_metadata.py @@ -88,7 +88,7 @@ class Controller(common.OpenstackController): self.compute_api.delete_instance_metadata(context, server_id, id) def _handle_quota_error(self, error): - """Reraise quota errors as api-specific http exceptions""" + """Reraise quota errors as api-specific http exceptions.""" if error.code == "MetadataLimitExceeded": raise exc.HTTPBadRequest(explanation=error.message) raise error -- cgit From 76bb9f42c6cc39218824332e396dca4a5e6ec351 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 12 Apr 2011 18:43:49 +0000 Subject: fix show_by_name in s3.py and give a helpful error message if image lookup fails --- nova/api/ec2/cloud.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 5e81878c4..10b1d0ac5 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -908,7 +908,10 @@ class CloudController(object): internal_id = ec2utils.ec2_id_to_id(ec2_id) return self.image_service.show(context, internal_id) except exception.NotFound: - return self.image_service.show_by_name(context, ec2_id) + try: + return self.image_service.show_by_name(context, ec2_id) + except exception.NotFound: + raise exception.NotFound(_('Image %s not found') % ec2_id) def _format_image(self, image): """Convert from format defined by BaseImageService to S3 format.""" -- cgit From 4b0785632ba626d34a8a9fae5e0a5c742660e2dc Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 14 Apr 2011 17:34:09 -0400 Subject: initial roundup of all 'exception.Invalid' cases --- nova/api/openstack/servers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 43e0c7963..2332b1af7 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -561,9 +561,7 @@ class Controller(common.OpenstackController): """ image_id = image_meta['id'] if image_meta['status'] != 'active': - raise exception.Invalid( - _("Cannot build from image %(image_id)s, status not active") % - locals()) + raise exception.InstanceNotRunning(image_id=image_id) if image_meta.get('container_format') != 'ami': return None, None -- cgit From ad138a5a50868531f34ba358600f1270588ce80b Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 15 Apr 2011 14:24:17 -0400 Subject: correcting tests; pep8 --- nova/api/openstack/servers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 2332b1af7..1cb42355a 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -561,7 +561,8 @@ class Controller(common.OpenstackController): """ image_id = image_meta['id'] if image_meta['status'] != 'active': - raise exception.InstanceNotRunning(image_id=image_id) + raise exception.ImageUnacceptable(image_id=image_id, + reason=_("status is not active")) if image_meta.get('container_format') != 'ami': return None, None -- cgit From b571bf6bb329e3bb085987554461c411ef56b330 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Fri, 15 Apr 2011 15:01:17 -0400 Subject: Explicitly tell a user that they need to authenticate against a version root. --- nova/api/openstack/auth.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index 42c23785a..311e6bde9 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -87,9 +87,10 @@ class AuthMiddleware(wsgi.Middleware): # honor it path_info = req.path_info if len(path_info) > 1: - msg = _("Authentication requests must be made against /") + msg = _("Authentication requests must be made against a version " + "root (e.g. /v1.0 or /v1.1).") LOG.warn(msg) - return faults.Fault(webob.exc.HTTPUnauthorized()) + return faults.Fault(webob.exc.HTTPUnauthorized(explanation=msg)) try: username = req.headers['X-Auth-User'] -- cgit From c49c372ec3e94331eb8a16a0af7c9c9c5e46bba0 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 18 Apr 2011 17:06:18 +0400 Subject: Fix logging in openstack api --- nova/api/openstack/common.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 234f921ab..2ace9b3de 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -25,7 +25,7 @@ from nova import log as logging from nova import wsgi -LOG = logging.getLogger('common') +LOG = logging.getLogger('nova.api.openstack.common') FLAGS = flags.FLAGS @@ -116,8 +116,14 @@ def get_image_id_from_image_hash(image_service, context, image_hash): items = image_service.index(context) for image in items: image_id = image['id'] - if abs(hash(image_id)) == int(image_hash): - return image_id + try: + if abs(hash(image_id)) == int(image_hash): + return image_id + except ValueError: + msg = _("Requested image_id has wrong format: %s," + "should have numerical format" % image_id) + LOG.error(msg) + raise msg raise exception.NotFound(image_hash) -- cgit From a582afce13286160411a65d4b1b91e69f67ab430 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 18 Apr 2011 17:31:29 +0400 Subject: Fix logging in openstack api --- nova/api/openstack/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 2ace9b3de..f3f7f6d9b 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -121,7 +121,7 @@ def get_image_id_from_image_hash(image_service, context, image_hash): return image_id except ValueError: msg = _("Requested image_id has wrong format: %s," - "should have numerical format" % image_id) + "should have numerical format") % image_id LOG.error(msg) raise msg raise exception.NotFound(image_hash) -- cgit From d1a7cf94f368e0c115bd7680512c582163f5e49e Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 18 Apr 2011 17:32:48 +0400 Subject: Fix logging in openstack api --- nova/api/openstack/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index f3f7f6d9b..0b6dc944a 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -123,7 +123,7 @@ def get_image_id_from_image_hash(image_service, context, image_hash): msg = _("Requested image_id has wrong format: %s," "should have numerical format") % image_id LOG.error(msg) - raise msg + raise Exception(msg) raise exception.NotFound(image_hash) -- cgit From fe2d43472548f7c32a621ab4f245e078d0f46f0b Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 18 Apr 2011 18:13:56 +0400 Subject: add fault as response --- nova/api/openstack/servers.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 43e0c7963..4fb0f078b 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -127,8 +127,13 @@ class Controller(common.OpenstackController): key_data = key_pair['public_key'] requested_image_id = self._image_id_from_req_data(env) - image_id = common.get_image_id_from_image_hash(self._image_service, - context, requested_image_id) + try: + image_id = common.get_image_id_from_image_hash(self._image_service, + context, requested_image_id) + except: + msg = _("Can not find requested image") + return faults.Fault(exc.HTTPBadRequest(msg)) + kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image( req, image_id) -- cgit From c8ca373cfc71cf62d79ff90957961e9b0aa2ed36 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 18 Apr 2011 19:36:19 +0400 Subject: pep8 fix --- nova/api/openstack/servers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4fb0f078b..d3f51df0d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -133,7 +133,7 @@ class Controller(common.OpenstackController): except: msg = _("Can not find requested image") return faults.Fault(exc.HTTPBadRequest(msg)) - + kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image( req, image_id) -- cgit From eb20dd53832577f94f5f251bd97e866435f6aeb9 Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Mon, 18 Apr 2011 15:40:16 -0500 Subject: Change '== None' to 'is None' --- nova/api/ec2/cloud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 10b1d0ac5..bd4c9dcd4 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -442,7 +442,7 @@ class CloudController(object): group_name) criteria = self._revoke_rule_args_to_dict(context, **kwargs) - if criteria == None: + if criteria is None: raise exception.ApiError(_("Not enough parameters to build a " "valid rule.")) @@ -664,7 +664,7 @@ class CloudController(object): 'volumeId': ec2utils.id_to_ec2_id(volume_id, 'vol-%08x')} def _convert_to_set(self, lst, label): - if lst == None or lst == []: + if lst is None or lst == []: return None if not isinstance(lst, list): lst = [lst] -- cgit From 65ca5ba31f2c5ecea05290390ad66e65543aa83d Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Mon, 18 Apr 2011 15:49:06 -0500 Subject: pep8 fixes --- nova/api/openstack/contrib/volumes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/volumes.py b/nova/api/openstack/contrib/volumes.py index 6efacce52..18de2ec71 100644 --- a/nova/api/openstack/contrib/volumes.py +++ b/nova/api/openstack/contrib/volumes.py @@ -322,8 +322,7 @@ class Volumes(extensions.ExtensionDescriptor): # Does this matter? res = extensions.ResourceExtension('volumes', VolumeController(), - collection_actions={'detail': 'GET'} - ) + collection_actions={'detail': 'GET'}) resources.append(res) res = extensions.ResourceExtension('volume_attachments', -- cgit From f59f792c83c7f18e48903165df8d3dd78f45dd4c Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Mon, 18 Apr 2011 15:53:09 -0500 Subject: use 'is not None' instead of '!= None' --- nova/api/ec2/apirequest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/apirequest.py b/nova/api/ec2/apirequest.py index d7ad08d2f..6672e60bb 100644 --- a/nova/api/ec2/apirequest.py +++ b/nova/api/ec2/apirequest.py @@ -196,7 +196,7 @@ class APIRequest(object): elif isinstance(data, datetime.datetime): data_el.appendChild( xml.createTextNode(_database_to_isoformat(data))) - elif data != None: + elif data is not None: data_el.appendChild(xml.createTextNode(str(data))) return data_el -- cgit From 745351d1e2a98a98de0a5f955385a92c01110684 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 09:19:52 -0700 Subject: Fixes cloudpipe to get the proper ip address. * Changes FLAGS.vpn_image_id to integer * Converts to str when comparing because instance['image_id'] is a str * Removes unused method from db * Converts integer_id to ami when launching * Adds docs for setting up interface in cloudpipe image --- nova/api/ec2/admin.py | 2 +- nova/api/ec2/cloud.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py index 6a5609d4a..ea94d9c1f 100644 --- a/nova/api/ec2/admin.py +++ b/nova/api/ec2/admin.py @@ -266,7 +266,7 @@ class AdminController(object): def _vpn_for(self, context, project_id): """Get the VPN instance for a project ID.""" for instance in db.instance_get_all_by_project(context, project_id): - if (instance['image_id'] == FLAGS.vpn_image_id + if (instance['image_id'] == str(FLAGS.vpn_image_id) and not instance['state_description'] in ['shutting_down', 'shutdown']): return instance diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 10b1d0ac5..d9c1af072 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -703,7 +703,7 @@ class CloudController(object): instances = self.compute_api.get_all(context, **kwargs) for instance in instances: if not context.is_admin: - if instance['image_id'] == FLAGS.vpn_image_id: + if instance['image_id'] == str(FLAGS.vpn_image_id): continue i = {} instance_id = instance['id'] @@ -898,7 +898,7 @@ class CloudController(object): return image_type @staticmethod - def _image_ec2_id(image_id, image_type='ami'): + def image_ec2_id(image_id, image_type='ami'): """Returns image ec2_id using id and three letter type.""" template = image_type + '-%08x' return ec2utils.id_to_ec2_id(int(image_id), template=template) -- cgit From c3a45962a322086e4d7339f980bcf61ee8bd3167 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 09:38:01 -0700 Subject: rename all versions of image_ec2_id --- nova/api/ec2/cloud.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index d9c1af072..c48ec9004 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -159,7 +159,7 @@ class CloudController(object): floating_ip = db.instance_get_floating_address(ctxt, instance_ref['id']) ec2_id = ec2utils.id_to_ec2_id(instance_ref['id']) - image_ec2_id = self._image_ec2_id(instance_ref['image_id'], 'ami') + image_ec2_id = self.image_ec2_id(instance_ref['image_id']) data = { 'user-data': base64.b64decode(instance_ref['user_data']), 'meta-data': { @@ -188,8 +188,8 @@ class CloudController(object): for image_type in ['kernel', 'ramdisk']: if '%s_id' % image_type in instance_ref: - ec2_id = self._image_ec2_id(instance_ref['%s_id' % image_type], - self._image_type(image_type)) + ec2_id = self.image_ec2_id(instance_ref['%s_id' % image_type], + self._image_type(image_type)) data['meta-data']['%s-id' % image_type] = ec2_id if False: # TODO(vish): store ancestor ids @@ -709,7 +709,7 @@ class CloudController(object): instance_id = instance['id'] ec2_id = ec2utils.id_to_ec2_id(instance_id) i['instanceId'] = ec2_id - i['imageId'] = self._image_ec2_id(instance['image_id']) + i['imageId'] = self.image_ec2_id(instance['image_id']) i['instanceState'] = { 'code': instance['state'], 'name': instance['state_description']} @@ -917,15 +917,15 @@ class CloudController(object): """Convert from format defined by BaseImageService to S3 format.""" i = {} image_type = self._image_type(image.get('container_format')) - ec2_id = self._image_ec2_id(image.get('id'), image_type) + ec2_id = self.image_ec2_id(image.get('id'), image_type) name = image.get('name') i['imageId'] = ec2_id kernel_id = image['properties'].get('kernel_id') if kernel_id: - i['kernelId'] = self._image_ec2_id(kernel_id, 'aki') + i['kernelId'] = self.image_ec2_id(kernel_id, 'aki') ramdisk_id = image['properties'].get('ramdisk_id') if ramdisk_id: - i['ramdiskId'] = self._image_ec2_id(ramdisk_id, 'ari') + i['ramdiskId'] = self.image_ec2_id(ramdisk_id, 'ari') i['imageOwnerId'] = image['properties'].get('owner_id') if name: i['imageLocation'] = "%s (%s)" % (image['properties']. @@ -976,8 +976,8 @@ class CloudController(object): metadata = {'properties': {'image_location': image_location}} image = self.image_service.create(context, metadata) image_type = self._image_type(image.get('container_format')) - image_id = self._image_ec2_id(image['id'], - image_type) + image_id = self.image_ec2_id(image['id'], + image_type) msg = _("Registered image %(image_location)s with" " id %(image_id)s") % locals() LOG.audit(msg, context=context) -- cgit From 1378b117b7ea2bb05219b5a0e48f4b1ae8cac9ae Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 19 Apr 2011 13:17:21 -0400 Subject: refactoring usage of exception.Duplicate errors --- nova/api/ec2/cloud.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bd4c9dcd4..0bbfa0ea6 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -61,8 +61,7 @@ def _gen_key(context, user_id, key_name): # creation before creating key_pair try: db.key_pair_get(context, user_id, key_name) - raise exception.Duplicate(_("The key_pair %s already exists") - % key_name) + raise exception.KeyPairExists(key_name=key_name) except exception.NotFound: pass private_key, public_key, fingerprint = crypto.generate_key_pair() -- cgit From ccf9b2ccb41b1e7f946f2b2c21e6f8fbc9bd04e8 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Tue, 19 Apr 2011 21:25:53 +0400 Subject: fix logging in reboot OpenStack API --- nova/api/openstack/servers.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index f221229f0..e9f570213 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -40,7 +40,7 @@ import nova.api.openstack from nova.scheduler import api as scheduler_api -LOG = logging.getLogger('server') +LOG = logging.getLogger('nova.api.openstack.servers') FLAGS = flags.FLAGS @@ -331,6 +331,7 @@ class Controller(common.OpenstackController): return exc.HTTPAccepted() def _action_rebuild(self, input_dict, req, id): + LOG.debug(_("Rebuild server action is not implemented")) return faults.Fault(exc.HTTPNotImplemented()) def _action_resize(self, input_dict, req, id): @@ -346,18 +347,20 @@ class Controller(common.OpenstackController): except Exception, e: LOG.exception(_("Error in resize %s"), e) return faults.Fault(exc.HTTPBadRequest()) - return faults.Fault(exc.HTTPAccepted()) + return exc.HTTPAccepted() def _action_reboot(self, input_dict, req, id): - try: + if 'reboot' in input_dict and 'type' in input_dict['reboot']: reboot_type = input_dict['reboot']['type'] - except Exception: - raise faults.Fault(exc.HTTPNotImplemented()) + else: + LOG.exception(_("Missing argument 'type' for reboot")) + return faults.Fault(exc.HTTPUnprocessableEntity()) try: # TODO(gundlach): pass reboot_type, support soft reboot in # virt driver self.compute_api.reboot(req.environ['nova.context'], id) - except: + except Exception, e: + LOG.exception(_("Error in reboot %s"), e) return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() -- cgit From d992fbbde7c8e5274d80e2fce9c840e7209c78c6 Mon Sep 17 00:00:00 2001 From: Jimmy Bergman Date: Wed, 20 Apr 2011 14:06:23 +0200 Subject: Change response format of CreateVolume to match EC2 --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bd4c9dcd4..2bbe4c368 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -613,7 +613,7 @@ class CloudController(object): # TODO(vish): Instance should be None at db layer instead of # trying to lazy load, but for now we turn it into # a dict to avoid an error. - return {'volumeSet': [self._format_volume(context, dict(volume))]} + return self._format_volume(context, dict(volume)) def delete_volume(self, context, volume_id, **kwargs): volume_id = ec2utils.ec2_id_to_id(volume_id) -- cgit From 7d8698ad551b756a9dfc7058e6d836de65a64945 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 20 Apr 2011 16:21:37 -0700 Subject: in doesn't work properly on instance_ref --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bd4c9dcd4..4785d812a 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -187,7 +187,7 @@ class CloudController(object): 'mpi': mpi}} for image_type in ['kernel', 'ramdisk']: - if '%s_id' % image_type in instance_ref: + if instance_ref.get('%s_id' % image_type): ec2_id = self._image_ec2_id(instance_ref['%s_id' % image_type], self._image_type(image_type)) data['meta-data']['%s-id' % image_type] = ec2_id -- cgit From ea11033935192ee26ea6d0d0dad47a0a624b17a0 Mon Sep 17 00:00:00 2001 From: Jimmy Bergman Date: Thu, 21 Apr 2011 15:23:36 +0200 Subject: Add privateIpAddress and ipAddress to EC2 API DescribeInstances response. --- nova/api/ec2/cloud.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4785d812a..4aa973290 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -726,7 +726,9 @@ class CloudController(object): instance['mac_address']) i['privateDnsName'] = fixed_addr + i['privateIpAddress'] = fixed_addr i['publicDnsName'] = floating_addr + i['ipAddress'] = floating_addr or fixed_addr i['dnsName'] = i['publicDnsName'] or i['privateDnsName'] i['keyName'] = instance['key_name'] -- cgit From 9cb5c0113d67a306a6c85ed6f6fd7f353cc95c7c Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 21 Apr 2011 14:12:54 -0400 Subject: Modified instance status for shutdown power state in OS api --- nova/api/openstack/views/servers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index e52bfaea3..f2d8d5720 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -63,7 +63,7 @@ class ViewBuilder(object): power_state.BLOCKED: 'ACTIVE', power_state.SUSPENDED: 'SUSPENDED', power_state.PAUSED: 'PAUSED', - power_state.SHUTDOWN: 'ACTIVE', + power_state.SHUTDOWN: 'INACTIVE', power_state.SHUTOFF: 'ACTIVE', power_state.CRASHED: 'ERROR', power_state.FAILED: 'ERROR'} -- cgit From 14e7200272e70ead7fe973e3cf2b20811ccf8377 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 21 Apr 2011 12:09:36 -0700 Subject: updated image builder and tests for OS API 1.1 compatibility (serverRef) --- nova/api/openstack/views/images.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 9dec8a355..ab9a9d294 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -87,7 +87,6 @@ class ViewBuilderV10(ViewBuilder): """OpenStack API v1.0 Image Builder""" pass - class ViewBuilderV11(ViewBuilder): """OpenStack API v1.1 Image Builder""" @@ -95,6 +94,9 @@ class ViewBuilderV11(ViewBuilder): """Return a standardized image structure for display by the API.""" image = ViewBuilder.build(self, image_obj, detail) href = self.generate_href(image_obj["id"]) + if "serverId" in image: + image["serverRef"] = image["serverId"] + del image["serverId"] image["links"] = [{ "rel": "self", -- cgit From 8681db3aa9104f97a84a3323b102ed10af269888 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 21 Apr 2011 15:50:04 -0400 Subject: Addressing exception.NotFound across the project --- nova/api/ec2/__init__.py | 4 +--- nova/api/ec2/cloud.py | 11 +++++------ nova/api/ec2/ec2utils.py | 5 +---- nova/api/openstack/common.py | 2 +- nova/api/openstack/servers.py | 6 ++---- 5 files changed, 10 insertions(+), 18 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index a3c3b25a1..e18e7f05e 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -322,9 +322,7 @@ class Executor(wsgi.Application): except exception.InstanceNotFound as ex: LOG.info(_('InstanceNotFound raised: %s'), unicode(ex), context=context) - ec2_id = ec2utils.id_to_ec2_id(ex.instance_id) - message = _('Instance %s not found') % ec2_id - return self._error(req, context, type(ex).__name__, message) + return self._error(req, context, type(ex).__name__, ex.message) except exception.VolumeNotFound as ex: LOG.info(_('VolumeNotFound raised: %s'), unicode(ex), context=context) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bd4c9dcd4..abd668ca4 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -907,11 +907,11 @@ class CloudController(object): try: internal_id = ec2utils.ec2_id_to_id(ec2_id) return self.image_service.show(context, internal_id) - except exception.NotFound: + except ValueError: try: return self.image_service.show_by_name(context, ec2_id) except exception.NotFound: - raise exception.NotFound(_('Image %s not found') % ec2_id) + raise exception.ImageNotFound(image_id=ec2_id) def _format_image(self, image): """Convert from format defined by BaseImageService to S3 format.""" @@ -955,8 +955,7 @@ class CloudController(object): try: image = self._get_image(context, ec2_id) except exception.NotFound: - raise exception.NotFound(_('Image %s not found') % - ec2_id) + raise exception.ImageNotFound(image_id=ec2_id) images.append(image) else: images = self.image_service.detail(context) @@ -990,7 +989,7 @@ class CloudController(object): try: image = self._get_image(context, image_id) except exception.NotFound: - raise exception.NotFound(_('Image %s not found') % image_id) + raise exception.ImageNotFound(image_id=image_id) result = {'imageId': image_id, 'launchPermission': []} if image['is_public']: result['launchPermission'].append({'group': 'all'}) @@ -1013,7 +1012,7 @@ class CloudController(object): try: image = self._get_image(context, image_id) except exception.NotFound: - raise exception.NotFound(_('Image %s not found') % image_id) + raise exception.ImageNotFound(image_id=image_id) internal_id = image['id'] del(image['id']) diff --git a/nova/api/ec2/ec2utils.py b/nova/api/ec2/ec2utils.py index 3b34f6ea5..1ac48163c 100644 --- a/nova/api/ec2/ec2utils.py +++ b/nova/api/ec2/ec2utils.py @@ -21,10 +21,7 @@ from nova import exception def ec2_id_to_id(ec2_id): """Convert an ec2 ID (i-[base 16 number]) to an instance id (int)""" - try: - return int(ec2_id.split('-')[-1], 16) - except ValueError: - raise exception.NotFound(_("Id %s Not Found") % ec2_id) + return int(ec2_id.split('-')[-1], 16) def id_to_ec2_id(instance_id, template='i-%08x'): diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 0b6dc944a..65ed1e143 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -124,7 +124,7 @@ def get_image_id_from_image_hash(image_service, context, image_hash): "should have numerical format") % image_id LOG.error(msg) raise Exception(msg) - raise exception.NotFound(image_hash) + raise exception.ImageNotFound(image_id=image_hash) def get_id_from_href(href): diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 2ccc6d1db..763b021a8 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -570,14 +570,12 @@ class Controller(common.OpenstackController): try: kernel_id = image_meta['properties']['kernel_id'] except KeyError: - raise exception.NotFound( - _("Kernel not found for image %(image_id)s") % locals()) + raise exception.KernelNotFoundForImage(image_id=image_id) try: ramdisk_id = image_meta['properties']['ramdisk_id'] except KeyError: - raise exception.NotFound( - _("Ramdisk not found for image %(image_id)s") % locals()) + raise exception.RamdiskNotFoundForImage(image_id=image_id) return kernel_id, ramdisk_id -- cgit From c8bf0d217ba3601dfccff32c56fef1565d90d262 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 21 Apr 2011 13:02:33 -0700 Subject: pep8 --- nova/api/openstack/views/images.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova/api') diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index ab9a9d294..3c98599b4 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -87,6 +87,7 @@ class ViewBuilderV10(ViewBuilder): """OpenStack API v1.0 Image Builder""" pass + class ViewBuilderV11(ViewBuilder): """OpenStack API v1.1 Image Builder""" -- cgit From 6c037c5c639249556fcadd871d8af91760b50e90 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Thu, 21 Apr 2011 16:17:16 -0400 Subject: Fixes and reworkings based on review. --- nova/api/openstack/servers.py | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 357a279ef..a7e240917 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -623,11 +623,6 @@ class ControllerV10(Controller): msg = _("Instance %d is currently being rebuilt.") % instance_id LOG.debug(msg) return faults.Fault(exc.HTTPConflict(explanation=msg)) - except exception.Error as ex: - msg = _("Error encountered attempting to rebuild instance " - "%(instance_id): %(ex)") % locals() - LOG.error(msg) - raise response = exc.HTTPAccepted() response.empty_body = True @@ -672,8 +667,8 @@ class ControllerV11(Controller): def _limit_items(self, items, req): return common.limited_by_marker(items, req) - def _check_metadata(self, metadata): - """Ensure that the metadata given is of the correct type.""" + def _validate_metadata(self, metadata): + """Ensure that we can work with the metadata given.""" try: metadata.iteritems() except AttributeError as ex: @@ -681,8 +676,8 @@ class ControllerV11(Controller): LOG.debug(msg) raise faults.Fault(exc.HTTPBadRequest(explanation=msg)) - def _check_personalities(self, personalities): - """Ensure the given personalities have valid paths and contents.""" + def _decode_personalities(self, personalities): + """Decode the Base64-encoded personalities.""" for personality in personalities: try: path = personality["path"] @@ -693,7 +688,7 @@ class ControllerV11(Controller): raise faults.Fault(exc.HTTPBadRequest(explanation=msg)) try: - base64.b64decode(contents) + personality["contents"] = base64.b64decode(contents) except TypeError: msg = _("Personality content could not be Base64 decoded.") LOG.info(msg) @@ -713,21 +708,16 @@ class ControllerV11(Controller): personalities = info["rebuild"].get("personality", []) metadata = info["rebuild"].get("metadata", {}) - self._check_metadata(metadata) - self._check_personalities(personalities) + self._validate_metadata(metadata) + self._decode_personalities(personalities) try: - args = [context, instance_id, image_id, metadata, personalities] - self.compute_api.rebuild(*args) + self.compute_api.rebuild(context, instance_id, image_id, metadata, + personalities) except exception.BuildInProgress: msg = _("Instance %d is currently being rebuilt.") % instance_id LOG.debug(msg) return faults.Fault(exc.HTTPConflict(explanation=msg)) - except exception.Error as ex: - msg = _("Error encountered attempting to rebuild instance " - "%(instance_id): %(ex)") % locals() - LOG.error(msg) - raise response = exc.HTTPAccepted() response.empty_body = True -- cgit From 2014dcd674cc18d440b92202558adef1a81e36c3 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Mon, 25 Apr 2011 00:01:19 -0700 Subject: updated tests to reflect serverRef as href (per Ilya Alekseyev) and refactored _build_server from ViewBuilder (per Eldar Nugaev) --- nova/api/openstack/views/images.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 3c98599b4..2773c9c13 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -46,6 +46,14 @@ class ViewBuilder(object): except KeyError: image['status'] = image['status'].upper() + def _build_server(self, image, instance_id): + """Indicates that you must use a ViewBuilder subclass.""" + raise NotImplementedError + + def generate_server_ref(self, server_id): + """Return an href string pointing to this server.""" + return os.path.join(self._url, "servers", str(server_id)) + def generate_href(self, image_id): """Return an href string pointing to this object.""" return os.path.join(self._url, "images", str(image_id)) @@ -66,7 +74,7 @@ class ViewBuilder(object): if "instance_id" in properties: try: - image["serverId"] = int(properties["instance_id"]) + self._build_server(image, int(properties["instance_id"])) except ValueError: pass @@ -85,19 +93,21 @@ class ViewBuilder(object): class ViewBuilderV10(ViewBuilder): """OpenStack API v1.0 Image Builder""" - pass + + def _build_server(self, image, instance_id): + image["serverId"] = instance_id class ViewBuilderV11(ViewBuilder): """OpenStack API v1.1 Image Builder""" + def _build_server(self, image, instance_id): + image["serverRef"] = self.generate_server_ref(instance_id) + def build(self, image_obj, detail=False): """Return a standardized image structure for display by the API.""" image = ViewBuilder.build(self, image_obj, detail) href = self.generate_href(image_obj["id"]) - if "serverId" in image: - image["serverRef"] = image["serverId"] - del image["serverId"] image["links"] = [{ "rel": "self", -- cgit From 6721d8918820f53288cbdf09ee352e93120439f9 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 26 Apr 2011 09:45:53 -0400 Subject: Modified instance status for shutoff power state in OS api --- nova/api/openstack/views/servers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index f2d8d5720..bdc85f4a1 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -63,8 +63,8 @@ class ViewBuilder(object): power_state.BLOCKED: 'ACTIVE', power_state.SUSPENDED: 'SUSPENDED', power_state.PAUSED: 'PAUSED', - power_state.SHUTDOWN: 'INACTIVE', - power_state.SHUTOFF: 'ACTIVE', + power_state.SHUTDOWN: 'SHUTDOWN', + power_state.SHUTOFF: 'SHUTOFF', power_state.CRASHED: 'ERROR', power_state.FAILED: 'ERROR'} -- cgit From 8e6875e8c9b45a03396d5e4312c4f9136b1dc552 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 27 Apr 2011 14:03:05 -0700 Subject: further cleanup of nova/exceptions.py --- nova/api/ec2/cloud.py | 8 +++----- nova/api/openstack/accounts.py | 2 +- nova/api/openstack/users.py | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 94fbf19ff..092b80fa2 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -49,8 +49,6 @@ flags.DECLARE('service_down_time', 'nova.scheduler.driver') LOG = logging.getLogger("nova.api.cloud") -InvalidInputException = exception.InvalidInputException - def _gen_key(context, user_id, key_name): """Generate a key @@ -398,11 +396,11 @@ class CloudController(object): ip_protocol = str(ip_protocol) if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']: - raise InvalidInputException(_('%s is not a valid ipProtocol') % - (ip_protocol,)) + raise exception.InvalidIpProtocol(protocol=ip_protocol) if ((min(from_port, to_port) < -1) or (max(from_port, to_port) > 65535)): - raise InvalidInputException(_('Invalid port range')) + raise exception.InvalidPortRange(from_port=from_port, + to_port=to_port) values['protocol'] = ip_protocol values['from_port'] = from_port diff --git a/nova/api/openstack/accounts.py b/nova/api/openstack/accounts.py index 6e3763e47..00fdd4540 100644 --- a/nova/api/openstack/accounts.py +++ b/nova/api/openstack/accounts.py @@ -48,7 +48,7 @@ class Controller(common.OpenstackController): """We cannot depend on the db layer to check for admin access for the auth manager, so we do it here""" if not context.is_admin: - raise exception.NotAuthorized(_("Not admin user.")) + raise exception.AdminRequired() def index(self, req): raise faults.Fault(webob.exc.HTTPNotImplemented()) diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py index 077ccfc79..7ae4c3232 100644 --- a/nova/api/openstack/users.py +++ b/nova/api/openstack/users.py @@ -48,7 +48,7 @@ class Controller(common.OpenstackController): """We cannot depend on the db layer to check for admin access for the auth manager, so we do it here""" if not context.is_admin: - raise exception.NotAuthorized(_("Not admin user")) + raise exception.AdminRequired() def index(self, req): """Return all users in brief""" -- cgit From 721fafcfe0679e21fc4f60ec9fa0cfb5dcc468b1 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Sat, 30 Apr 2011 07:14:20 -0400 Subject: adding view file --- nova/api/openstack/views/limits.py | 100 +++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 nova/api/openstack/views/limits.py (limited to 'nova/api') diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py new file mode 100644 index 000000000..552db39ee --- /dev/null +++ b/nova/api/openstack/views/limits.py @@ -0,0 +1,100 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010-2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import time + +from nova.api.openstack import common + + +class ViewBuilder(object): + """Openstack API base limits view builder.""" + + def build(self, rate_limits, absolute_limits): + rate_limits = self._build_rate_limits(rate_limits) + absolute_limits = self._build_absolute_limits(absolute_limits) + + output = { + "limits": { + "rate": rate_limits, + "absolute": absolute_limits, + }, + } + + return output + + +class ViewBuilderV10(ViewBuilder): + """Openstack API v1.0 limits view builder.""" + + def _build_rate_limits(self, rate_limits): + return [self._build_rate_limit(r) for r in rate_limits] + + def _build_rate_limit(self, rate_limit): + return { + "verb": rate_limit["verb"], + "URI": rate_limit["URI"], + "regex": rate_limit["regex"], + "value": rate_limit["value"], + "remaining": int(rate_limit["remaining"]), + "unit": rate_limit["unit"], + "resetTime": rate_limit["resetTime"], + } + + def _build_absolute_limits(self, absolute_limit): + return {} + + +class ViewBuilderV11(ViewBuilder): + """Openstack API v1.1 limits view builder.""" + + def _build_rate_limits(self, rate_limits): + limits = [] + for rate_limit in rate_limits: + _rate_limit_key = None + _rate_limit = self._build_rate_limit(rate_limit) + + # check for existing key + for limit in limits: + if limit["uri"] == rate_limit["URI"] and \ + limit["regex"] == limit["regex"]: + _rate_limit_key = limit + break + + # ensure we have a key if we didn't find one + if not _rate_limit_key: + _rate_limit_key = { + "uri": rate_limit["URI"], + "regex": rate_limit["regex"], + "limit": [], + } + limits.append(_rate_limit_key) + + _rate_limit_key["limit"].append(_rate_limit) + + return limits + + def _build_rate_limit(self, rate_limit): + return { + "verb": rate_limit["verb"], + "value": rate_limit["value"], + "remaining": int(rate_limit["remaining"]), + "unit": rate_limit["unit"], + "next-available": rate_limit["resetTime"], + } + + def _build_absolute_limits(self, absolute_limit): + return {} -- cgit From 5ee53b6df23988263ffdc43549756ef59770981c Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 2 May 2011 00:45:09 -0700 Subject: removed unused method and fixed imports --- nova/api/openstack/servers.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 9b883f06b..03f700844 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -14,28 +14,25 @@ # under the License. import base64 -import hashlib import traceback from webob import exc from xml.dom import minidom from nova import compute -from nova import context from nova import exception from nova import flags from nova import log as logging from nova import quota from nova import utils -from nova import wsgi from nova.api.openstack import common from nova.api.openstack import faults import nova.api.openstack.views.addresses import nova.api.openstack.views.flavors +import nova.api.openstack.views.flavors import nova.api.openstack.views.servers from nova.auth import manager as auth_manager from nova.compute import instance_types -from nova.compute import power_state import nova.api.openstack from nova.scheduler import api as scheduler_api @@ -595,9 +592,6 @@ class ControllerV10(Controller): return nova.api.openstack.views.servers.ViewBuilderV10( addresses_builder) - def _get_addresses_view_builder(self, req): - return nova.api.openstack.views.addresses.ViewBuilderV10(req) - def _limit_items(self, items, req): return common.limited(items, req) @@ -629,9 +623,6 @@ class ControllerV11(Controller): return nova.api.openstack.views.servers.ViewBuilderV11( addresses_builder, flavor_builder, image_builder, base_url) - def _get_addresses_view_builder(self, req): - return nova.api.openstack.views.addresses.ViewBuilderV11(req) - def _action_change_password(self, input_dict, req, id): context = req.environ['nova.context'] if (not 'changePassword' in input_dict -- cgit From e28ec55f91b944346065df737adf063436c53779 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 2 May 2011 00:55:54 -0700 Subject: fix typo in import --- nova/api/openstack/servers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 03f700844..8505c3f71 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -29,7 +29,7 @@ from nova.api.openstack import common from nova.api.openstack import faults import nova.api.openstack.views.addresses import nova.api.openstack.views.flavors -import nova.api.openstack.views.flavors +import nova.api.openstack.views.images import nova.api.openstack.views.servers from nova.auth import manager as auth_manager from nova.compute import instance_types -- cgit From b4b427ce5d7f66245135b9cf57208884b8b556fe Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Mon, 2 May 2011 16:14:41 -0400 Subject: Added support in osapi for requests with local hrefs, e.g., "imageRef":"2" --- nova/api/openstack/common.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 65ed1e143..32cd689ca 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -15,6 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. +import re from urlparse import urlparse import webob @@ -130,10 +131,16 @@ def get_image_id_from_image_hash(image_service, context, image_hash): def get_id_from_href(href): """Return the id portion of a url as an int. - Given: http://www.foo.com/bar/123?q=4 + Given: 'http://www.foo.com/bar/123?q=4' + Returns: 123 + + In order to support local hrefs, the href argument can be just an id: + Given: '123' Returns: 123 """ + if re.match(r'\d+$', str(href)): + return int(href) try: return int(urlparse(href).path.split('/')[-1]) except: -- cgit From bf889f68e3efbf0ca388912b6c93ef61c5a8e7ad Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 3 May 2011 12:25:19 -0400 Subject: removing class imports --- nova/api/openstack/limits.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index f582fd1b6..47bc238f1 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -34,8 +34,6 @@ from nova import wsgi from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack.views import limits as limits_views -from nova.wsgi import Controller -from nova.wsgi import Middleware # Convenience constants for the limits dictionary passed to Limiter(). @@ -197,7 +195,7 @@ DEFAULT_LIMITS = [ ] -class RateLimitingMiddleware(Middleware): +class RateLimitingMiddleware(wsgi.Middleware): """ Rate-limits requests passing through this middleware. All limit information is stored in memory for this implementation. @@ -211,7 +209,7 @@ class RateLimitingMiddleware(Middleware): @param application: WSGI application to wrap @param limits: List of dictionaries describing limits """ - Middleware.__init__(self, application) + wsgi.Middleware.__init__(self, application) self._limiter = Limiter(limits or DEFAULT_LIMITS) @wsgify(RequestClass=wsgi.Request) -- cgit From 29e9aa173ea20a7d5cb816ce7478d6c0c2c38b80 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 3 May 2011 12:32:40 -0400 Subject: adding debug log message --- nova/api/openstack/servers.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index a238e6c82..3cf78e32c 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -692,6 +692,7 @@ class ControllerV11(Controller): image_ref = info["rebuild"]["imageRef"] except (KeyError, TypeError): msg = _("Could not parse imageRef from request.") + LOG.debug(msg) return faults.Fault(exc.HTTPBadRequest(explanation=msg)) image_id = common.get_id_from_href(image_ref) -- cgit From 2cfa0ab48e981e31484287936fbc738d6073f473 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 5 May 2011 15:35:34 -0400 Subject: removing rogue TimeoutException --- nova/api/openstack/servers.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 3cf78e32c..547310613 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -594,10 +594,7 @@ class ControllerV10(Controller): def _parse_update(self, context, server_id, inst_dict, update_dict): if 'adminPass' in inst_dict['server']: update_dict['admin_pass'] = inst_dict['server']['adminPass'] - try: - self.compute_api.set_admin_password(context, server_id) - except exception.TimeoutException: - return exc.HTTPRequestTimeout() + self.compute_api.set_admin_password(context, server_id) def _action_rebuild(self, info, request, instance_id): context = request.environ['nova.context'] -- cgit From 8d3f20e776af0fe174474a9fe8ee02eabe64053b Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 5 May 2011 15:56:04 -0400 Subject: Added interfaces to server controller --- nova/api/openstack/servers.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 3cf78e32c..1d3eab65b 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -75,6 +75,26 @@ class Controller(common.OpenstackController): """ Returns a list of server details for a given user """ return self._items(req, is_detail=True) + def _image_id_from_req_data(self, data): + raise NotImplementedError + + def _flavor_id_from_req_data(self, data): + raise NotImplementedError + + def _get_view_builder(self, req): + raise NotImplementedError + + def _limit_items(self, items, req): + raise NotImplementedError + + def _limit_items(self, items, req): + raise NotImplementedError + + def _action_rebuild(self, info, request, instance_id): + raise NotImplementedError + + + def _items(self, req, is_detail): """Returns a list of servers for a given user. -- cgit From 5a3e8eea45bc11978112e3fed93768a1daf71530 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 5 May 2011 16:29:31 -0400 Subject: Added interface function to ViewBilder --- nova/api/openstack/flavors.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index 40787bd17..dee70bb2b 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -45,6 +45,9 @@ class Controller(common.OpenstackController): items = self._get_flavors(req, is_detail=True) return dict(flavors=items) + def _get_view_builder(self, req): + raise NotImplementedError + def _get_flavors(self, req, is_detail=True): """Helper function that returns a list of flavor dicts.""" ctxt = req.environ['nova.context'] -- cgit From bbb2bba0f05493ec40c70279b532b26a4a4c235c Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 6 May 2011 10:48:11 -0400 Subject: Added stub function for a referenced, previously non-existant function --- nova/api/ec2/cloud.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 092b80fa2..40ae06750 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -366,6 +366,9 @@ class CloudController(object): g['ipPermissions'] += [r] return g + def _get_instance(instance_id): + raise NotImplementedError + def _revoke_rule_args_to_dict(self, context, to_port=None, from_port=None, ip_protocol=None, cidr_ip=None, user_id=None, source_security_group_name=None, -- cgit From 2946a21f78e4fd2b18bd6eb8c85eb2cc0c764f8a Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 6 May 2011 14:13:27 -0400 Subject: Added interface functions --- nova/api/ec2/cloud.py | 2 +- nova/api/openstack/servers.py | 14 ++++++-------- nova/api/openstack/views/limits.py | 9 +++++++++ 3 files changed, 16 insertions(+), 9 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 40ae06750..9aa4e7778 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -367,7 +367,7 @@ class CloudController(object): return g def _get_instance(instance_id): - raise NotImplementedError + raise NotImplementedError() def _revoke_rule_args_to_dict(self, context, to_port=None, from_port=None, ip_protocol=None, cidr_ip=None, user_id=None, diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 1d3eab65b..2bf405545 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -76,24 +76,22 @@ class Controller(common.OpenstackController): return self._items(req, is_detail=True) def _image_id_from_req_data(self, data): - raise NotImplementedError + raise NotImplementedError() def _flavor_id_from_req_data(self, data): - raise NotImplementedError + raise NotImplementedError() def _get_view_builder(self, req): - raise NotImplementedError + raise NotImplementedError() def _limit_items(self, items, req): - raise NotImplementedError + raise NotImplementedError() def _limit_items(self, items, req): - raise NotImplementedError + raise NotImplementedError() def _action_rebuild(self, info, request, instance_id): - raise NotImplementedError - - + raise NotImplementedError() def _items(self, req, is_detail): """Returns a list of servers for a given user. diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index 552db39ee..22d1c260d 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -23,6 +23,15 @@ from nova.api.openstack import common class ViewBuilder(object): """Openstack API base limits view builder.""" + def _build_rate_limits(self, rate_limits): + raise NotImplementedError() + + def _build_rate_limit(self, rate_limit): + raise NotImplementedError() + + def _build_absolute_limits(self, absolute_limit): + raise NotImplementedError() + def build(self, rate_limits, absolute_limits): rate_limits = self._build_rate_limits(rate_limits) absolute_limits = self._build_absolute_limits(absolute_limits) -- cgit From 3a7d1422d52f551e870542305ce9bab9e9e6ebad Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 6 May 2011 16:13:35 -0400 Subject: Fixed method in flavors --- nova/api/openstack/flavors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index dee70bb2b..4c5971cf6 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -46,7 +46,7 @@ class Controller(common.OpenstackController): return dict(flavors=items) def _get_view_builder(self, req): - raise NotImplementedError + raise NotImplementedError() def _get_flavors(self, req, is_detail=True): """Helper function that returns a list of flavor dicts.""" -- cgit From e1cfa28fc9e1194bbd4c9ce9c2f06ea3f6e5548e Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 6 May 2011 16:48:38 -0400 Subject: Fixed duplicate function --- nova/api/openstack/servers.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 2bf405545..71cb31c72 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -87,9 +87,6 @@ class Controller(common.OpenstackController): def _limit_items(self, items, req): raise NotImplementedError() - def _limit_items(self, items, req): - raise NotImplementedError() - def _action_rebuild(self, info, request, instance_id): raise NotImplementedError() -- cgit From eb0619c91b4756d355b7a5cd5c1f16d342f14a6b Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Wed, 11 May 2011 06:28:07 -0700 Subject: First cut with tests passing --- nova/api/openstack/__init__.py | 3 ++- nova/api/openstack/zones.py | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 348b70d5b..b743d306b 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -98,7 +98,8 @@ class APIRouter(wsgi.Router): server_members['inject_network_info'] = 'POST' mapper.resource("zone", "zones", controller=zones.Controller(), - collection={'detail': 'GET', 'info': 'GET'}), + collection={'detail': 'GET', 'info': 'GET', + 'select': 'GET',}), mapper.resource("user", "users", controller=users.Controller(), collection={'detail': 'GET'}) diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index 227ffecdc..70653dc0e 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -13,6 +13,10 @@ # License for the specific language governing permissions and limitations # under the License. +import json +import urlparse + +from nova import crypto from nova import db from nova import flags from nova import log as logging @@ -21,6 +25,12 @@ from nova.scheduler import api FLAGS = flags.FLAGS +flags.DEFINE_string('build_plan_encryption_key', + None, + '128bit (hex) encryption key for scheduler build plans.') + + +LOG = logging.getLogger('nova.api.openstack.zones') def _filter_keys(item, keys): @@ -41,6 +51,14 @@ def _scrub_zone(zone): 'deleted', 'deleted_at', 'updated_at')) +def check_encryption_key(func): + def wrapped(*args, **kwargs): + if not FLAGS.build_plan_encryption_key: + raise exception.Error(_("--build_plan_encryption_key not set")) + return func(*args, **kwargs) + return wrapped + + class Controller(common.OpenstackController): _serialization_metadata = { @@ -97,3 +115,33 @@ class Controller(common.OpenstackController): zone_id = int(id) zone = api.zone_update(context, zone_id, env["zone"]) return dict(zone=_scrub_zone(zone)) + + @check_encryption_key + def select(self, req): + """Returns a weighted list of costs to create instances + of desired capabilities.""" + ctx = req.environ['nova.context'] + qs = req.environ['QUERY_STRING'] + param_dict = urlparse.parse_qs(qs) + param_dict.pop("fresh", None) + # parse_qs returns a dict where the values are lists, + # since query strings can have multiple values for the + # same key. We need to convert that to single values. + for key in param_dict: + param_dict[key] = param_dict[key][0] + build_plan = api.select(ctx, specs=param_dict) + cooked = self._scrub_build_plan(build_plan) + return {"weights": cooked} + + def _scrub_build_plan(self, build_plan): + """Remove all the confidential data and return a sanitized + version of the build plan. Include an encrypted full version + of the weighting entry so we can get back to it later.""" + encryptor = crypto.encryptor(FLAGS.build_plan_encryption_key) + cooked = [] + for entry in build_plan: + json_entry = json.dumps(entry) + cipher_text = encryptor(json_entry) + cooked.append(dict(weight=entry['weight'], + blob=cipher_text)) + return cooked -- cgit From 43fa5afac9e5af74e2e3977a5dafd9640d064cf1 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 11 May 2011 15:12:12 +0000 Subject: Abstract out IPv6 address generation to pluggable backends --- nova/api/ec2/cloud.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 092b80fa2..993c91fe1 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -39,6 +39,7 @@ from nova import log as logging from nova import network from nova import utils from nova import volume +from nova import ipv6 from nova.api.ec2 import ec2utils from nova.compute import instance_types from nova.image import s3 @@ -718,7 +719,7 @@ class CloudController(object): fixed = instance['fixed_ip'] floating_addr = fixed['floating_ips'][0]['address'] if instance['fixed_ip']['network'] and 'use_v6' in kwargs: - i['dnsNameV6'] = utils.to_global_ipv6( + i['dnsNameV6'] = ipv6.to_global( instance['fixed_ip']['network']['cidr_v6'], instance['mac_address']) -- cgit From 3b0b69ddc02f57859b351d6d354a12d5955c09f1 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 11 May 2011 11:02:01 -0700 Subject: make sure proper exceptions are raised for ec2 id conversion and add tests --- nova/api/ec2/cloud.py | 2 +- nova/api/ec2/ec2utils.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 092b80fa2..be5dd38a0 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -906,7 +906,7 @@ class CloudController(object): try: internal_id = ec2utils.ec2_id_to_id(ec2_id) return self.image_service.show(context, internal_id) - except ValueError: + except (exception.InvalidEc2Id, exception.ImageNotFound): try: return self.image_service.show_by_name(context, ec2_id) except exception.NotFound: diff --git a/nova/api/ec2/ec2utils.py b/nova/api/ec2/ec2utils.py index 1ac48163c..163aa4ed2 100644 --- a/nova/api/ec2/ec2utils.py +++ b/nova/api/ec2/ec2utils.py @@ -21,7 +21,10 @@ from nova import exception def ec2_id_to_id(ec2_id): """Convert an ec2 ID (i-[base 16 number]) to an instance id (int)""" - return int(ec2_id.split('-')[-1], 16) + try: + return int(ec2_id.split('-')[-1], 16) + except ValueError: + raise exception.InvalidEc2Id(ec2_id=ec2_id) def id_to_ec2_id(instance_id, template='i-%08x'): -- cgit From d2b8350a026e0f00eae7cadbacaa15d4b44331af Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 11 May 2011 21:04:40 +0000 Subject: Implement IPv6 address generation that includes account identifier --- nova/api/ec2/cloud.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 1b51b5463..63baf8036 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -721,7 +721,8 @@ class CloudController(object): if instance['fixed_ip']['network'] and 'use_v6' in kwargs: i['dnsNameV6'] = ipv6.to_global( instance['fixed_ip']['network']['cidr_v6'], - instance['mac_address']) + instance['mac_address'], + instance['project_id']) i['privateDnsName'] = fixed_addr i['privateIpAddress'] = fixed_addr -- cgit From 22c33d80ce040f09c9bcd7584cf1165cf769e192 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 12 May 2011 10:55:04 -0400 Subject: Initial work on request extensions. --- nova/api/openstack/extensions.py | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 7ea7afef6..e6dd228ec 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -165,6 +165,34 @@ class ResponseExtensionController(common.OpenstackController): return res +class RequestExtensionController(common.OpenstackController): + + def __init__(self, application): + self.application = application + self.handlers = [] + + def add_handler(self, handler): + self.handlers.append(handler) + + def process(self, req, *args, **kwargs): + res = req.get_response(self.application) + content_type = req.best_match_content_type() + # currently response handlers are un-ordered + for handler in self.handlers: + res = handler(req, res) + try: + body = res.body + headers = res.headers + except AttributeError: + default_xmlns = None + body = self._serialize(res, content_type, default_xmlns) + headers = {"Content-Type": content_type} + res = webob.Response() + res.body = body + res.headers = headers + return res + + class ExtensionController(common.OpenstackController): def __init__(self, extension_manager): @@ -245,6 +273,25 @@ class ExtensionMiddleware(wsgi.Middleware): return response_ext_controllers + def _request_ext_controllers(self, application, ext_mgr, mapper): + """Returns a dict of RequestExtensionController-s by collection.""" + request_ext_controllers = {} + for req_ext in ext_mgr.get_request_extensions(): + if not req_ext.key in request_ext_controllers.keys(): + controller = RequestExtensionController(application) + mapper.connect(req_ext.url_route + '.:(format)', + action='process', + controller=controller, + conditions=req_ext.conditions) + + mapper.connect(req_ext.url_route, + action='process', + controller=controller, + conditions=req_ext.conditions) + request_ext_controllers[req_ext.key] = controller + + return request_ext_controllers + def __init__(self, application, ext_mgr=None): if ext_mgr is None: @@ -279,6 +326,14 @@ class ExtensionMiddleware(wsgi.Middleware): controller = resp_controllers[response_ext.key] controller.add_handler(response_ext.handler) + # extended requests + req_controllers = self._request_ext_controllers(application, ext_mgr, + mapper) + for request_ext in ext_mgr.get_request_extensions(): + LOG.debug(_('Extended request: %s'), request_ext.key) + controller = req_controllers[request_ext.key] + controller.add_handler(request_ext.handler) + self._router = routes.middleware.RoutesMiddleware(self._dispatch, mapper) @@ -359,6 +414,18 @@ class ExtensionManager(object): pass return response_exts + def get_request_extensions(self): + """Returns a list of RequestExtension objects.""" + request_exts = [] + for alias, ext in self.extensions.iteritems(): + try: + request_exts.extend(ext.get_request_extensions()) + except AttributeError: + # NOTE(dprince): Extension aren't required to have request + # extensions + pass + return request_exts + def _check_extension(self, extension): """Checks for required methods in extension objects.""" try: @@ -431,6 +498,17 @@ class ResponseExtension(object): self.key = "%s-%s" % (method, url_route) +class RequestExtension(object): + """Provide a way to handle custom request data that is sent to core + nova OpenStack API controllers. + """ + def __init__(self, method, url_route, handler): + self.url_route = url_route + self.handler = handler + self.conditions = dict(method=[method]) + self.key = "%s-%s" % (method, url_route) + + class ActionExtension(object): """Add custom actions to core nova OpenStack API controllers.""" -- cgit From ce2b13d9fb30c0afbcff97f434d7423cad39b8b9 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 12 May 2011 12:52:32 -0400 Subject: Remove ResponseExtensions. The new RequestExtension covers both use cases. --- nova/api/openstack/extensions.py | 88 +++------------------------------------- 1 file changed, 5 insertions(+), 83 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index e6dd228ec..3a7763463 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -105,15 +105,14 @@ class ExtensionDescriptor(object): actions = [] return actions - def get_response_extensions(self): - """List of extensions.ResponseExtension extension objects. + def get_request_extensions(self): + """List of extensions.RequestException extension objects. - Response extensions are used to insert information into existing - response data. + Request extensions are used to handle custom request data. """ - response_exts = [] - return response_exts + request_exts = [] + return request_exts class ActionExtensionController(common.OpenstackController): @@ -137,34 +136,6 @@ class ActionExtensionController(common.OpenstackController): return res -class ResponseExtensionController(common.OpenstackController): - - def __init__(self, application): - self.application = application - self.handlers = [] - - def add_handler(self, handler): - self.handlers.append(handler) - - def process(self, req, *args, **kwargs): - res = req.get_response(self.application) - content_type = req.best_match_content_type() - # currently response handlers are un-ordered - for handler in self.handlers: - res = handler(res) - try: - body = res.body - headers = res.headers - except AttributeError: - default_xmlns = None - body = self._serialize(res, content_type, default_xmlns) - headers = {"Content-Type": content_type} - res = webob.Response() - res.body = body - res.headers = headers - return res - - class RequestExtensionController(common.OpenstackController): def __init__(self, application): @@ -254,25 +225,6 @@ class ExtensionMiddleware(wsgi.Middleware): return action_controllers - def _response_ext_controllers(self, application, ext_mgr, mapper): - """Returns a dict of ResponseExtensionController-s by collection.""" - response_ext_controllers = {} - for resp_ext in ext_mgr.get_response_extensions(): - if not resp_ext.key in response_ext_controllers.keys(): - controller = ResponseExtensionController(application) - mapper.connect(resp_ext.url_route + '.:(format)', - action='process', - controller=controller, - conditions=resp_ext.conditions) - - mapper.connect(resp_ext.url_route, - action='process', - controller=controller, - conditions=resp_ext.conditions) - response_ext_controllers[resp_ext.key] = controller - - return response_ext_controllers - def _request_ext_controllers(self, application, ext_mgr, mapper): """Returns a dict of RequestExtensionController-s by collection.""" request_ext_controllers = {} @@ -318,14 +270,6 @@ class ExtensionMiddleware(wsgi.Middleware): controller = action_controllers[action.collection] controller.add_action(action.action_name, action.handler) - # extended responses - resp_controllers = self._response_ext_controllers(application, ext_mgr, - mapper) - for response_ext in ext_mgr.get_response_extensions(): - LOG.debug(_('Extended response: %s'), response_ext.key) - controller = resp_controllers[response_ext.key] - controller.add_handler(response_ext.handler) - # extended requests req_controllers = self._request_ext_controllers(application, ext_mgr, mapper) @@ -402,18 +346,6 @@ class ExtensionManager(object): pass return actions - def get_response_extensions(self): - """Returns a list of ResponseExtension objects.""" - response_exts = [] - for alias, ext in self.extensions.iteritems(): - try: - response_exts.extend(ext.get_response_extensions()) - except AttributeError: - # NOTE(dprince): Extension aren't required to have response - # extensions - pass - return response_exts - def get_request_extensions(self): """Returns a list of RequestExtension objects.""" request_exts = [] @@ -488,16 +420,6 @@ class ExtensionManager(object): self.extensions[alias] = ext -class ResponseExtension(object): - """Add data to responses from core nova OpenStack API controllers.""" - - def __init__(self, method, url_route, handler): - self.url_route = url_route - self.handler = handler - self.conditions = dict(method=[method]) - self.key = "%s-%s" % (method, url_route) - - class RequestExtension(object): """Provide a way to handle custom request data that is sent to core nova OpenStack API controllers. -- cgit From e03921c2799acf36083eb13c3134b861bc4732a6 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 12 May 2011 14:37:15 -0400 Subject: Make it so that ExtensionRequest objects now return proper webob objects. This avoids the odd serialization code in the RequestExtensionController class which converts JSON dicts to webobs for us. --- nova/api/openstack/extensions.py | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 3a7763463..ac79b9310 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -147,20 +147,9 @@ class RequestExtensionController(common.OpenstackController): def process(self, req, *args, **kwargs): res = req.get_response(self.application) - content_type = req.best_match_content_type() # currently response handlers are un-ordered for handler in self.handlers: res = handler(req, res) - try: - body = res.body - headers = res.headers - except AttributeError: - default_xmlns = None - body = self._serialize(res, content_type, default_xmlns) - headers = {"Content-Type": content_type} - res = webob.Response() - res.body = body - res.headers = headers return res -- cgit From e72667cb125f1d970f302bb18f051380fac0711d Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 12 May 2011 14:52:54 -0400 Subject: Update comment. --- nova/api/openstack/extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index ac79b9310..0e729e137 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -147,7 +147,7 @@ class RequestExtensionController(common.OpenstackController): def process(self, req, *args, **kwargs): res = req.get_response(self.application) - # currently response handlers are un-ordered + # currently request handlers are un-ordered for handler in self.handlers: res = handler(req, res) return res -- cgit From 1aad930383fa425b88e59929aa1698e31978eb62 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Thu, 12 May 2011 22:19:52 +0000 Subject: Make sure imports are in alphabetical order --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 63baf8036..1fa07d042 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -35,11 +35,11 @@ from nova import crypto from nova import db from nova import exception from nova import flags +from nova import ipv6 from nova import log as logging from nova import network from nova import utils from nova import volume -from nova import ipv6 from nova.api.ec2 import ec2utils from nova.compute import instance_types from nova.image import s3 -- cgit From 5502c2764bd55a2b9c5012fd01d821ee5882aca2 Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Thu, 12 May 2011 20:07:54 -0500 Subject: Adding basic tests for call_zone_method --- nova/api/openstack/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index b743d306b..5b7f080ad 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -99,7 +99,7 @@ class APIRouter(wsgi.Router): mapper.resource("zone", "zones", controller=zones.Controller(), collection={'detail': 'GET', 'info': 'GET', - 'select': 'GET',}), + 'select': 'GET'}) mapper.resource("user", "users", controller=users.Controller(), collection={'detail': 'GET'}) -- cgit From 35c37d7d74296bf6362ceb675e4f2c2e7b8f994a Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Thu, 12 May 2011 18:44:22 -0700 Subject: pep8 --- nova/api/openstack/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index b743d306b..5d45efde6 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -99,7 +99,7 @@ class APIRouter(wsgi.Router): mapper.resource("zone", "zones", controller=zones.Controller(), collection={'detail': 'GET', 'info': 'GET', - 'select': 'GET',}), + 'select': 'GET'}), mapper.resource("user", "users", controller=users.Controller(), collection={'detail': 'GET'}) -- cgit From 262dec736fa6ef54a1101a0a17671ff2a19cbd95 Mon Sep 17 00:00:00 2001 From: Nirmal Ranganathan Date: Mon, 16 May 2011 11:12:16 -0500 Subject: Added the imageRef and flavorRef attributes in the xml deserialization --- nova/api/openstack/servers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 3cf78e32c..1289c1e0a 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -746,8 +746,9 @@ class ServerCreateRequestXMLDeserializer(object): """Marshal the server attribute of a parsed request""" server = {} server_node = self._find_first_child_named(node, 'server') - for attr in ["name", "imageId", "flavorId"]: - server[attr] = server_node.getAttribute(attr) + for attr in ["name", "imageId", "flavorId", "imageRef", "flavorRef"]: + if server_node.getAttribute(attr): + server[attr] = server_node.getAttribute(attr) metadata = self._extract_metadata(server_node) if metadata is not None: server["metadata"] = metadata -- cgit From e7f699706089919274055fc5c57c276f36d7a301 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 16 May 2011 14:02:56 -0400 Subject: Removed obsolete method and test --- nova/api/ec2/cloud.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 9aa4e7778..092b80fa2 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -366,9 +366,6 @@ class CloudController(object): g['ipPermissions'] += [r] return g - def _get_instance(instance_id): - raise NotImplementedError() - def _revoke_rule_args_to_dict(self, context, to_port=None, from_port=None, ip_protocol=None, cidr_ip=None, user_id=None, source_security_group_name=None, -- cgit From 8cf2087747ab87fec0e1f7cc3d57ed1fa5065749 Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Mon, 16 May 2011 14:50:07 -0400 Subject: add a todo --- nova/api/openstack/limits.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index 47bc238f1..f30c9ec59 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -64,7 +64,9 @@ class LimitsController(common.OpenstackController): """ Return all global and rate limit information. """ - abs_limits = {} + # TODO(alex.meade) make this work + project_quota = quota.get_project_quota(...) + abs_limits = project_quota.limits rate_limits = req.environ.get("nova.limits", []) builder = self._get_view_builder(req) -- cgit From 6404e2bb02f0736c43ef37292c1143e58903c5db Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 16 May 2011 23:14:51 -0400 Subject: Update comment on RequestExtension class. --- nova/api/openstack/extensions.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 0e729e137..8e77b25fb 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -410,8 +410,11 @@ class ExtensionManager(object): class RequestExtension(object): - """Provide a way to handle custom request data that is sent to core - nova OpenStack API controllers. + """Extend requests and responses of core nova OpenStack API controllers. + + Provide a way to add data to responses and handle custom request data + that is sent to core nova OpenStack API controllers. + """ def __init__(self, method, url_route, handler): self.url_route = url_route -- cgit From b312ac2634f530273e599ee48ff2e3a238bbbf4f Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Tue, 17 May 2011 16:46:13 +0000 Subject: Set password to one requested in API call --- nova/api/openstack/servers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 8f2de2afe..fcb630fae 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -609,7 +609,8 @@ class ControllerV10(Controller): def _parse_update(self, context, server_id, inst_dict, update_dict): if 'adminPass' in inst_dict['server']: update_dict['admin_pass'] = inst_dict['server']['adminPass'] - self.compute_api.set_admin_password(context, server_id) + self.compute_api.set_admin_password(context, server_id, + inst_dict['server']['adminPass']) def _action_rebuild(self, info, request, instance_id): context = request.environ['nova.context'] -- cgit From 6c27e24a559722a5a82d8883f508a77d281956f5 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Tue, 17 May 2011 17:51:22 +0000 Subject: Avoid using spawn_n to fix LP784132 --- nova/api/openstack/servers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index fcb630fae..bd9711555 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -609,7 +609,9 @@ class ControllerV10(Controller): def _parse_update(self, context, server_id, inst_dict, update_dict): if 'adminPass' in inst_dict['server']: update_dict['admin_pass'] = inst_dict['server']['adminPass'] - self.compute_api.set_admin_password(context, server_id, + # We call _set_admin_password() here to avoid the spawn_n in + # set_admin_password() + self.compute_api._set_admin_password(context, server_id, inst_dict['server']['adminPass']) def _action_rebuild(self, info, request, instance_id): -- cgit From 11a36377f81f6f4c6c20e5802aa91e472772fbc9 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 17 May 2011 11:31:09 -0700 Subject: make token use typo that is in database. Also fix now -> utcnow and stop using . syntax for dealing with tokens --- nova/api/openstack/auth.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index 311e6bde9..7ccd46f54 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -17,7 +17,6 @@ import datetime import hashlib -import json import time import webob.exc @@ -25,11 +24,9 @@ import webob.dec from nova import auth from nova import context -from nova import db from nova import exception from nova import flags from nova import log as logging -from nova import manager from nova import utils from nova import wsgi from nova.api.openstack import faults @@ -102,11 +99,13 @@ class AuthMiddleware(wsgi.Middleware): token, user = self._authorize_user(username, key, req) if user and token: res = webob.Response() - res.headers['X-Auth-Token'] = token.token_hash + res.headers['X-Auth-Token'] = token['token_hash'] + # NOTE(vish): the apparrent typo in manageent is actually how it + # is in the db res.headers['X-Server-Management-Url'] = \ - token.server_management_url - res.headers['X-Storage-Url'] = token.storage_url - res.headers['X-CDN-Management-Url'] = token.cdn_management_url + token['server_manageent_url'] + res.headers['X-Storage-Url'] = token['storage_url'] + res.headers['X-CDN-Management-Url'] = token['cdn_management_url'] res.content_type = 'text/plain' res.status = '204' LOG.debug(_("Successfully authenticated '%s'") % username) @@ -130,11 +129,11 @@ class AuthMiddleware(wsgi.Middleware): except exception.NotFound: return None if token: - delta = datetime.datetime.now() - token.created_at + delta = datetime.datetime.utcnow() - token['created_at'] if delta.days >= 2: - self.db.auth_token_destroy(ctxt, token.token_hash) + self.db.auth_token_destroy(ctxt, token['token_hash']) else: - return self.auth.get_user(token.user_id) + return self.auth.get_user(token['user_id']) return None def _authorize_user(self, username, key, req): @@ -159,7 +158,7 @@ class AuthMiddleware(wsgi.Middleware): token_dict['token_hash'] = token_hash token_dict['cdn_management_url'] = '' os_url = req.url - token_dict['server_management_url'] = os_url + token_dict['server_manageent_url'] = os_url token_dict['storage_url'] = '' token_dict['user_id'] = user.id token = self.db.auth_token_create(ctxt, token_dict) -- cgit From 91e96cea27c91190f6205defa1f5a3641a0e0f56 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 17 May 2011 12:12:48 -0700 Subject: add migration for proper name --- nova/api/openstack/auth.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index 7ccd46f54..6c6ee22a2 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -100,10 +100,8 @@ class AuthMiddleware(wsgi.Middleware): if user and token: res = webob.Response() res.headers['X-Auth-Token'] = token['token_hash'] - # NOTE(vish): the apparrent typo in manageent is actually how it - # is in the db res.headers['X-Server-Management-Url'] = \ - token['server_manageent_url'] + token['server_management_url'] res.headers['X-Storage-Url'] = token['storage_url'] res.headers['X-CDN-Management-Url'] = token['cdn_management_url'] res.content_type = 'text/plain' @@ -158,7 +156,7 @@ class AuthMiddleware(wsgi.Middleware): token_dict['token_hash'] = token_hash token_dict['cdn_management_url'] = '' os_url = req.url - token_dict['server_manageent_url'] = os_url + token_dict['server_management_url'] = os_url token_dict['storage_url'] = '' token_dict['user_id'] = user.id token = self.db.auth_token_create(ctxt, token_dict) -- cgit From 7ab16489276daa2ec6f51fea6ec24cc0c46a8e14 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 17 May 2011 15:14:52 -0400 Subject: Changed builder to match specs and added test --- nova/api/openstack/limits.py | 9 +++++++-- nova/api/openstack/views/limits.py | 24 +++++++++--------------- 2 files changed, 16 insertions(+), 17 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index cf96b1bce..e383b5efc 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -42,6 +42,9 @@ PER_MINUTE = 60 PER_HOUR = 60 * 60 PER_DAY = 60 * 60 * 24 +#TODO remove when mark catches up +TEST_ABSOLUTE_LIMITS = {} + class LimitsController(common.OpenstackController): """ @@ -53,7 +56,8 @@ class LimitsController(common.OpenstackController): "attributes": { "limit": ["verb", "URI", "uri", "regex", "value", "unit", "resetTime", "next-available", "remaining", "name"], - "absolute_limit": ["limit", "value"], + "absolute_limit": ["maxTotalRAMSize", "maxTotalInstances", + "maxTotalCores"], }, "plurals": { "rate": "limit", @@ -69,7 +73,8 @@ class LimitsController(common.OpenstackController): # TODO(alex.meade) make this work #project_quota = quota.get_project_quota(...) #abs_limits = project_quota.limits - abs_limits = {} + #TODO remove when mark catches up + abs_limits = TEST_ABSOLUTE_LIMITS rate_limits = req.environ.get("nova.limits", []) builder = self._get_view_builder(req) diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index 7fae2d166..ef1243f3d 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -112,25 +112,19 @@ class ViewBuilderV11(ViewBuilder): For example: {"ram": 512, "gigabytes": 1024}. """ - limits = [] + limits = {} #loops through absolute limits and their values for absolute_limit_key, absolute_limit_value \ in absolute_limits.items(): - _abs_limit = None - # check for existing key - for limit in limits: - if limit["limit"] == absolute_limit_key: - _abs_limit = limit - break - - # ensure we have a key if we didn't find one - if not _abs_limit: - _abs_limit = { - "limit": absolute_limit_key, - "value": absolute_limit_value, - } + _abs_limit_map = { + "ram": "maxTotalRAMSize", + "instances": "maxTotalInstances", + "cores": "maxTotalCores", + } - limits.append(_abs_limit) + if not absolute_limit_value is None: + limits[_abs_limit_map[absolute_limit_key]] \ + = absolute_limit_value return limits -- cgit From 0bc5511ccfb4ea97a0ba4c8533ce5d3cd3e6df19 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 17 May 2011 16:25:45 -0400 Subject: Removed extra serialization metadata --- nova/api/openstack/limits.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index e383b5efc..5e3f93f79 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -56,12 +56,9 @@ class LimitsController(common.OpenstackController): "attributes": { "limit": ["verb", "URI", "uri", "regex", "value", "unit", "resetTime", "next-available", "remaining", "name"], - "absolute_limit": ["maxTotalRAMSize", "maxTotalInstances", - "maxTotalCores"], }, "plurals": { "rate": "limit", - "absolute": "absolute_limit", }, }, } -- cgit From bd0125647a04ab8da7eef934e4a97560c1553551 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 18 May 2011 15:31:41 +0000 Subject: Fix call to spawn_n() instead. It expects a callable --- nova/api/openstack/servers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index bd9711555..fcb630fae 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -609,9 +609,7 @@ class ControllerV10(Controller): def _parse_update(self, context, server_id, inst_dict, update_dict): if 'adminPass' in inst_dict['server']: update_dict['admin_pass'] = inst_dict['server']['adminPass'] - # We call _set_admin_password() here to avoid the spawn_n in - # set_admin_password() - self.compute_api._set_admin_password(context, server_id, + self.compute_api.set_admin_password(context, server_id, inst_dict['server']['adminPass']) def _action_rebuild(self, info, request, instance_id): -- cgit From 156ebab6599f9500d8b98c7cc1271d2502fa0627 Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Wed, 18 May 2011 13:54:51 -0400 Subject: get real absolute limits in openstack api and verify absolute limit responses --- nova/api/openstack/limits.py | 11 +++-------- nova/api/openstack/views/limits.py | 23 +++++++++-------------- 2 files changed, 12 insertions(+), 22 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index 5e3f93f79..1411cec01 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -30,6 +30,7 @@ from collections import defaultdict from webob.dec import wsgify +from nova import quota from nova import wsgi from nova.api.openstack import common from nova.api.openstack import faults @@ -42,9 +43,6 @@ PER_MINUTE = 60 PER_HOUR = 60 * 60 PER_DAY = 60 * 60 * 24 -#TODO remove when mark catches up -TEST_ABSOLUTE_LIMITS = {} - class LimitsController(common.OpenstackController): """ @@ -67,11 +65,8 @@ class LimitsController(common.OpenstackController): """ Return all global and rate limit information. """ - # TODO(alex.meade) make this work - #project_quota = quota.get_project_quota(...) - #abs_limits = project_quota.limits - #TODO remove when mark catches up - abs_limits = TEST_ABSOLUTE_LIMITS + context = req.environ['nova.context'] + abs_limits = quota.get_quota(context, context.project_id) rate_limits = req.environ.get("nova.limits", []) builder = self._get_view_builder(req) diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index ef1243f3d..464f91e33 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -112,19 +112,14 @@ class ViewBuilderV11(ViewBuilder): For example: {"ram": 512, "gigabytes": 1024}. """ + limit_names = { + "ram": "maxTotalRAMSize", + "instances": "maxTotalInstances", + "cores": "maxTotalCores", + "metadata_items": "maxServerMeta", + } limits = {} - #loops through absolute limits and their values - for absolute_limit_key, absolute_limit_value \ - in absolute_limits.items(): - - _abs_limit_map = { - "ram": "maxTotalRAMSize", - "instances": "maxTotalInstances", - "cores": "maxTotalCores", - } - - if not absolute_limit_value is None: - limits[_abs_limit_map[absolute_limit_key]] \ - = absolute_limit_value - + for name, value in absolute_limits.iteritems(): + if name in limit_names and value is not None: + limits[limit_names[name]] = value return limits -- cgit From 01f7b0aa8de984baa27be50171526696aac48c0c Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Wed, 18 May 2011 14:46:39 -0500 Subject: Adding FlagNotSet exception --- nova/api/openstack/zones.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index 70653dc0e..145b24347 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -18,6 +18,7 @@ import urlparse from nova import crypto from nova import db +from nova import exception from nova import flags from nova import log as logging from nova.api.openstack import common @@ -54,7 +55,7 @@ def _scrub_zone(zone): def check_encryption_key(func): def wrapped(*args, **kwargs): if not FLAGS.build_plan_encryption_key: - raise exception.Error(_("--build_plan_encryption_key not set")) + raise exception.FlagNotSet(flag='build_plan_encryption_key') return func(*args, **kwargs) return wrapped -- cgit From d44a4728c23cebd1eaa7615c3b439e44972750cc Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Wed, 18 May 2011 15:14:24 -0500 Subject: On second thought, removing decorator --- nova/api/openstack/zones.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index 145b24347..af73d8f6d 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -52,14 +52,6 @@ def _scrub_zone(zone): 'deleted', 'deleted_at', 'updated_at')) -def check_encryption_key(func): - def wrapped(*args, **kwargs): - if not FLAGS.build_plan_encryption_key: - raise exception.FlagNotSet(flag='build_plan_encryption_key') - return func(*args, **kwargs) - return wrapped - - class Controller(common.OpenstackController): _serialization_metadata = { @@ -117,7 +109,6 @@ class Controller(common.OpenstackController): zone = api.zone_update(context, zone_id, env["zone"]) return dict(zone=_scrub_zone(zone)) - @check_encryption_key def select(self, req): """Returns a weighted list of costs to create instances of desired capabilities.""" @@ -138,6 +129,9 @@ class Controller(common.OpenstackController): """Remove all the confidential data and return a sanitized version of the build plan. Include an encrypted full version of the weighting entry so we can get back to it later.""" + if not FLAGS.build_plan_encryption_key: + raise exception.FlagNotSet(flag='build_plan_encryption_key') + encryptor = crypto.encryptor(FLAGS.build_plan_encryption_key) cooked = [] for entry in build_plan: -- cgit From 79d505c015bff1598e8e896f6198d65d90095ba6 Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Wed, 18 May 2011 19:22:53 -0400 Subject: fixup absolute limits to latest 1.1 spec --- nova/api/openstack/limits.py | 2 +- nova/api/openstack/views/limits.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index 1411cec01..032a5ff2f 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -66,7 +66,7 @@ class LimitsController(common.OpenstackController): Return all global and rate limit information. """ context = req.environ['nova.context'] - abs_limits = quota.get_quota(context, context.project_id) + abs_limits = quota.get_quota(context, context.project_id) rate_limits = req.environ.get("nova.limits", []) builder = self._get_view_builder(req) diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index 464f91e33..5b34c8ad0 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -113,13 +113,14 @@ class ViewBuilderV11(ViewBuilder): """ limit_names = { - "ram": "maxTotalRAMSize", - "instances": "maxTotalInstances", - "cores": "maxTotalCores", - "metadata_items": "maxServerMeta", + "ram": ["maxTotalRAMSize"], + "instances": ["maxTotalInstances"], + "cores": ["maxTotalCores"], + "metadata_items": ["maxServerMeta", "maxImageMeta"], } limits = {} for name, value in absolute_limits.iteritems(): if name in limit_names and value is not None: - limits[limit_names[name]] = value + for name in limit_names[name]: + limits[name] = value return limits -- cgit From 10816023a71cca189fb77a1989e3dd542a0e9c25 Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Thu, 19 May 2011 14:08:15 -0400 Subject: waldon's naming feedback --- nova/api/openstack/limits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index 032a5ff2f..bd0250a7f 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -66,7 +66,7 @@ class LimitsController(common.OpenstackController): Return all global and rate limit information. """ context = req.environ['nova.context'] - abs_limits = quota.get_quota(context, context.project_id) + abs_limits = quota.get_project_quotas(context, context.project_id) rate_limits = req.environ.get("nova.limits", []) builder = self._get_view_builder(req) -- cgit From 1c485a515b299551c44bd4411d82be1cccf5f4bd Mon Sep 17 00:00:00 2001 From: Mark Washenberger Date: Fri, 20 May 2011 00:24:35 -0400 Subject: add absolute limits support to 1.0 api as well --- nova/api/openstack/views/limits.py | 44 +++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index dd7681db4..33be12c0c 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -46,7 +46,26 @@ class ViewBuilder(object): return output def _build_absolute_limits(self, absolute_limits): - raise NotImplementedError() + """Builder for absolute limits + + absolute_limits should be given as a dict of limits. + For example: {"ram": 512, "gigabytes": 1024}. + + """ + limit_names = { + "ram": ["maxTotalRAMSize"], + "instances": ["maxTotalInstances"], + "cores": ["maxTotalCores"], + "metadata_items": ["maxServerMeta", "maxImageMeta"], + "injected_files": ["maxPersonality"], + "injected_file_content_bytes": ["maxPersonalitySize"], + } + limits = {} + for name, value in absolute_limits.iteritems(): + if name in limit_names and value is not None: + for name in limit_names[name]: + limits[name] = value + return limits def _build_rate_limits(self, rate_limits): raise NotImplementedError() @@ -72,9 +91,6 @@ class ViewBuilderV10(ViewBuilder): "resetTime": rate_limit["resetTime"], } - def _build_absolute_limits(self, absolute_limit): - return {} - class ViewBuilderV11(ViewBuilder): """Openstack API v1.1 limits view builder.""" @@ -113,23 +129,3 @@ class ViewBuilderV11(ViewBuilder): "unit": rate_limit["unit"], "next-available": rate_limit["resetTime"], } - - def _build_absolute_limits(self, absolute_limits): - """Builder for absolute limits - - absolute_limits should be given as a dict of limits. - For example: {"ram": 512, "gigabytes": 1024}. - - """ - limit_names = { - "ram": ["maxTotalRAMSize"], - "instances": ["maxTotalInstances"], - "cores": ["maxTotalCores"], - "metadata_items": ["maxServerMeta", "maxImageMeta"], - } - limits = {} - for name, value in absolute_limits.iteritems(): - if name in limit_names and value is not None: - for name in limit_names[name]: - limits[name] = value - return limits -- cgit From 968523ff49fc9d5aed7182b4084b2d7ec9f567ba Mon Sep 17 00:00:00 2001 From: "Dave Walker (Daviey)" Date: Sat, 21 May 2011 13:00:06 +0100 Subject: When adding a keypair that already exists, give a friendly error and no traceback in nova-api. --- nova/api/ec2/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'nova/api') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index cd59340bd..4686c32ec 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -338,6 +338,10 @@ class Executor(wsgi.Application): else: return self._error(req, context, type(ex).__name__, unicode(ex)) + except exception.KeyPairExists as ex: + LOG.info(_('KeyPairExists raised: %s'), unicode(ex), + context=context) + return self._error(req, context, type(ex).__name__, unicode(ex)) except Exception as ex: extra = {'environment': req.environ} LOG.exception(_('Unexpected error raised: %s'), unicode(ex), -- cgit From d72815193d64b9dcce974888bef05a18689c0504 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 23 May 2011 10:37:28 -0400 Subject: Fixed mistyped line --- nova/api/openstack/views/limits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index 22d1c260d..02fa0fdd6 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -79,7 +79,7 @@ class ViewBuilderV11(ViewBuilder): # check for existing key for limit in limits: if limit["uri"] == rate_limit["URI"] and \ - limit["regex"] == limit["regex"]: + limit["regex"] == rate_limit["regex"]: _rate_limit_key = limit break -- cgit From 107eedf06ba6d27e65169302bd51a391e6e104f7 Mon Sep 17 00:00:00 2001 From: "Dave Walker (Daviey)" Date: Mon, 23 May 2011 22:15:41 +0100 Subject: Changed ec2 api dupe key exception log handler info->debug --- nova/api/ec2/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 4686c32ec..c13993dd3 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -339,7 +339,7 @@ class Executor(wsgi.Application): return self._error(req, context, type(ex).__name__, unicode(ex)) except exception.KeyPairExists as ex: - LOG.info(_('KeyPairExists raised: %s'), unicode(ex), + LOG.debug(_('KeyPairExists raised: %s'), unicode(ex), context=context) return self._error(req, context, type(ex).__name__, unicode(ex)) except Exception as ex: -- cgit From e0aa1369d8050f023fee1e60b276d44a6298feb9 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Tue, 24 May 2011 21:09:43 -0700 Subject: instead of the API spawning a greenthread to wait for a host to be picked, the instance to boot, etc for setting the admin password... let's push the admin password down to the scheduler so that compute can just take care of setting the password as a part of the build process. --- nova/api/openstack/servers.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index fcb630fae..789c69977 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -180,7 +180,8 @@ class Controller(common.OpenstackController): key_name=key_name, key_data=key_data, metadata=env['server'].get('metadata', {}), - injected_files=injected_files) + injected_files=injected_files, + admin_password=password) except quota.QuotaError as error: self._handle_quota_error(error) @@ -190,8 +191,6 @@ class Controller(common.OpenstackController): builder = self._get_view_builder(req) server = builder.build(inst, is_detail=True) server['server']['adminPass'] = password - self.compute_api.set_admin_password(context, server['server']['id'], - password) return server def _deserialize_create(self, request): -- cgit From b933f90faecaddf7281455f4824577b586e07f0c Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Wed, 25 May 2011 17:55:51 +0000 Subject: updating admin_pass moved down to compute where the password is actually reset. only update if it succeeds. --- nova/api/openstack/servers.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 789c69977..5c10fc916 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -607,7 +607,6 @@ class ControllerV10(Controller): def _parse_update(self, context, server_id, inst_dict, update_dict): if 'adminPass' in inst_dict['server']: - update_dict['admin_pass'] = inst_dict['server']['adminPass'] self.compute_api.set_admin_password(context, server_id, inst_dict['server']['adminPass']) -- cgit