diff options
| author | Jason Koelker <jason@koelker.net> | 2011-07-29 09:37:11 -0500 |
|---|---|---|
| committer | Jason Koelker <jason@koelker.net> | 2011-07-29 09:37:11 -0500 |
| commit | 396cf66676a64643645e25f81bd2422ac3ba5dbf (patch) | |
| tree | 7f042f9c391ed7033a91a39cdf2ee2a9dabec168 | |
| parent | 815f8b587310b396fa10011cb12e91d578a2cb60 (diff) | |
| parent | 8c099960a0938f168fe8ca85c63988d697228512 (diff) | |
| download | nova-396cf66676a64643645e25f81bd2422ac3ba5dbf.tar.gz nova-396cf66676a64643645e25f81bd2422ac3ba5dbf.tar.xz nova-396cf66676a64643645e25f81bd2422ac3ba5dbf.zip | |
merge trunk
| -rw-r--r-- | nova/api/openstack/common.py | 82 | ||||
| -rw-r--r-- | nova/api/openstack/image_metadata.py | 88 | ||||
| -rw-r--r-- | nova/api/openstack/images.py | 2 | ||||
| -rw-r--r-- | nova/api/openstack/servers.py | 127 | ||||
| -rw-r--r-- | nova/api/openstack/views/servers.py | 15 | ||||
| -rw-r--r-- | nova/auth/dbdriver.py | 2 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_common.py | 201 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_image_metadata.py | 201 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_servers.py | 601 |
9 files changed, 1016 insertions, 303 deletions
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index bd14a1389..efa4ab385 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') @@ -192,3 +194,83 @@ def get_version_from_href(href): except IndexError: version = '1.0' return version + + +class MetadataXMLDeserializer(wsgi.MetadataXMLDeserializer): + + def _extract_metadata_container(self, datastring): + dom = minidom.parseString(datastring) + metadata_node = self.find_first_child_named(dom, "metadata") + metadata = self.extract_metadata(metadata_node) + return {'body': {'metadata': metadata}} + + def create(self, datastring): + return self._extract_metadata_container(datastring) + + def update_all(self, datastring): + return self._extract_metadata_container(datastring) + + def update(self, datastring): + dom = minidom.parseString(datastring) + metadata_item = self.extract_metadata(dom) + return {'body': {'meta': metadata_item}} + + +class MetadataHeadersSerializer(wsgi.ResponseHeadersSerializer): + + def delete(self, response, data): + response.status_int = 204 + + +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 update_all(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 default(self, *args, **kwargs): + return '' diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index ee181c924..aaf64a123 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -16,12 +16,12 @@ # under the License. from webob import exc -from xml.dom import minidom 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 wsgi @@ -118,95 +118,15 @@ class Controller(object): self.image_service.update(context, image_id, img, None) -class ImageMetadataXMLDeserializer(wsgi.MetadataXMLDeserializer): - - def _extract_metadata_container(self, datastring): - dom = minidom.parseString(datastring) - metadata_node = self.find_first_child_named(dom, "metadata") - metadata = self.extract_metadata(metadata_node) - return {'body': {'metadata': metadata}} - - def create(self, datastring): - return self._extract_metadata_container(datastring) - - def update_all(self, datastring): - return self._extract_metadata_container(datastring) - - def update(self, datastring): - dom = minidom.parseString(datastring) - metadata_item = self.extract_metadata(dom) - return {'body': {'meta': metadata_item}} - - -class HeadersSerializer(wsgi.ResponseHeadersSerializer): - - def delete(self, response, data): - response.status_int = 204 - - -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 update_all(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 default(self, *args, **kwargs): - return '' - - def create_resource(): - headers_serializer = HeadersSerializer() + headers_serializer = common.MetadataHeadersSerializer() body_deserializers = { - 'application/xml': ImageMetadataXMLDeserializer(), + 'application/xml': common.MetadataXMLDeserializer(), } body_serializers = { - 'application/xml': ImageMetadataXMLSerializer(), + 'application/xml': common.MetadataXMLSerializer(), } serializer = wsgi.ResponseSerializer(body_serializers, headers_serializer) deserializer = wsgi.RequestDeserializer(body_deserializers) diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 30e4fd389..9ba8b639e 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -284,7 +284,7 @@ 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): image_node = xml_doc.createElement('image') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index dbfd30ff5..f6841318d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -18,6 +18,7 @@ import traceback from webob import exc import webob +from xml.dom import minidom from nova import compute from nova import db @@ -27,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 +610,123 @@ class HeadersSerializer(wsgi.ResponseHeadersSerializer): response.status_int = 204 +class ServerXMLSerializer(wsgi.XMLDictSerializer): + + xmlns = wsgi.XMLNS_V11 + + 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) + 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): + return self.addresses_serializer.networks_to_xml(xml_doc, addresses) + + 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', str(server['created'])) + node.setAttribute('updated', str(server['updated'])) + node.setAttribute('status', server['status']) + 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) + + link_nodes = self._create_link_nodes(xml_doc, + server['links']) + for link_node in link_nodes: + server_node.appendChild(link_node) + + 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) + + 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) + + 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 _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 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, + 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 = { '1.0': ControllerV10, @@ -637,9 +756,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': wsgi.XMLDictSerializer(metadata=metadata, - xmlns=xmlns), + 'application/xml': xml_serializer, } body_deserializers = { diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index be25e1e40..659a43522 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, date_time): + """Converts the given time into the common time format + + :param date_time: the datetime object to convert + + """ + return date_time.strftime(utils.TIME_FORMAT) diff --git a/nova/auth/dbdriver.py b/nova/auth/dbdriver.py index 0158c4e23..c6d81ee04 100644 --- a/nova/auth/dbdriver.py +++ b/nova/auth/dbdriver.py @@ -127,7 +127,7 @@ class DbDriver(object): try: project = db.project_create(context.get_admin_context(), values) - except (exception.Duplicate, exception.DBError): + except exception.DBError: raise exception.ProjectExists(project=name) for member in members: diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py index f09270b34..0b76841f0 100644 --- a/nova/tests/api/openstack/test_common.py +++ b/nova/tests/api/openstack/test_common.py @@ -20,6 +20,7 @@ Test suites for 'common' code used throughout the OpenStack HTTP API. """ import webob.exc +import xml.dom.minidom as minidom from webob import Request @@ -265,3 +266,203 @@ class MiscFunctionsTest(test.TestCase): expected = '1.0' actual = common.get_version_from_href(fixture) self.assertEqual(actual, expected) + + +class MetadataXMLDeserializationTest(test.TestCase): + + deserializer = common.MetadataXMLDeserializer() + + def test_create(self): + request_body = """ + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> + <meta key='123'>asdf</meta> + <meta key='567'>jkl;</meta> + </metadata>""" + output = self.deserializer.deserialize(request_body, 'create') + expected = {"body": {"metadata": {"123": "asdf", "567": "jkl;"}}} + self.assertEquals(output, expected) + + def test_create_empty(self): + request_body = """ + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"/>""" + output = self.deserializer.deserialize(request_body, 'create') + expected = {"body": {"metadata": {}}} + self.assertEquals(output, expected) + + def test_update_all(self): + request_body = """ + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> + <meta key='123'>asdf</meta> + <meta key='567'>jkl;</meta> + </metadata>""" + output = self.deserializer.deserialize(request_body, 'update_all') + expected = {"body": {"metadata": {"123": "asdf", "567": "jkl;"}}} + self.assertEquals(output, expected) + + def test_update(self): + request_body = """ + <meta xmlns="http://docs.openstack.org/compute/api/v1.1" + key='123'>asdf</meta>""" + output = self.deserializer.deserialize(request_body, 'update') + expected = {"body": {"meta": {"123": "asdf"}}} + self.assertEquals(output, expected) + + +class MetadataXMLSerializationTest(test.TestCase): + + def test_index(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + 'one': 'two', + 'three': 'four', + }, + } + output = serializer.serialize(fixture, 'index') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> + <meta key="three"> + four + </meta> + <meta key="one"> + two + </meta> + </metadata> + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_index_null(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + None: None, + }, + } + output = serializer.serialize(fixture, 'index') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> + <meta key="None"> + None + </meta> + </metadata> + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_index_unicode(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + u'three': u'Jos\xe9', + }, + } + output = serializer.serialize(fixture, 'index') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(u""" + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> + <meta key="three"> + Jos\xe9 + </meta> + </metadata> + """.encode("UTF-8").replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_show(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'meta': { + 'one': 'two', + }, + } + output = serializer.serialize(fixture, 'show') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + <meta xmlns="http://docs.openstack.org/compute/api/v1.1" key="one"> + two + </meta> + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_update_all(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + 'key6': 'value6', + 'key4': 'value4', + }, + } + output = serializer.serialize(fixture, 'update_all') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> + <meta key="key6"> + value6 + </meta> + <meta key="key4"> + value4 + </meta> + </metadata> + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_update_item(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'meta': { + 'one': 'two', + }, + } + output = serializer.serialize(fixture, 'update') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + <meta xmlns="http://docs.openstack.org/compute/api/v1.1" key="one"> + two + </meta> + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_create(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + 'key9': 'value9', + 'key2': 'value2', + 'key1': 'value1', + }, + } + output = serializer.serialize(fixture, 'create') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> + <meta key="key2"> + value2 + </meta> + <meta key="key9"> + value9 + </meta> + <meta key="key1"> + value1 + </meta> + </metadata> + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_delete(self): + serializer = common.MetadataXMLSerializer() + output = serializer.serialize(None, 'delete') + self.assertEqual(output, '') diff --git a/nova/tests/api/openstack/test_image_metadata.py b/nova/tests/api/openstack/test_image_metadata.py index 31ca18497..c9137cc24 100644 --- a/nova/tests/api/openstack/test_image_metadata.py +++ b/nova/tests/api/openstack/test_image_metadata.py @@ -19,7 +19,6 @@ import json import stubout import unittest import webob -import xml.dom.minidom as minidom from nova import flags @@ -252,203 +251,3 @@ class ImageMetaDataTest(test.TestCase): req.headers["content-type"] = "application/json" res = req.get_response(fakes.wsgi_app()) self.assertEqual(400, res.status_int) - - -class ImageMetadataXMLDeserializationTest(test.TestCase): - - deserializer = openstack.image_metadata.ImageMetadataXMLDeserializer() - - def test_create(self): - request_body = """ - <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> - <meta key='123'>asdf</meta> - <meta key='567'>jkl;</meta> - </metadata>""" - output = self.deserializer.deserialize(request_body, 'create') - expected = {"body": {"metadata": {"123": "asdf", "567": "jkl;"}}} - self.assertEquals(output, expected) - - def test_create_empty(self): - request_body = """ - <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"/>""" - output = self.deserializer.deserialize(request_body, 'create') - expected = {"body": {"metadata": {}}} - self.assertEquals(output, expected) - - def test_update_all(self): - request_body = """ - <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> - <meta key='123'>asdf</meta> - <meta key='567'>jkl;</meta> - </metadata>""" - output = self.deserializer.deserialize(request_body, 'update_all') - expected = {"body": {"metadata": {"123": "asdf", "567": "jkl;"}}} - self.assertEquals(output, expected) - - def test_update(self): - request_body = """ - <meta xmlns="http://docs.openstack.org/compute/api/v1.1" - key='123'>asdf</meta>""" - output = self.deserializer.deserialize(request_body, 'update') - expected = {"body": {"meta": {"123": "asdf"}}} - self.assertEquals(output, expected) - - -class ImageMetadataXMLSerializationTest(test.TestCase): - - def test_index(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - 'one': 'two', - 'three': 'four', - }, - } - output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> - <meta key="three"> - four - </meta> - <meta key="one"> - two - </meta> - </metadata> - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_index_null(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - None: None, - }, - } - output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> - <meta key="None"> - None - </meta> - </metadata> - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_index_unicode(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - u'three': u'Jos\xe9', - }, - } - output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(u""" - <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> - <meta key="three"> - Jos\xe9 - </meta> - </metadata> - """.encode("UTF-8").replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_show(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'meta': { - 'one': 'two', - }, - } - output = serializer.serialize(fixture, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - <meta xmlns="http://docs.openstack.org/compute/api/v1.1" key="one"> - two - </meta> - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_update_all(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - 'key6': 'value6', - 'key4': 'value4', - }, - } - output = serializer.serialize(fixture, 'update_all') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> - <meta key="key6"> - value6 - </meta> - <meta key="key4"> - value4 - </meta> - </metadata> - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_update_item(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'meta': { - 'one': 'two', - }, - } - output = serializer.serialize(fixture, 'update') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - <meta xmlns="http://docs.openstack.org/compute/api/v1.1" key="one"> - two - </meta> - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_create(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - 'key9': 'value9', - 'key2': 'value2', - 'key1': 'value1', - }, - } - output = serializer.serialize(fixture, 'create') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - <metadata xmlns="http://docs.openstack.org/compute/api/v1.1"> - <meta key="key2"> - value2 - </meta> - <meta key="key9"> - value9 - </meta> - <meta key="key1"> - value1 - </meta> - </metadata> - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_delete(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - output = serializer.serialize(None, 'delete') - self.assertEqual(output, '') diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 31cbc11a6..4027ef829 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -16,6 +16,7 @@ # under the License. import base64 +import datetime import json import unittest from xml.dom import minidom @@ -172,8 +173,8 @@ def stub_instance(id, user_id=1, private_address=None, public_addresses=None, instance = { "id": int(id), - "created_at": "2010-10-10T12:00:00Z", - "updated_at": "2010-11-11T11:00:00Z", + "created_at": datetime.datetime(2010, 10, 10, 12, 0, 0), + "updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0), "admin_pass": "", "user_id": user_id, "project_id": "", @@ -399,6 +400,78 @@ class ServersTest(test.TestCase): self.assertDictMatch(res_dict, expected_server) + def test_get_server_by_id_v1_1_xml(self): + image_bookmark = "http://localhost/images/10" + flavor_ref = "http://localhost/v1.1/flavors/1" + flavor_id = "1" + flavor_bookmark = "http://localhost/flavors/1" + server_href = "http://localhost/v1.1/servers/1" + server_bookmark = "http://localhost/servers/1" + + public_ip = '192.168.0.3' + private_ip = '172.19.0.1' + interfaces = [ + { + 'network': {'label': 'public'}, + 'fixed_ips': [ + {'address': public_ip}, + ], + }, + { + 'network': {'label': 'private'}, + 'fixed_ips': [ + {'address': private_ip}, + ], + }, + ] + new_return_server = return_server_with_attributes( + interfaces=interfaces) + self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + + req = webob.Request.blank('/v1.1/servers/1') + req.headers['Accept'] = 'application/xml' + res = req.get_response(fakes.wsgi_app()) + actual = minidom.parseString(res.body.replace(' ', '')) + expected_uuid = FAKE_UUID + expected_updated = "2010-11-11T11:00:00Z" + expected_created = "2010-10-10T12:00:00Z" + expected = minidom.parseString(""" + <server id="1" + uuid="%(expected_uuid)s" + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" + name="server1" + updated="%(expected_updated)s" + created="%(expected_created)s" + hostId="" + status="BUILD" + progress="0"> + <atom:link href="%(server_href)s" rel="self"/> + <atom:link href="%(server_bookmark)s" rel="bookmark"/> + <image id="10"> + <atom:link rel="bookmark" href="%(image_bookmark)s"/> + </image> + <flavor id="1"> + <atom:link rel="bookmark" href="%(flavor_bookmark)s"/> + </flavor> + <metadata> + <meta key="seq"> + 1 + </meta> + </metadata> + <addresses> + <network id="public"> + <ip version="4" addr="%(public_ip)s"/> + </network> + <network id="private"> + <ip version="4" addr="%(private_ip)s"/> + </network> + </addresses> + </server> + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) + def test_get_server_with_active_status_by_id_v1_1(self): image_bookmark = "http://localhost/images/10" flavor_ref = "http://localhost/v1.1/flavors/1" @@ -1048,8 +1121,8 @@ class ServersTest(test.TestCase): 'uuid': FAKE_UUID, 'instance_type': dict(inst_type), 'image_ref': image_ref, - 'created_at': '2010-10-10T12:00:00Z', - 'updated_at': '2010-11-11T11:00:00Z', + "created_at": datetime.datetime(2010, 10, 10, 12, 0, 0), + "updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0), } def server_update(context, id, params): @@ -3077,10 +3150,12 @@ class ServersViewBuilderV11Test(test.TestCase): pass def _get_instance(self): + created_at = datetime.datetime(2010, 10, 10, 12, 0, 0) + updated_at = datetime.datetime(2010, 11, 11, 11, 0, 0) instance = { "id": 1, - "created_at": "2010-10-10T12:00:00Z", - "updated_at": "2010-11-11T11:00:00Z", + "created_at": created_at, + "updated_at": updated_at, "admin_pass": "", "user_id": "", "project_id": "", @@ -3284,12 +3359,12 @@ class ServersViewBuilderV11Test(test.TestCase): }, "flavor": { "id": "1", - "links": [ - { - "rel": "bookmark", - "href": flavor_bookmark, - }, - ], + "links": [ + { + "rel": "bookmark", + "href": flavor_bookmark, + }, + ], }, "addresses": {}, "metadata": { @@ -3311,3 +3386,505 @@ class ServersViewBuilderV11Test(test.TestCase): output = self.view_builder.build(self.instance, True) self.assertDictMatch(output, expected_server) + + +class ServerXMLSerializationTest(test.TestCase): + + TIMESTAMP = "2010-10-11T10:30:22Z" + SERVER_HREF = 'http://localhost/v1.1/servers/123' + SERVER_BOOKMARK = 'http://localhost/servers/123' + IMAGE_BOOKMARK = 'http://localhost/images/5' + FLAVOR_BOOKMARK = 'http://localhost/flavors/1' + + def setUp(self): + self.maxDiff = None + test.TestCase.setUp(self) + + def test_show(self): + serializer = servers.ServerXMLSerializer() + + fixture = { + "server": { + "id": 1, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 0, + "name": "test_server", + "status": "BUILD", + "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": self.IMAGE_BOOKMARK, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": self.FLAVOR_BOOKMARK, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + "network_two": [ + { + "version": 4, + "addr": "67.23.10.139", + }, + { + "version": 6, + "addr": "::babe:67.23.10.139", + }, + ], + }, + "metadata": { + "Open": "Stack", + "Number": "1", + }, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + } + } + + output = serializer.serialize(fixture, 'show') + actual = minidom.parseString(output.replace(" ", "")) + + expected_server_href = self.SERVER_HREF + expected_server_bookmark = self.SERVER_BOOKMARK + expected_image_bookmark = self.IMAGE_BOOKMARK + expected_flavor_bookmark = self.FLAVOR_BOOKMARK + expected_now = self.TIMESTAMP + expected_uuid = FAKE_UUID + expected = minidom.parseString(""" + <server id="1" + uuid="%(expected_uuid)s" + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" + name="test_server" + updated="%(expected_now)s" + created="%(expected_now)s" + hostId="e4d909c290d0fb1ca068ffaddf22cbd0" + status="BUILD" + progress="0"> + <atom:link href="%(expected_server_href)s" rel="self"/> + <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/> + <image id="5"> + <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/> + </image> + <flavor id="1"> + <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/> + </flavor> + <metadata> + <meta key="Open"> + Stack + </meta> + <meta key="Number"> + 1 + </meta> + </metadata> + <addresses> + <network id="network_one"> + <ip version="4" addr="67.23.10.138"/> + <ip version="6" addr="::babe:67.23.10.138"/> + </network> + <network id="network_two"> + <ip version="4" addr="67.23.10.139"/> + <ip version="6" addr="::babe:67.23.10.139"/> + </network> + </addresses> + </server> + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_create(self): + serializer = servers.ServerXMLSerializer() + + fixture = { + "server": { + "id": 1, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 0, + "name": "test_server", + "status": "BUILD", + "hostId": "e4d909c290d0fb1ca068ffaddf22cbd0", + "adminPass": "test_password", + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": self.IMAGE_BOOKMARK, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": self.FLAVOR_BOOKMARK, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + "network_two": [ + { + "version": 4, + "addr": "67.23.10.139", + }, + { + "version": 6, + "addr": "::babe:67.23.10.139", + }, + ], + }, + "metadata": { + "Open": "Stack", + "Number": "1", + }, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + } + } + + output = serializer.serialize(fixture, 'create') + actual = minidom.parseString(output.replace(" ", "")) + + expected_server_href = self.SERVER_HREF + expected_server_bookmark = self.SERVER_BOOKMARK + expected_image_bookmark = self.IMAGE_BOOKMARK + expected_flavor_bookmark = self.FLAVOR_BOOKMARK + expected_now = self.TIMESTAMP + expected_uuid = FAKE_UUID + expected = minidom.parseString(""" + <server id="1" + uuid="%(expected_uuid)s" + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" + name="test_server" + updated="%(expected_now)s" + created="%(expected_now)s" + hostId="e4d909c290d0fb1ca068ffaddf22cbd0" + status="BUILD" + adminPass="test_password" + progress="0"> + <atom:link href="%(expected_server_href)s" rel="self"/> + <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/> + <image id="5"> + <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/> + </image> + <flavor id="1"> + <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/> + </flavor> + <metadata> + <meta key="Open"> + Stack + </meta> + <meta key="Number"> + 1 + </meta> + </metadata> + <addresses> + <network id="network_one"> + <ip version="4" addr="67.23.10.138"/> + <ip version="6" addr="::babe:67.23.10.138"/> + </network> + <network id="network_two"> + <ip version="4" addr="67.23.10.139"/> + <ip version="6" addr="::babe:67.23.10.139"/> + </network> + </addresses> + </server> + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_index(self): + serializer = servers.ServerXMLSerializer() + + expected_server_href = 'http://localhost/v1.1/servers/1' + expected_server_bookmark = 'http://localhost/servers/1' + expected_server_href_2 = 'http://localhost/v1.1/servers/2' + expected_server_bookmark_2 = 'http://localhost/servers/2' + fixture = {"servers": [ + { + "id": 1, + "name": "test_server", + 'links': [ + { + 'href': expected_server_href, + 'rel': 'self', + }, + { + 'href': expected_server_bookmark, + 'rel': 'bookmark', + }, + ], + }, + { + "id": 2, + "name": "test_server_2", + 'links': [ + { + 'href': expected_server_href_2, + 'rel': 'self', + }, + { + 'href': expected_server_bookmark_2, + 'rel': 'bookmark', + }, + ], + }, + ]} + + output = serializer.serialize(fixture, 'index') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + <servers xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom"> + <server id="1" name="test_server"> + <atom:link href="%(expected_server_href)s" rel="self"/> + <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/> + </server> + <server id="2" name="test_server_2"> + <atom:link href="%(expected_server_href_2)s" rel="self"/> + <atom:link href="%(expected_server_bookmark_2)s" rel="bookmark"/> + </server> + </servers> + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_detail(self): + serializer = servers.ServerXMLSerializer() + + expected_server_href = 'http://localhost/v1.1/servers/1' + expected_server_bookmark = 'http://localhost/servers/1' + expected_image_bookmark = self.IMAGE_BOOKMARK + expected_flavor_bookmark = self.FLAVOR_BOOKMARK + expected_now = self.TIMESTAMP + expected_uuid = FAKE_UUID + + expected_server_href_2 = 'http://localhost/v1.1/servers/2' + expected_server_bookmark_2 = 'http://localhost/servers/2' + fixture = {"servers": [ + { + "id": 1, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 0, + "name": "test_server", + "status": "BUILD", + "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": expected_image_bookmark, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": expected_flavor_bookmark, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + }, + "metadata": { + "Number": "1", + }, + "links": [ + { + "href": expected_server_href, + "rel": "self", + }, + { + "href": expected_server_bookmark, + "rel": "bookmark", + }, + ], + }, + { + "id": 2, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 100, + "name": "test_server_2", + "status": "ACTIVE", + "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": expected_image_bookmark, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": expected_flavor_bookmark, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + }, + "metadata": { + "Number": "2", + }, + "links": [ + { + "href": expected_server_href_2, + "rel": "self", + }, + { + "href": expected_server_bookmark_2, + "rel": "bookmark", + }, + ], + }, + ]} + + output = serializer.serialize(fixture, 'detail') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + <servers xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom"> + <server id="1" + uuid="%(expected_uuid)s" + name="test_server" + updated="%(expected_now)s" + created="%(expected_now)s" + hostId="e4d909c290d0fb1ca068ffaddf22cbd0" + status="BUILD" + progress="0"> + <atom:link href="%(expected_server_href)s" rel="self"/> + <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/> + <image id="5"> + <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/> + </image> + <flavor id="1"> + <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/> + </flavor> + <metadata> + <meta key="Number"> + 1 + </meta> + </metadata> + <addresses> + <network id="network_one"> + <ip version="4" addr="67.23.10.138"/> + <ip version="6" addr="::babe:67.23.10.138"/> + </network> + </addresses> + </server> + <server id="2" + uuid="%(expected_uuid)s" + name="test_server_2" + updated="%(expected_now)s" + created="%(expected_now)s" + hostId="e4d909c290d0fb1ca068ffaddf22cbd0" + status="ACTIVE" + progress="100"> + <atom:link href="%(expected_server_href_2)s" rel="self"/> + <atom:link href="%(expected_server_bookmark_2)s" rel="bookmark"/> + <image id="5"> + <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/> + </image> + <flavor id="1"> + <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/> + </flavor> + <metadata> + <meta key="Number"> + 2 + </meta> + </metadata> + <addresses> + <network id="network_one"> + <ip version="4" addr="67.23.10.138"/> + <ip version="6" addr="::babe:67.23.10.138"/> + </network> + </addresses> + </server> + </servers> + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) |
