diff options
| author | Brian Waldon <brian.waldon@rackspace.com> | 2011-08-04 17:37:57 +0000 |
|---|---|---|
| committer | Tarmac <> | 2011-08-04 17:37:57 +0000 |
| commit | a9326d78c4493765f023106b2fa33df4faa33a93 (patch) | |
| tree | 23bfde7e6e5ed9fea6f04be093c2b8c60f9b9606 /nova/api | |
| parent | c52614791167b3986a3d196dc859a8683f437138 (diff) | |
| parent | 5826a793e7e05db8ccc14d15326245246fb652d4 (diff) | |
Update the OS API servers metadata resource to match the current v1.1 specification
- move /servers/<id>/meta to /servers/<id>/metadata
- add PUT /servers/<id>/metadata
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/openstack/__init__.py | 13 | ||||
| -rw-r--r-- | nova/api/openstack/common.py | 16 | ||||
| -rw-r--r-- | nova/api/openstack/create_instance_helper.py | 11 | ||||
| -rw-r--r-- | nova/api/openstack/server_metadata.py | 113 |
4 files changed, 107 insertions, 46 deletions
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 9ab8aeb58..d6a98c2cd 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -170,7 +170,9 @@ class APIRouterV11(APIRouter): def _setup_routes(self, mapper): super(APIRouterV11, self)._setup_routes(mapper, '1.1') + image_metadata_controller = image_metadata.create_resource() + mapper.resource("image_meta", "metadata", controller=image_metadata_controller, parent_resource=dict(member_name='image', @@ -181,7 +183,14 @@ class APIRouterV11(APIRouter): action='update_all', conditions={"method": ['PUT']}) - mapper.resource("server_meta", "meta", - controller=server_metadata.create_resource(), + server_metadata_controller = server_metadata.create_resource() + + mapper.resource("server_meta", "metadata", + controller=server_metadata_controller, parent_resource=dict(member_name='server', collection_name='servers')) + + mapper.connect("metadata", "/servers/{server_id}/metadata", + controller=server_metadata_controller, + action='update_all', + conditions={"method": ['PUT']}) diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index efa4ab385..829028169 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -196,7 +196,17 @@ def get_version_from_href(href): return version -class MetadataXMLDeserializer(wsgi.MetadataXMLDeserializer): +class MetadataXMLDeserializer(wsgi.XMLDeserializer): + + def extract_metadata(self, metadata_node): + """Marshal the metadata attribute of a parsed request""" + if metadata_node is None: + return {} + metadata = {} + for meta_node in self.find_children_named(metadata_node, "meta"): + key = meta_node.getAttribute("key") + metadata[key] = self.extract_text(meta_node) + return metadata def _extract_metadata_container(self, datastring): dom = minidom.parseString(datastring) @@ -247,7 +257,7 @@ class MetadataXMLSerializer(wsgi.XMLDictSerializer): container_node = self.meta_list_to_xml(xml_doc, items) xml_doc.appendChild(container_node) self._add_xmlns(container_node) - return xml_doc.toprettyxml(indent=' ', encoding='UTF-8') + return xml_doc.toxml('UTF-8') def index(self, metadata_dict): return self._meta_list_to_xml_string(metadata_dict) @@ -264,7 +274,7 @@ class MetadataXMLSerializer(wsgi.XMLDictSerializer): item_node = self._meta_item_to_xml(xml_doc, item_key, item_value) xml_doc.appendChild(item_node) self._add_xmlns(item_node) - return xml_doc.toprettyxml(indent=' ', encoding='UTF-8') + return xml_doc.toxml('UTF-8') def show(self, meta_item_dict): return self._meta_item_to_xml_string(meta_item_dict['meta']) diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 333994fcc..2a8e7fd7e 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -29,6 +29,7 @@ from nova import quota from nova import utils from nova.compute import instance_types +from nova.api.openstack import common from nova.api.openstack import wsgi @@ -293,7 +294,7 @@ class CreateInstanceHelper(object): return password -class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer): +class ServerXMLDeserializer(wsgi.XMLDeserializer): """ Deserializer to handle xml-formatted server create requests. @@ -301,6 +302,8 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer): and personality attributes """ + metadata_deserializer = common.MetadataXMLDeserializer() + def action(self, string): dom = minidom.parseString(string) action_node = dom.childNodes[0] @@ -329,7 +332,8 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer): if value: data[attribute] = value metadata_node = self.find_first_child_named(node, 'metadata') - data['metadata'] = self.extract_metadata(metadata_node) + metadata = self.metadata_deserializer.extract_metadata(metadata_node) + data['metadata'] = metadata return data def create(self, string): @@ -350,7 +354,8 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer): server[attr] = server_node.getAttribute(attr) metadata_node = self.find_first_child_named(server_node, "metadata") - server["metadata"] = self.extract_metadata(metadata_node) + server["metadata"] = self.metadata_deserializer.extract_metadata( + metadata_node) server["personality"] = self._extract_personality(server_node) diff --git a/nova/api/openstack/server_metadata.py b/nova/api/openstack/server_metadata.py index d4f42bbf5..b0b014f86 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.api.openstack import common from nova.api.openstack import wsgi from nova import exception from nova import quota @@ -31,36 +32,37 @@ class Controller(object): super(Controller, self).__init__() def _get_metadata(self, context, server_id): - metadata = self.compute_api.get_instance_metadata(context, server_id) + try: + meta = self.compute_api.get_instance_metadata(context, server_id) + except exception.InstanceNotFound: + msg = _('Server does not exist') + raise exc.HTTPNotFound(explanation=msg) + meta_dict = {} - for key, value in metadata.iteritems(): + for key, value in meta.iteritems(): meta_dict[key] = value - return dict(metadata=meta_dict) - - def _check_body(self, body): - if body == None or body == "": - expl = _('No Request Body') - raise exc.HTTPBadRequest(explanation=expl) + return meta_dict def index(self, req, server_id): """ Returns the list of metadata for a given instance """ context = req.environ['nova.context'] - try: - return self._get_metadata(context, server_id) - except exception.InstanceNotFound: - msg = _('Server %(server_id)s does not exist') % locals() - raise exc.HTTPNotFound(explanation=msg) + return {'metadata': self._get_metadata(context, server_id)} def create(self, req, server_id, body): - self._check_body(body) + try: + metadata = body['metadata'] + except (KeyError, TypeError): + msg = _("Malformed request body") + raise exc.HTTPBadRequest(explanation=msg) + context = req.environ['nova.context'] - metadata = body.get('metadata') + try: self.compute_api.update_or_create_instance_metadata(context, server_id, metadata) except exception.InstanceNotFound: - msg = _('Server %(server_id)s does not exist') % locals() + msg = _('Server does not exist') raise exc.HTTPNotFound(explanation=msg) except quota.QuotaError as error: @@ -69,51 +71,80 @@ class Controller(object): return body def update(self, req, server_id, id, body): - self._check_body(body) - context = req.environ['nova.context'] - if not id in body: + try: + meta_item = body['meta'] + except (TypeError, KeyError): + expl = _('Malformed request body') + raise exc.HTTPBadRequest(explanation=expl) + + try: + meta_value = meta_item.pop(id) + except (AttributeError, KeyError): expl = _('Request body and URI mismatch') raise exc.HTTPBadRequest(explanation=expl) - if len(body) > 1: + + if len(meta_item) > 0: expl = _('Request body contains too many items') raise exc.HTTPBadRequest(explanation=expl) + + context = req.environ['nova.context'] + self._set_instance_metadata(context, server_id, meta_item) + + return {'meta': {id: meta_value}} + + def update_all(self, req, server_id, body): + try: + metadata = body['metadata'] + except (TypeError, KeyError): + expl = _('Malformed request body') + raise exc.HTTPBadRequest(explanation=expl) + + context = req.environ['nova.context'] + self._set_instance_metadata(context, server_id, metadata) + + return {'metadata': metadata} + + def _set_instance_metadata(self, context, server_id, metadata): try: self.compute_api.update_or_create_instance_metadata(context, server_id, - body) + metadata) except exception.InstanceNotFound: - msg = _('Server %(server_id)s does not exist') % locals() + msg = _('Server does not exist') raise exc.HTTPNotFound(explanation=msg) + except ValueError: + msg = _("Malformed request body") + raise exc.HTTPBadRequest(explanation=msg) + except quota.QuotaError as error: self._handle_quota_error(error) - return body - def show(self, req, server_id, id): """ Return a single metadata item """ context = req.environ['nova.context'] - try: - data = self._get_metadata(context, server_id) - except exception.InstanceNotFound: - msg = _('Server %(server_id)s does not exist') % locals() - raise exc.HTTPNotFound(explanation=msg) + data = self._get_metadata(context, server_id) try: - return {id: data['metadata'][id]} + return {'meta': {id: data[id]}} except KeyError: - msg = _("metadata item %s was not found" % (id)) + msg = _("Metadata item was not found") raise exc.HTTPNotFound(explanation=msg) def delete(self, req, server_id, id): """ Deletes an existing metadata """ context = req.environ['nova.context'] + + metadata = self._get_metadata(context, server_id) + try: - self.compute_api.delete_instance_metadata(context, server_id, id) - except exception.InstanceNotFound: - msg = _('Server %(server_id)s does not exist') % locals() + meta_key = metadata[id] + except KeyError: + msg = _("Metadata item was not found") raise exc.HTTPNotFound(explanation=msg) + self.compute_api.delete_instance_metadata(context, server_id, meta_key) + def _handle_quota_error(self, error): """Reraise quota errors as api-specific http exceptions.""" if error.code == "MetadataLimitExceeded": @@ -122,10 +153,16 @@ class Controller(object): def create_resource(): - body_serializers = { - 'application/xml': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V11), + headers_serializer = common.MetadataHeadersSerializer() + + body_deserializers = { + 'application/xml': common.MetadataXMLDeserializer(), } - serializer = wsgi.ResponseSerializer(body_serializers) + body_serializers = { + 'application/xml': common.MetadataXMLSerializer(), + } + serializer = wsgi.ResponseSerializer(body_serializers, headers_serializer) + deserializer = wsgi.RequestDeserializer(body_deserializers) - return wsgi.Resource(Controller(), serializer=serializer) + return wsgi.Resource(Controller(), deserializer, serializer) |
