From 54be28647ac3ad401006bca3069b1dfc1a65d093 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 12 Jul 2011 14:35:09 -0400 Subject: server create deserialization functional and tested --- nova/api/openstack/create_instance_helper.py | 81 ++++++++++++++++++++-------- nova/api/openstack/servers.py | 63 ++++++++++++++++++++-- nova/api/openstack/wsgi.py | 21 ++++++++ 3 files changed, 139 insertions(+), 26 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 2654e3c40..eea973a56 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -180,7 +180,7 @@ class CreateInstanceHelper(object): Overrides normal behavior in the case of xml content """ if request.content_type == "application/xml": - deserializer = ServerCreateRequestXMLDeserializer() + deserializer = ServerXMLDeserializer() return deserializer.deserialize(request.body) else: return self._deserialize(request.body, request.get_content_type()) @@ -295,9 +295,15 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): """Marshal the server attribute of a parsed request""" server = {} server_node = self._find_first_child_named(node, 'server') - for attr in ["name", "imageId", "flavorId", "imageRef", "flavorRef"]: + for attr in ["name", "imageId", "flavorId"]: if server_node.getAttribute(attr): server[attr] = server_node.getAttribute(attr) + image = self._extract_image(server_node) + if image is not None: + server["image"] = image + flavor = self._extract_flavor(server_node) + if flavor is not None: + server["flavor"] = flavor metadata = self._extract_metadata(server_node) if metadata is not None: server["metadata"] = metadata @@ -306,6 +312,56 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): server["personality"] = personality return server + def _extract_image(self, server_node): + """Retrieve an image entity from the server node""" + image_node = self._find_first_child_named(server_node, "image") + if image_node is None: + return None + + image = {} + image_id = image_node.getAttribute('id') + if image_id: + image['id'] = image_id + + image_links = self._extract_links_from_node(image_node) + if len(image_links) > 0: + image['links'] = image_links + + return image + + def _extract_flavor(self, server_node): + """Retrieve a flavor entity from the server node""" + flavor_node = self._find_first_child_named(server_node, "flavor") + if flavor_node is None: + return None + + flavor = {} + flavor_id = flavor_node.getAttribute('id') + if flavor_id: + flavor['id'] = flavor_id + + flavor_links = self._extract_links_from_node(flavor_node) + if len(flavor_links) > 0: + flavor['links'] = flavor_links + + return flavor + + def _extract_links_from_node(self, parent_node): + """Retrieve link entities from a links container provided node""" + links = [] + + for link_node in self._find_children_named(parent_node, 'atom:link'): + link = {} + link_rel = link_node.getAttribute('rel') + if link_rel is not None: + link['rel'] = link_rel + link_href = link_node.getAttribute('href') + if link_href is not None: + link['href'] = link_href + links.append(link) + + return links + def _extract_metadata(self, server_node): """Marshal the metadata attribute of a parsed request""" metadata_node = self._find_first_child_named(server_node, "metadata") @@ -331,24 +387,3 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): item["contents"] = self._extract_text(file_node) personality.append(item) return personality - - def _find_first_child_named(self, parent, name): - """Search a nodes children for the first child with a given name""" - for node in parent.childNodes: - if node.nodeName == name: - return node - return None - - def _find_children_named(self, parent, name): - """Return all of a nodes children who have the given name""" - for node in parent.childNodes: - if node.nodeName == name: - yield node - - def _extract_text(self, node): - """Get the text field contained by the given node""" - if len(node.childNodes) == 1: - child = node.childNodes[0] - if child.nodeType == child.TEXT_NODE: - return child.nodeValue - return "" diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 12af44a8d..f239044ff 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -492,11 +492,68 @@ class ControllerV11(Controller): return faults.Fault(exc.HTTPNotFound()) def _image_ref_from_req_data(self, data): - return data['server']['imageRef'] + try: + image = data['server']['image'] + except (AttributeError, KeyError): + msg = _("Missing image entity") + raise exc.HTTPBadRequest(explanation=msg) + + try: + links = image.get('links', []) + except AttributeError: + msg = _("Malformed image entity") + raise exc.HTTPBadRequest(explanation=msg) + + image_ref = None + for link in links: + try: + if link.get('rel') == 'bookmark': + image_ref = link.get('href') + break + except AttributeError: + msg = _("Malformed image link") + raise exc.HTTPBadRequest(explanation=msg) + + if image_ref is None: + try: + image_ref = image['id'] + except KeyError: + msg = _("Missing id attribute on image entity") + raise exc.HTTPBadRequest(explanation=msg) + + return image_ref def _flavor_id_from_req_data(self, data): - href = data['server']['flavorRef'] - return common.get_id_from_href(href) + try: + flavor = data['server']['flavor'] + except (AttributeError, KeyError): + msg = _("Missing flavor entity") + raise exc.HTTPBadRequest(explanation=msg) + + try: + links = flavor.get('links', []) + except AttributeError: + msg = _("Malformed flavor entity") + raise exc.HTTPBadRequest(explanation=msg) + + flavor_ref = None + for link in links: + try: + if link.get('rel') == 'bookmark': + flavor_ref = link.get('href') + break + except AttributeError: + msg = _("Malformed flavor link") + raise exc.HTTPBadRequest(explanation=msg) + + if flavor_ref is None: + try: + return flavor['id'] + except (KeyError, AttributeError): + msg = _("Missing id attribute in flavor entity") + raise exc.HTTPBadRequest(explanation=msg) + else: + return common.get_id_from_href(flavor_ref) def _get_view_builder(self, req): base_url = req.application_url diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 8eff9e441..0ece2cff0 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -134,6 +134,27 @@ class XMLDeserializer(TextDeserializer): listnames) return result + def _find_first_child_named(self, parent, name): + """Search a nodes children for the first child with a given name""" + for node in parent.childNodes: + if node.nodeName == name: + return node + return None + + def _find_children_named(self, parent, name): + """Return all of a nodes children who have the given name""" + for node in parent.childNodes: + if node.nodeName == name: + yield node + + def _extract_text(self, node): + """Get the text field contained by the given node""" + if len(node.childNodes) == 1: + child = node.childNodes[0] + if child.nodeType == child.TEXT_NODE: + return child.nodeValue + return "" + def default(self, datastring): return {'body': self._from_xml(datastring)} -- cgit From 07baabb67d9491da61fa5bfe9adc52f7ff744e22 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 12 Jul 2011 16:02:39 -0400 Subject: cleanup --- nova/api/openstack/create_instance_helper.py | 24 ++++++---------- nova/api/openstack/servers.py | 41 ++++++++++++---------------- 2 files changed, 27 insertions(+), 38 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index eea973a56..e46bc9d98 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -320,12 +320,10 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): image = {} image_id = image_node.getAttribute('id') - if image_id: + if image_id is not None: image['id'] = image_id - image_links = self._extract_links_from_node(image_node) - if len(image_links) > 0: - image['links'] = image_links + image['links'] = self._extract_links_from_node(image_node) return image @@ -340,9 +338,7 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): if flavor_id: flavor['id'] = flavor_id - flavor_links = self._extract_links_from_node(flavor_node) - if len(flavor_links) > 0: - flavor['links'] = flavor_links + flavor['links'] = self._extract_links_from_node(flavor_node) return flavor @@ -351,14 +347,12 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): links = [] for link_node in self._find_children_named(parent_node, 'atom:link'): - link = {} - link_rel = link_node.getAttribute('rel') - if link_rel is not None: - link['rel'] = link_rel - link_href = link_node.getAttribute('href') - if link_href is not None: - link['href'] = link_href - links.append(link) + link = { + 'rel': link_node.getAttribute('rel'), + 'href': link_node.getAttribute('href'), + } + if link['rel'] is not None and link['href'] is not None: + links.append(link) return links diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index f239044ff..1e8749f56 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -491,10 +491,21 @@ class ControllerV11(Controller): except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) + def _href_from_bookmark_links(self, links) + for link in links: + try: + if link.get('rel') == 'bookmark': + href = link.get('href') + if href is not None: + return href + except AttributeError: + msg = _("Malformed link entity") + raise exc.HTTPBadRequest(explanation=msg) + def _image_ref_from_req_data(self, data): try: image = data['server']['image'] - except (AttributeError, KeyError): + except (TypeError, KeyError): msg = _("Missing image entity") raise exc.HTTPBadRequest(explanation=msg) @@ -504,29 +515,21 @@ class ControllerV11(Controller): msg = _("Malformed image entity") raise exc.HTTPBadRequest(explanation=msg) - image_ref = None - for link in links: - try: - if link.get('rel') == 'bookmark': - image_ref = link.get('href') - break - except AttributeError: - msg = _("Malformed image link") - raise exc.HTTPBadRequest(explanation=msg) + image_ref = self._href_from_bookmark_links(links) if image_ref is None: try: - image_ref = image['id'] + return image['id'] except KeyError: msg = _("Missing id attribute on image entity") raise exc.HTTPBadRequest(explanation=msg) - - return image_ref + else: + return image_ref def _flavor_id_from_req_data(self, data): try: flavor = data['server']['flavor'] - except (AttributeError, KeyError): + except (TypeError, KeyError): msg = _("Missing flavor entity") raise exc.HTTPBadRequest(explanation=msg) @@ -536,15 +539,7 @@ class ControllerV11(Controller): msg = _("Malformed flavor entity") raise exc.HTTPBadRequest(explanation=msg) - flavor_ref = None - for link in links: - try: - if link.get('rel') == 'bookmark': - flavor_ref = link.get('href') - break - except AttributeError: - msg = _("Malformed flavor link") - raise exc.HTTPBadRequest(explanation=msg) + flavor_ref = self._href_from_bookmark_links(links) if flavor_ref is None: try: -- cgit From 486afc9b9e38a68c18b80daab4f23c5b936ee185 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 13 Jul 2011 11:17:05 -0400 Subject: pep8 --- 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 1e8749f56..50d1442d4 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -491,7 +491,7 @@ class ControllerV11(Controller): except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - def _href_from_bookmark_links(self, links) + def _href_from_bookmark_links(self, links): for link in links: try: if link.get('rel') == 'bookmark': -- cgit From 64a9c37cbf070345831ba6e4db646c5d972e179b Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sat, 16 Jul 2011 19:17:08 -0400 Subject: Added ServerXMLSerializer with working 'show' method Factored out MetadataXMLSerializer from images and servers into common --- nova/api/openstack/common.py | 50 ++++++++++++++++++++ nova/api/openstack/image_metadata.py | 49 -------------------- nova/api/openstack/images.py | 4 +- nova/api/openstack/servers.py | 89 ++++++++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 51 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 8e12ce0c0..8a78292aa 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -17,12 +17,14 @@ import re from urlparse import urlparse +from xml.dom import minidom import webob from nova import exception from nova import flags from nova import log as logging +from nova.api.openstack import wsgi LOG = logging.getLogger('nova.api.openstack.common') @@ -162,3 +164,51 @@ def remove_version_from_href(href): msg = _('href does not contain version') raise ValueError(msg) return new_href + + +class MetadataXMLSerializer(wsgi.XMLDictSerializer): + def __init__(self, xmlns=wsgi.XMLNS_V11): + super(MetadataXMLSerializer, self).__init__(xmlns=xmlns) + + def _meta_item_to_xml(self, doc, key, value): + node = doc.createElement('meta') + doc.appendChild(node) + node.setAttribute('key', '%s' % key) + text = doc.createTextNode('%s' % value) + node.appendChild(text) + return node + + def meta_list_to_xml(self, xml_doc, meta_items): + container_node = xml_doc.createElement('metadata') + for (key, value) in meta_items: + item_node = self._meta_item_to_xml(xml_doc, key, value) + container_node.appendChild(item_node) + return container_node + + def _meta_list_to_xml_string(self, metadata_dict): + xml_doc = minidom.Document() + items = metadata_dict['metadata'].items() + 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') + + def index(self, metadata_dict): + return self._meta_list_to_xml_string(metadata_dict) + + def create(self, metadata_dict): + return self._meta_list_to_xml_string(metadata_dict) + + def _meta_item_to_xml_string(self, meta_item_dict): + xml_doc = minidom.Document() + item_key, item_value = meta_item_dict.items()[0] + 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') + + def show(self, meta_item_dict): + return self._meta_item_to_xml_string(meta_item_dict['meta']) + + def update(self, meta_item_dict): + return self._meta_item_to_xml_string(meta_item_dict['meta']) diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index 4f33844fa..dd1a3f130 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -16,7 +16,6 @@ # under the License. from webob import exc -from xml.dom import minidom from nova import flags from nova import image @@ -111,54 +110,6 @@ class Controller(object): self.image_service.update(context, image_id, img, None) -class ImageMetadataXMLSerializer(wsgi.XMLDictSerializer): - def __init__(self, xmlns=wsgi.XMLNS_V11): - super(ImageMetadataXMLSerializer, self).__init__(xmlns=xmlns) - - def _meta_item_to_xml(self, doc, key, value): - node = doc.createElement('meta') - doc.appendChild(node) - node.setAttribute('key', '%s' % key) - text = doc.createTextNode('%s' % value) - node.appendChild(text) - return node - - def meta_list_to_xml(self, xml_doc, meta_items): - container_node = xml_doc.createElement('metadata') - for (key, value) in meta_items: - item_node = self._meta_item_to_xml(xml_doc, key, value) - container_node.appendChild(item_node) - return container_node - - def _meta_list_to_xml_string(self, metadata_dict): - xml_doc = minidom.Document() - items = metadata_dict['metadata'].items() - 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') - - def index(self, metadata_dict): - return self._meta_list_to_xml_string(metadata_dict) - - def create(self, metadata_dict): - return self._meta_list_to_xml_string(metadata_dict) - - def _meta_item_to_xml_string(self, meta_item_dict): - xml_doc = minidom.Document() - item_key, item_value = meta_item_dict.items()[0] - 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') - - def show(self, meta_item_dict): - return self._meta_item_to_xml_string(meta_item_dict['meta']) - - def update(self, meta_item_dict): - return self._meta_item_to_xml_string(meta_item_dict['meta']) - - def create_resource(): body_serializers = { 'application/xml': ImageMetadataXMLSerializer(), diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index d0317583e..6c7c0feb9 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -278,9 +278,9 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer): xmlns = wsgi.XMLNS_V11 def __init__(self): - self.metadata_serializer = image_metadata.ImageMetadataXMLSerializer() + self.metadata_serializer = common.MetadataXMLSerializer() - def _image_to_xml(self, xml_doc, image): + def image_to_xml(self, xml_doc, image): image_node = xml_doc.createElement('image') image_node.setAttribute('id', str(image['id'])) image_node.setAttribute('name', image['name']) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 93f8e832c..b07b903f8 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -17,6 +17,7 @@ import base64 import traceback from webob import exc +from xml.dom import minidom from nova import compute from nova import db @@ -612,6 +613,94 @@ class HeadersSerializer(wsgi.ResponseHeadersSerializer): response.status_int = 204 +class ServerXMLSerializer(wsgi.XMLDictSerializer): + + xmlns = wsgi.XMLNS_V11 + + def __init__(self): + self.metadata_serializer = common.MetadataXMLSerializer() + + def _create_basic_entity_node(self, xml_doc, id, links, name): + basic_node = xml_doc.createElement(name) + basic_node.setAttribute('id', str(id)) + link_nodes = self._create_link_nodes(xml_doc, links) + for link_node in link_nodes: + basic_node.appendChild(link_node) + return basic_node + + def _create_metadata_node(self, xml_doc, metadata): + return self.metadata_serializer.meta_list_to_xml(xml_doc, metadata) + + def _create_addresses_node(self, xml_doc, addresses): + addresses_node = xml_doc.createElement('addresses') + for name, network_dict in addresses.items(): + network_node = self._create_network_node(xml_doc, + name, + network_dict) + addresses_node.appendChild(network_node) + return addresses_node + + def _create_network_node(self, xml_doc, network_name, network_dict): + network_node = xml_doc.createElement('network') + network_node.setAttribute('id', network_name) + for ip in network_dict: + ip_node = xml_doc.createElement('ip') + ip_node.setAttribute('version', str(ip['version'])) + ip_node.setAttribute('addr', ip['addr']) + network_node.appendChild(ip_node) + return network_node + + + def _add_server_attributes(self, node, server): + node.setAttribute('id', str(server['id'])) + node.setAttribute('uuid', str(server['uuid'])) + node.setAttribute('hostId', str(server['hostId'])) + node.setAttribute('name', server['name']) + node.setAttribute('created', server['created']) + node.setAttribute('updated', server['updated']) + node.setAttribute('status', server['status']) + if 'progress' in server: + node.setAttribute('progress', str(server['progress'])) + + def _server_to_xml_detailed(self, xml_doc, server): + server_node = xml_doc.createElement('server') + self._add_server_attributes(server_node, server) + + link_nodes = self._create_link_nodes(xml_doc, + server['links']) + for link_node in link_nodes: + server_node.appendChild(link_node) + + image_node = self._create_basic_entity_node(xml_doc, + server['image']['id'], + server['image']['links'], + 'image') + server_node.appendChild(image_node) + + flavor_node = self._create_basic_entity_node(xml_doc, + server['flavor']['id'], + server['flavor']['links'], + 'flavor') + server_node.appendChild(flavor_node) + + metadata = server.get('metadata', {}).items() + if len(metadata) > 0: + metadata_node = self._create_metadata_node(xml_doc, metadata) + server_node.appendChild(metadata_node) + + addresses_node = self._create_addresses_node(xml_doc, + server['addresses']) + server_node.appendChild(addresses_node) + + return server_node + + def show(self, server_dict): + xml_doc = minidom.Document() + node = self._server_to_xml_detailed(xml_doc, + server_dict['server']) + return self.to_xml_string(node, True) + + def create_resource(version='1.0'): controller = { '1.0': ControllerV10, -- cgit From 7af043463a350cfc71c45ff719354511173b5c39 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sat, 16 Jul 2011 19:39:27 -0400 Subject: Moved Metadata Serialization Test --- nova/api/openstack/image_metadata.py | 3 ++- nova/api/openstack/images.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index dd1a3f130..d1065a4e3 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -21,6 +21,7 @@ from nova import flags from nova import image from nova import quota from nova import utils +from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack import wsgi @@ -112,7 +113,7 @@ class Controller(object): def create_resource(): body_serializers = { - 'application/xml': ImageMetadataXMLSerializer(), + 'application/xml': common.MetadataXMLSerializer(), } serializer = wsgi.ResponseSerializer(body_serializers) diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 6c7c0feb9..df7bf0cf9 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -280,7 +280,7 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer): def __init__(self): self.metadata_serializer = common.MetadataXMLSerializer() - def image_to_xml(self, xml_doc, image): + def _image_to_xml(self, xml_doc, image): image_node = xml_doc.createElement('image') image_node.setAttribute('id', str(image['id'])) image_node.setAttribute('name', image['name']) -- cgit From c538d38d890e74382e928d225e8abdc57da9760e Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sat, 16 Jul 2011 19:45:28 -0400 Subject: pep8 --- nova/api/openstack/image_metadata.py | 2 +- nova/api/openstack/servers.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index d1065a4e3..b9b782f92 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -21,7 +21,7 @@ from nova import flags from nova import image from nova import quota from nova import utils -from nova.api.openstack import common +from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack import wsgi diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index b07b903f8..1a85fda58 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -650,7 +650,6 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): network_node.appendChild(ip_node) return network_node - def _add_server_attributes(self, node, server): node.setAttribute('id', str(server['id'])) node.setAttribute('uuid', str(server['uuid'])) -- cgit From 712493f65415a7a5fc727f6b316c66ef90f1cad5 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 14:50:44 -0400 Subject: added index to servers xml serializer --- nova/api/openstack/servers.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 1a85fda58..8d59c8626 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -661,6 +661,16 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): if 'progress' in server: node.setAttribute('progress', str(server['progress'])) + def _server_to_xml(self, xml_doc, server): + server_node = xml_doc.createElement('server') + server_node.setAttribute('id', str(server['id'])) + server_node.setAttribute('name', server['name']) + link_nodes = self._create_link_nodes(xml_doc, + server['links']) + for link_node in link_nodes: + server_node.appendChild(link_node) + return server_node + def _server_to_xml_detailed(self, xml_doc, server): server_node = xml_doc.createElement('server') self._add_server_attributes(server_node, server) @@ -693,6 +703,25 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): return server_node + def _server_list_to_xml(self, xml_doc, servers, detailed): + container_node = xml_doc.createElement('servers') + if detailed: + server_to_xml = self._server_to_xml_detailed + else: + server_to_xml = self._server_to_xml + + for server in servers: + item_node = server_to_xml(xml_doc, server) + container_node.appendChild(item_node) + return container_node + + def index(self, servers_dict): + xml_doc = minidom.Document() + node = self._server_list_to_xml(xml_doc, + servers_dict['servers'], + detailed=False) + return self.to_xml_string(node, True) + def show(self, server_dict): xml_doc = minidom.Document() node = self._server_to_xml_detailed(xml_doc, -- cgit From baaaa80d36570d5734ac823bc49be8ff2477e5c2 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 21:24:02 -0400 Subject: added 'detail' to server XML serializer --- 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 8d59c8626..82630397f 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -722,6 +722,13 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): detailed=False) return self.to_xml_string(node, True) + def detail(self, servers_dict): + xml_doc = minidom.Document() + node = self._server_list_to_xml(xml_doc, + servers_dict['servers'], + detailed=True) + return self.to_xml_string(node, True) + def show(self, server_dict): xml_doc = minidom.Document() node = self._server_to_xml_detailed(xml_doc, -- cgit From 8ab775585fee4af7b30a28a5bffae46c23ec76d1 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 21:36:57 -0400 Subject: added 'create' to server XML serializer --- 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 82630397f..4a29e1454 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -735,6 +735,13 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): server_dict['server']) return self.to_xml_string(node, True) + def create(self, server_dict): + xml_doc = minidom.Document() + node = self._server_to_xml_detailed(xml_doc, + server_dict['server']) + node.setAttribute('adminPass', server_dict['server']['adminPass']) + return self.to_xml_string(node, True) + def create_resource(version='1.0'): controller = { -- cgit From e23e70afd096ca1d7ad22c776f6f439986bbc8b5 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 22:28:16 -0400 Subject: updated servers to use ServerXMLSerializer --- nova/api/openstack/servers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4a29e1454..a6229125d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -773,8 +773,7 @@ def create_resource(version='1.0'): headers_serializer = HeadersSerializer() body_serializers = { - 'application/xml': wsgi.XMLDictSerializer(metadata=metadata, - xmlns=xmlns), + 'application/xml': ServerXMLSerializer(), } body_deserializers = { -- cgit From b9d316452a1e2a204e56d1434feade1ab0bd281c Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 22:50:10 -0400 Subject: Updated servers to choose XML serializer based on api version --- nova/api/openstack/servers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index a6229125d..6d55b856d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -772,8 +772,13 @@ def create_resource(version='1.0'): headers_serializer = HeadersSerializer() + xml_serializer = { + '1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10), + '1.1': ServerXMLSerializer(), + }[version] + body_serializers = { - 'application/xml': ServerXMLSerializer(), + 'application/xml': xml_serializer, } body_deserializers = { -- cgit From 422d5329276f5c2252d7328d4112be7c696a274a Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 26 Jul 2011 09:57:39 -0400 Subject: Updated ServerXMLSerializer to utilize the IPXMLSerializer --- nova/api/openstack/servers.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4e6f0d7b5..11dafc272 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -28,6 +28,7 @@ from nova import log as logging from nova import utils from nova.api.openstack import common from nova.api.openstack import create_instance_helper as helper +from nova.api.openstack import ips import nova.api.openstack.views.addresses import nova.api.openstack.views.flavors import nova.api.openstack.views.images @@ -608,6 +609,7 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): def __init__(self): self.metadata_serializer = common.MetadataXMLSerializer() + self.addresses_serializer = ips.IPXMLSerializer() def _create_basic_entity_node(self, xml_doc, id, links, name): basic_node = xml_doc.createElement(name) @@ -621,23 +623,7 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): return self.metadata_serializer.meta_list_to_xml(xml_doc, metadata) def _create_addresses_node(self, xml_doc, addresses): - addresses_node = xml_doc.createElement('addresses') - for name, network_dict in addresses.items(): - network_node = self._create_network_node(xml_doc, - name, - network_dict) - addresses_node.appendChild(network_node) - return addresses_node - - def _create_network_node(self, xml_doc, network_name, network_dict): - network_node = xml_doc.createElement('network') - network_node.setAttribute('id', network_name) - for ip in network_dict: - ip_node = xml_doc.createElement('ip') - ip_node.setAttribute('version', str(ip['version'])) - ip_node.setAttribute('addr', ip['addr']) - network_node.appendChild(ip_node) - return network_node + return self.addresses_serializer.networks_to_xml(xml_doc, addresses) def _add_server_attributes(self, node, server): node.setAttribute('id', str(server['id'])) -- cgit From 1ad5f2eaf49904d8e14546d59699b1472a1a5bb2 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 12:57:06 -0400 Subject: xml deserialization works now --- nova/api/openstack/create_instance_helper.py | 79 ++++++---------------------- nova/api/openstack/wsgi.py | 9 ++-- 2 files changed, 19 insertions(+), 69 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 03272443a..b717b8ac0 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -303,79 +303,30 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer): """Marshal the server attribute of a parsed request""" server = {} server_node = self.find_first_child_named(node, 'server') - for attr in ["name", "imageId", "flavorId"]: + + attributes = ["name", "imageId", "flavorId", "imageRef", + "flavorRef", "adminPass"] + for attr in attributes: if server_node.getAttribute(attr): server[attr] = server_node.getAttribute(attr) - image = self._extract_image(server_node) - if image is not None: - server["image"] = image - flavor = self._extract_flavor(server_node) - if flavor is not None: - server["flavor"] = flavor - metadata_node = self.find_first_child_named(server_node, "metadata") - metadata = self.extract_metadata(metadata_node) - if metadata is not None: - server["metadata"] = metadata - personality = self._extract_personality(server_node) - if personality is not None: - server["personality"] = personality - return server - - def _extract_image(self, server_node): - """Retrieve an image entity from the server node""" - image_node = self.find_first_child_named(server_node, "image") - if image_node is None: - return None - - image = {} - image_id = image_node.getAttribute('id') - if image_id is not None: - image['id'] = image_id - - image['links'] = self._extract_links_from_node(image_node) - - return image - def _extract_flavor(self, server_node): - """Retrieve a flavor entity from the server node""" - flavor_node = self.find_first_child_named(server_node, "flavor") - if flavor_node is None: - return None - - flavor = {} - flavor_id = flavor_node.getAttribute('id') - if flavor_id: - flavor['id'] = flavor_id - - flavor['links'] = self._extract_links_from_node(flavor_node) - - return flavor - - def _extract_links_from_node(self, parent_node): - """Retrieve link entities from a links container provided node""" - links = [] + metadata_node = self.find_first_child_named(server_node, "metadata") + server["metadata"] = self.extract_metadata(metadata_node) - for link_node in self.find_children_named(parent_node, 'atom:link'): - link = { - 'rel': link_node.getAttribute('rel'), - 'href': link_node.getAttribute('href'), - } - if link['rel'] is not None and link['href'] is not None: - links.append(link) + server["personality"] = self._extract_personality(server_node) - return links + return server def _extract_personality(self, server_node): """Marshal the personality attribute of a parsed request""" personality_node = \ self.find_first_child_named(server_node, "personality") - if personality_node is None: - return None personality = [] - for file_node in self.find_children_named(personality_node, "file"): - item = {} - if file_node.hasAttribute("path"): - item["path"] = file_node.getAttribute("path") - item["contents"] = self.extract_text(file_node) - personality.append(item) + if personality_node is not None: + for file_node in self.find_children_named(personality_node, "file"): + item = {} + if file_node.hasAttribute("path"): + item["path"] = file_node.getAttribute("path") + item["contents"] = self.extract_text(file_node) + personality.append(item) return personality diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index a28443d12..53dab22e8 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -165,12 +165,11 @@ class MetadataXMLDeserializer(XMLDeserializer): def extract_metadata(self, metadata_node): """Marshal the metadata attribute of a parsed request""" - if metadata_node is None: - return None metadata = {} - for meta_node in self.find_children_named(metadata_node, "meta"): - key = meta_node.getAttribute("key") - metadata[key] = self.extract_text(meta_node) + if metadata_node is not None: + 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 -- cgit From 3db1c53486fdb669ac2bab303335548d7a7c617d Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 13:28:11 -0400 Subject: updating imageRef and flavorRef parsing --- nova/api/openstack/servers.py | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index e1f845f36..06112eee3 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -493,51 +493,19 @@ class ControllerV11(Controller): def _image_ref_from_req_data(self, data): try: - image = data['server']['image'] + return data['server']['imageRef'] except (TypeError, KeyError): - msg = _("Missing image entity") + msg = _("Missing imageRef attribute") raise exc.HTTPBadRequest(explanation=msg) - try: - links = image.get('links', []) - except AttributeError: - msg = _("Malformed image entity") - raise exc.HTTPBadRequest(explanation=msg) - - image_ref = self._href_from_bookmark_links(links) - - if image_ref is None: - try: - return image['id'] - except KeyError: - msg = _("Missing id attribute on image entity") - raise exc.HTTPBadRequest(explanation=msg) - else: - return image_ref - def _flavor_id_from_req_data(self, data): try: - flavor = data['server']['flavor'] + flavor_ref = data['server']['flavorRef'] except (TypeError, KeyError): - msg = _("Missing flavor entity") + msg = _("Missing flavorRef attribute") raise exc.HTTPBadRequest(explanation=msg) - try: - links = flavor.get('links', []) - except AttributeError: - msg = _("Malformed flavor entity") - raise exc.HTTPBadRequest(explanation=msg) - - flavor_ref = self._href_from_bookmark_links(links) - - if flavor_ref is None: - try: - return flavor['id'] - except (KeyError, AttributeError): - msg = _("Missing id attribute in flavor entity") - raise exc.HTTPBadRequest(explanation=msg) - else: - return common.get_id_from_href(flavor_ref) + return common.get_id_from_href(flavor_ref) def _build_view(self, req, instance, is_detail=False): base_url = req.application_url -- cgit From 94866fef798a6b72061720cb654442cd194b9f5f Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 13:47:37 -0400 Subject: reverting tests to use imageRef, flavorRef --- nova/api/openstack/create_instance_helper.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index b717b8ac0..1342397c4 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -319,11 +319,10 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer): def _extract_personality(self, server_node): """Marshal the personality attribute of a parsed request""" - personality_node = \ - self.find_first_child_named(server_node, "personality") + node = self.find_first_child_named(server_node, "personality") personality = [] - if personality_node is not None: - for file_node in self.find_children_named(personality_node, "file"): + if node is not None: + for file_node in self.find_children_named(node, "file"): item = {} if file_node.hasAttribute("path"): item["path"] = file_node.getAttribute("path") -- cgit From 7cd146e7e658c51cc94664d8da8d2bc15b0141fc Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 26 Jul 2011 13:49:04 -0400 Subject: fixed minor issues --- nova/api/openstack/servers.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 11dafc272..194ec82d5 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -630,8 +630,8 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): node.setAttribute('uuid', str(server['uuid'])) node.setAttribute('hostId', str(server['hostId'])) node.setAttribute('name', server['name']) - node.setAttribute('created', server['created']) - node.setAttribute('updated', server['updated']) + node.setAttribute('created', str(server['created'])) + node.setAttribute('updated', str(server['updated'])) node.setAttribute('status', server['status']) if 'progress' in server: node.setAttribute('progress', str(server['progress'])) @@ -655,17 +655,19 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): for link_node in link_nodes: server_node.appendChild(link_node) - image_node = self._create_basic_entity_node(xml_doc, + if 'image' in server: + image_node = self._create_basic_entity_node(xml_doc, server['image']['id'], server['image']['links'], 'image') - server_node.appendChild(image_node) + server_node.appendChild(image_node) - flavor_node = self._create_basic_entity_node(xml_doc, + if 'flavor' in server: + flavor_node = self._create_basic_entity_node(xml_doc, server['flavor']['id'], server['flavor']['links'], 'flavor') - server_node.appendChild(flavor_node) + server_node.appendChild(flavor_node) metadata = server.get('metadata', {}).items() if len(metadata) > 0: -- cgit From 24e1f23dbaf9ffd3f42fe05c24b980a6a0f09499 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 14:06:02 -0400 Subject: removing extra function --- nova/api/openstack/servers.py | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 06112eee3..618778ea3 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -480,17 +480,6 @@ class ControllerV11(Controller): except exception.NotFound: raise exc.HTTPNotFound() - def _href_from_bookmark_links(self, links): - for link in links: - try: - if link.get('rel') == 'bookmark': - href = link.get('href') - if href is not None: - return href - except AttributeError: - msg = _("Malformed link entity") - raise exc.HTTPBadRequest(explanation=msg) - def _image_ref_from_req_data(self, data): try: return data['server']['imageRef'] -- cgit From 2e652f4cc72976ecc471a6c6f3b48afb3eb5a420 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 26 Jul 2011 16:42:16 -0400 Subject: Updated test stubs to contain the correct data Updated created and updated in responses to use correct time format --- nova/api/openstack/views/servers.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index be25e1e40..c90801724 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -15,6 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime import hashlib import os @@ -149,8 +150,10 @@ class ViewBuilderV11(ViewBuilder): def _build_detail(self, inst): response = super(ViewBuilderV11, self)._build_detail(inst) - response['server']['created'] = inst['created_at'] - response['server']['updated'] = inst['updated_at'] + response['server']['created'] = \ + self._convert_timeformat(inst['created_at']) + response['server']['updated'] = \ + self._convert_timeformat(inst['updated_at']) if 'status' in response['server']: if response['server']['status'] == "ACTIVE": response['server']['progress'] = 100 @@ -221,3 +224,11 @@ class ViewBuilderV11(ViewBuilder): """Create an url that refers to a specific flavor id.""" return os.path.join(common.remove_version_from_href(self.base_url), "servers", str(server_id)) + + def _convert_timeformat(self, time): + """Converts the given time into the common time format + + :param time: should be a datetime + + """ + return time.strftime(utils.TIME_FORMAT) -- cgit From 0300c952d925ccaad2d3d4191d87c08656d4b413 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 27 Jul 2011 12:54:12 -0400 Subject: removed unused import --- nova/api/openstack/image_metadata.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index da753dee5..aaf64a123 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -22,7 +22,6 @@ from nova import image from nova import quota from nova import utils from nova.api.openstack import common -from nova.api.openstack import faults from nova.api.openstack import wsgi -- cgit From b8183e11e56781fce27ec1af261c5e53bca78ca5 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 27 Jul 2011 15:15:48 -0400 Subject: change local variable name --- nova/api/openstack/views/servers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index c90801724..659a43522 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -225,10 +225,10 @@ class ViewBuilderV11(ViewBuilder): return os.path.join(common.remove_version_from_href(self.base_url), "servers", str(server_id)) - def _convert_timeformat(self, time): + def _convert_timeformat(self, date_time): """Converts the given time into the common time format - :param time: should be a datetime + :param date_time: the datetime object to convert """ - return time.strftime(utils.TIME_FORMAT) + return date_time.strftime(utils.TIME_FORMAT) -- cgit