diff options
| author | Naveed Massjouni <naveedm9@gmail.com> | 2011-07-21 15:08:46 -0400 |
|---|---|---|
| committer | Naveed Massjouni <naveedm9@gmail.com> | 2011-07-21 15:08:46 -0400 |
| commit | af5c549d7795fcf9fdcb7d8e9193aa985f121fc6 (patch) | |
| tree | 5b8dbd31fc11cf3086c0a0004a216d87efafb4d1 /nova | |
| parent | 74c399cb2ebb914973c2f0dc6ecf4dd8bbc062d7 (diff) | |
Moving lp:~rackspace-titan/nova/extensions-xml-serialization to new branch based off of trunk. To remove dep on another branch.
Diffstat (limited to 'nova')
| -rw-r--r-- | nova/api/openstack/extensions.py | 43 | ||||
| -rw-r--r-- | nova/api/openstack/wsgi.py | 4 | ||||
| -rw-r--r-- | nova/tests/api/openstack/test_extensions.py | 113 |
3 files changed, 152 insertions, 8 deletions
diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index da06ecd15..e500e51fa 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -23,6 +23,7 @@ import sys import routes import webob.dec import webob.exc +from xml.etree import ElementTree from nova import exception from nova import flags @@ -194,7 +195,7 @@ class ExtensionsResource(wsgi.Resource): def show(self, req, id): # NOTE(dprince): the extensions alias is used as the 'id' for show ext = self.extension_manager.extensions[id] - return self._translate(ext) + return dict(extension=self._translate(ext)) def delete(self, req, id): raise faults.Fault(webob.exc.HTTPNotFound()) @@ -258,15 +259,18 @@ class ExtensionMiddleware(base_wsgi.Middleware): mapper = routes.Mapper() + serializer = wsgi.ResponseSerializer( + {'application/xml': ExtensionsXMLSerializer()}) # extended resources for resource in ext_mgr.get_resources(): LOG.debug(_('Extended resource: %s'), resource.collection) mapper.resource(resource.collection, resource.collection, - controller=wsgi.Resource(resource.controller), - collection=resource.collection_actions, - member=resource.member_actions, - parent_resource=resource.parent) + controller=wsgi.Resource( + resource.controller, serializer=serializer), + collection=resource.collection_actions, + member=resource.member_actions, + parent_resource=resource.parent) # extended actions action_resources = self._action_ext_resources(application, ext_mgr, @@ -462,3 +466,32 @@ class ResourceExtension(object): self.parent = parent self.collection_actions = collection_actions self.member_actions = member_actions + + +class ExtensionsXMLSerializer(wsgi.XMLDictSerializer): + + def _add_extension_attributes(self, node, extension): + node.setAttribute('name', extension['name']) + node.setAttribute('namespace', extension['namespace']) + node.setAttribute('alias', extension['alias']) + node.setAttribute('updated', extension['updated']) + + def show(self, ext_dict): + root = ElementTree.Element('extension'); + extension = ext_dict['extension'] + root.set('xmlns', wsgi.XMLNS_V11) + root.set('xmlns:atom', wsgi.XMLNS_ATOM) + root.set('name', extension['name']) + root.set('namespace', extension['namespace']) + root.set('alias', extension['alias']) + root.set('updated', extension['updated']) + desc = ElementTree.Element('description'); + desc.text = extension['description'] + root.append(desc) + for link in extension.get('links', []): + elem = ElementTree.Element('atom:link'); + elem.set('rel', link['rel']) + elem.set('href', link['href']) + elem.set('type', link['type']) + root.append(elem) + return ElementTree.tostring(root) diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 9df6fd058..d9993282f 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -13,6 +13,7 @@ from nova import wsgi XMLNS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0' XMLNS_V11 = 'http://docs.openstack.org/compute/api/v1.1' +XMLNS_ATOM = 'http://www.w3.org/2005/Atom' LOG = logging.getLogger('nova.api.openstack.wsgi') @@ -352,6 +353,9 @@ class XMLDictSerializer(DictSerializer): link_node = xml_doc.createElement('atom:link') link_node.setAttribute('rel', link['rel']) link_node.setAttribute('href', link['href']) + if link.get('type'): + link_node.setAttribute('type', link['type']) + link_nodes.append(link_node) return link_nodes diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py index 697c62e5c..6d3c1b1be 100644 --- a/nova/tests/api/openstack/test_extensions.py +++ b/nova/tests/api/openstack/test_extensions.py @@ -16,10 +16,11 @@ # under the License. import json +import os.path import stubout import unittest import webob -import os.path +from xml.etree import ElementTree from nova import context from nova import flags @@ -80,19 +81,73 @@ class StubExtensionManager(object): class ExtensionControllerTest(unittest.TestCase): - def test_index(self): + def setUp(self): + FLAGS.osapi_extensions_path = os.path.join( + os.path.dirname(__file__), "extensions") + + def test_list_extensions_json(self): app = openstack.APIRouterV11() ext_midware = extensions.ExtensionMiddleware(app) request = webob.Request.blank("/extensions") response = request.get_response(ext_midware) self.assertEqual(200, response.status_int) - def test_get_by_alias(self): + # Make sure we have all the extensions. + data = json.loads(response.body) + names = [x['name'] for x in data['extensions']] + names.sort() + self.assertEqual(names, ["FlavorExtraSpecs", "Floating_ips", + "Fox In Socks", "Hosts", "Multinic", "Volumes"]) + + # Make sure that at least Fox in Sox is correct. + (fox_ext,) = [ + x for x in data['extensions'] if x['alias'] == 'FOXNSOX'] + self.assertEqual(fox_ext, { + "namespace" : "http://www.fox.in.socks/api/ext/pie/v1.0", + "name" : "Fox In Socks", + "updated" : "2011-01-22T13:25:27-06:00", + "description" : "The Fox In Socks Extension", + "alias" : "FOXNSOX", + "links" : [] + } + ) + + def test_get_extension_json(self): + app = openstack.APIRouterV11() + ext_midware = extensions.ExtensionMiddleware(app) + request = webob.Request.blank("/extensions/FOXNSOX") + response = request.get_response(ext_midware) + self.assertEqual(200, response.status_int) + + data = json.loads(response.body) + self.assertEqual(data['extension'], { + "namespace" : "http://www.fox.in.socks/api/ext/pie/v1.0", + "name" : "Fox In Socks", + "updated" : "2011-01-22T13:25:27-06:00", + "description" : "The Fox In Socks Extension", + "alias" : "FOXNSOX", + "links" : [] + } + ) + + def test_get_extension_xml(self): app = openstack.APIRouterV11() ext_midware = extensions.ExtensionMiddleware(app) request = webob.Request.blank("/extensions/FOXNSOX") + request.accept = "application/xml" response = request.get_response(ext_midware) self.assertEqual(200, response.status_int) + print response.body + + elem = ElementTree.XML(response.body.replace(" ", "")) + self.assertEqual(elem.get('alias'), 'FOXNSOX') + self.assertEqual(elem.get('name'), 'Fox In Socks') + self.assertEqual(elem.get('namespace'), + 'http://www.fox.in.socks/api/ext/pie/v1.0') + self.assertEqual(elem.get('updated'), '2011-01-22T13:25:27-06:00') + ns = "{http://docs.openstack.org/compute/api/v1.1}" + self.assertEqual(elem.findtext('{0}description'.format(ns)), + 'The Fox In Socks Extension') class ResourceExtensionTest(unittest.TestCase): @@ -244,3 +299,55 @@ class RequestExtensionTest(unittest.TestCase): response_data = json.loads(response.body) self.assertEqual('newblue', response_data['flavor']['googoose']) self.assertEqual("Pig Bands!", response_data['big_bands']) + +class ExtensionsXMLSerializerTest(unittest.TestCase): + def test_serialize(self): + serializer = extensions.ExtensionsXMLSerializer() + data = { + 'extension': { + 'name': 'ext1', + "namespace" : "http://docs.rack.com/servers/api/ext/pie/v1.0", + "alias" : "RS-PIE", + "updated" : "2011-01-22T13:25:27-06:00", + "description" : "Adds the capability to share an image.", + "links" : [ + { + "rel" : "describedby", + "type" : "application/pdf", + "href" : "http://docs.rack.com/servers/api/ext/cs.pdf" + }, + { + "rel" : "describedby", + "type" : "application/vnd.sun.wadl+xml", + "href" : "http://docs.rack.com/servers/api/ext/cs.wadl" + } + ] + }, + } + + ns = "{http://docs.openstack.org/compute/api/v1.1}" + atomns = "{http://www.w3.org/2005/Atom}" + elem = ElementTree.XML(serializer.serialize(data, 'show')) + self.assertEqual(elem.tag.split('extension')[0], ns) + self.assertEqual(elem.get('alias'), 'RS-PIE') + self.assertEqual(elem.get('name'), 'ext1') + self.assertEqual(elem.get('namespace'), + 'http://docs.rack.com/servers/api/ext/pie/v1.0') + self.assertEqual(elem.get('updated'), '2011-01-22T13:25:27-06:00') + self.assertEqual(elem.findtext('{0}description'.format(ns)), + 'Adds the capability to share an image.') + + link_nodes = elem.findall('{0}link'.format(atomns)) + self.assertEqual(len(link_nodes), 2) + link_nodes.sort(key=lambda x: x.get('type')) + + self.assertEqual(link_nodes[0].get('type'), 'application/pdf') + self.assertEqual(link_nodes[0].get('rel'), 'describedby') + self.assertEqual(link_nodes[0].get('href'), + 'http://docs.rack.com/servers/api/ext/cs.pdf') + + self.assertEqual(link_nodes[1].get('type'), + 'application/vnd.sun.wadl+xml') + self.assertEqual(link_nodes[1].get('rel'), 'describedby') + self.assertEqual(link_nodes[1].get('href'), + 'http://docs.rack.com/servers/api/ext/cs.wadl') |
