diff options
-rw-r--r-- | nova/api/openstack/common.py | 17 | ||||
-rw-r--r-- | nova/api/openstack/images.py | 111 | ||||
-rw-r--r-- | nova/api/openstack/views/images.py | 28 | ||||
-rw-r--r-- | nova/api/openstack/wsgi.py | 23 | ||||
-rw-r--r-- | nova/tests/api/openstack/test_common.py | 33 | ||||
-rw-r--r-- | nova/tests/api/openstack/test_images.py | 532 |
6 files changed, 544 insertions, 200 deletions
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 9aa384f33..79969d393 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -133,14 +133,25 @@ def get_id_from_href(href): return int(urlparse(href).path.split('/')[-1]) except: LOG.debug(_("Error extracting id from href: %s") % href) - raise webob.exc.HTTPBadRequest(_('could not parse id from href')) + raise ValueError(_('could not parse id from href')) -def remove_version_from_href(base_url): +def remove_version_from_href(href): """Removes the api version from the href. Given: 'http://www.nova.com/v1.1/123' Returns: 'http://www.nova.com/123' """ - return base_url.rsplit('/', 1).pop(0) + try: + #matches /v#.# + new_href = re.sub(r'[/][v][0-9]*.[0-9]*', '', href) + except: + LOG.debug(_("Error removing version from href: %s") % href) + msg = _('could not parse version from href') + raise ValueError(msg) + + if new_href == href: + msg = _('href does not contain version') + raise ValueError(msg) + return new_href diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 8ff92b8fe..d0317583e 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -27,6 +27,7 @@ from nova import log from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack import image_metadata +from nova.api.openstack import servers from nova.api.openstack.views import images as images_view from nova.api.openstack import wsgi @@ -274,59 +275,99 @@ class ControllerV11(Controller): class ImageXMLSerializer(wsgi.XMLDictSerializer): - metadata = { - "attributes": { - "image": ["id", "name", "updated", "created", "status", - "serverId", "progress", "serverRef"], - "link": ["rel", "type", "href"], - }, - } - xmlns = wsgi.XMLNS_V11 def __init__(self): self.metadata_serializer = image_metadata.ImageMetadataXMLSerializer() def _image_to_xml(self, xml_doc, image): - try: - metadata = image.pop('metadata').items() - except Exception: - LOG.debug(_("Image object missing metadata attribute")) - metadata = {} - - node = self._to_xml_node(xml_doc, self.metadata, 'image', image) - metadata_node = self.metadata_serializer.meta_list_to_xml(xml_doc, - metadata) - node.appendChild(metadata_node) - return node - - def _image_list_to_xml(self, xml_doc, images): + image_node = xml_doc.createElement('image') + image_node.setAttribute('id', str(image['id'])) + image_node.setAttribute('name', image['name']) + link_nodes = self._create_link_nodes(xml_doc, + image['links']) + for link_node in link_nodes: + image_node.appendChild(link_node) + return image_node + + def _image_to_xml_detailed(self, xml_doc, image): + image_node = xml_doc.createElement('image') + self._add_image_attributes(image_node, image) + + if 'server' in image: + server_node = self._create_server_node(xml_doc, image['server']) + image_node.appendChild(server_node) + + metadata = image.get('metadata', {}).items() + if len(metadata) > 0: + metadata_node = self._create_metadata_node(xml_doc, metadata) + image_node.appendChild(metadata_node) + + link_nodes = self._create_link_nodes(xml_doc, + image['links']) + for link_node in link_nodes: + image_node.appendChild(link_node) + + return image_node + + def _add_image_attributes(self, node, image): + node.setAttribute('id', str(image['id'])) + node.setAttribute('name', image['name']) + node.setAttribute('created', image['created']) + node.setAttribute('updated', image['updated']) + node.setAttribute('status', image['status']) + if 'progress' in image: + node.setAttribute('progress', str(image['progress'])) + + def _create_metadata_node(self, xml_doc, metadata): + return self.metadata_serializer.meta_list_to_xml(xml_doc, metadata) + + def _create_server_node(self, xml_doc, server): + server_node = xml_doc.createElement('server') + server_node.setAttribute('id', str(server['id'])) + 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 _image_list_to_xml(self, xml_doc, images, detailed): container_node = xml_doc.createElement('images') + if detailed: + image_to_xml = self._image_to_xml_detailed + else: + image_to_xml = self._image_to_xml + for image in images: - item_node = self._image_to_xml(xml_doc, image) + item_node = image_to_xml(xml_doc, image) container_node.appendChild(item_node) return container_node - def _image_to_xml_string(self, image): - xml_doc = minidom.Document() - item_node = self._image_to_xml(xml_doc, image) - self._add_xmlns(item_node) - return item_node.toprettyxml(indent=' ') - - def _image_list_to_xml_string(self, images): + def index(self, images_dict): xml_doc = minidom.Document() - container_node = self._image_list_to_xml(xml_doc, images) - self._add_xmlns(container_node) - return container_node.toprettyxml(indent=' ') + node = self._image_list_to_xml(xml_doc, + images_dict['images'], + detailed=False) + return self.to_xml_string(node, True) def detail(self, images_dict): - return self._image_list_to_xml_string(images_dict['images']) + xml_doc = minidom.Document() + node = self._image_list_to_xml(xml_doc, + images_dict['images'], + detailed=True) + return self.to_xml_string(node, True) def show(self, image_dict): - return self._image_to_xml_string(image_dict['image']) + xml_doc = minidom.Document() + node = self._image_to_xml_detailed(xml_doc, + image_dict['image']) + return self.to_xml_string(node, True) def create(self, image_dict): - return self._image_to_xml_string(image_dict['image']) + xml_doc = minidom.Document() + node = self._image_to_xml_detailed(xml_doc, + image_dict['image']) + return self.to_xml_string(node, True) def create_resource(version='1.0'): diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 005341c62..5c0510377 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -98,7 +98,20 @@ class ViewBuilderV11(ViewBuilder): def _build_server(self, image, image_obj): try: - image['serverRef'] = image_obj['properties']['instance_ref'] + serverRef = image_obj['properties']['instance_ref'] + image['server'] = { + "id": common.get_id_from_href(serverRef), + "links": [ + { + "rel": "self", + "href": serverRef, + }, + { + "rel": "bookmark", + "href": common.remove_version_from_href(serverRef), + }, + ] + } except KeyError: return @@ -108,18 +121,17 @@ class ViewBuilderV11(ViewBuilder): href = self.generate_href(image_obj["id"]) bookmark = self.generate_bookmark(image_obj["id"]) - if detail: - image["metadata"] = image_obj.get("properties", {}) - image["links"] = [{ "rel": "self", "href": href, - }, - { - "rel": "bookmark", - "href": bookmark, }] + if detail: + image["metadata"] = image_obj.get("properties", {}) + image["links"].append({"rel": "bookmark", + "href": bookmark, + }) + return image def generate_bookmark(self, image_id): diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 8eff9e441..c3f841aa5 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -270,13 +270,21 @@ class XMLDictSerializer(DictSerializer): doc = minidom.Document() node = self._to_xml_node(doc, self.metadata, root_key, data[root_key]) - self._add_xmlns(node) + return self.to_xml_string(node) - return node.toprettyxml(indent=' ', encoding='utf-8') + def to_xml_string(self, node, has_atom=False): + self._add_xmlns(node, has_atom) + return node.toprettyxml(indent=' ', encoding='UTF-8') - def _add_xmlns(self, node): + #NOTE (ameade): the has_atom should be removed after all of the + # xml serializers and view builders have been updated to the current + # spec that required all responses include the xmlns:atom, the has_atom + # flag is to prevent current tests from breaking + def _add_xmlns(self, node, has_atom=False): if self.xmlns is not None: node.setAttribute('xmlns', self.xmlns) + if has_atom: + node.setAttribute('xmlns:atom', "http://www.w3.org/2005/Atom") def _to_xml_node(self, doc, metadata, nodename, data): """Recursive method to convert data members to XML nodes.""" @@ -332,6 +340,15 @@ class XMLDictSerializer(DictSerializer): result.appendChild(node) return result + def _create_link_nodes(self, xml_doc, links): + link_nodes = [] + for link in links: + link_node = xml_doc.createElement('atom:link') + link_node.setAttribute('rel', link['rel']) + link_node.setAttribute('href', link['href']) + link_nodes.append(link_node) + return link_nodes + class ResponseHeadersSerializer(ActionDispatcher): """Default response headers serialization""" diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py index 29cb8b944..7440bccfb 100644 --- a/nova/tests/api/openstack/test_common.py +++ b/nova/tests/api/openstack/test_common.py @@ -190,3 +190,36 @@ class PaginationParamsTest(test.TestCase): req = Request.blank('/?limit=20&marker=40') self.assertEqual(common.get_pagination_params(req), {'marker': 40, 'limit': 20}) + + +class MiscFunctionsTest(test.TestCase): + + def test_remove_version_from_href(self): + fixture = 'http://www.testsite.com/v1.1/images' + expected = 'http://www.testsite.com/images' + actual = common.remove_version_from_href(fixture) + self.assertEqual(actual, expected) + + def test_remove_version_from_href_2(self): + fixture = 'http://www.testsite.com/v1.1/' + expected = 'http://www.testsite.com/' + actual = common.remove_version_from_href(fixture) + self.assertEqual(actual, expected) + + def test_remove_version_from_href_bad_request(self): + fixture = 'http://www.testsite.com/1.1/images' + self.assertRaises(ValueError, + common.remove_version_from_href, + fixture) + + def test_get_id_from_href(self): + fixture = 'http://www.testsite.com/dir/45' + actual = common.get_id_from_href(fixture) + expected = 45 + self.assertEqual(actual, expected) + + def test_get_id_from_href_bad_request(self): + fixture = 'http://45' + self.assertRaises(ValueError, + common.get_id_from_href, + fixture) diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index f451ee145..c1bdd6906 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -401,15 +401,27 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): href = "http://localhost/v1.1/images/124" bookmark = "http://localhost/images/124" + server_href = "http://localhost/v1.1/servers/42" + server_bookmark = "http://localhost/servers/42" expected_image = { "image": { "id": 124, "name": "queued snapshot", - "serverRef": "http://localhost/v1.1/servers/42", "updated": self.NOW_API_FORMAT, "created": self.NOW_API_FORMAT, "status": "QUEUED", + 'server': { + 'id': 42, + "links": [{ + "rel": "self", + "href": server_href, + }, + { + "rel": "bookmark", + "href": server_bookmark, + }], + }, "metadata": { "instance_ref": "http://localhost/v1.1/servers/42", "user_id": "1", @@ -559,10 +571,6 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): "links": [{ "rel": "self", "href": href, - }, - { - "rel": "bookmark", - "href": bookmark, }], } self.assertTrue(test_image in response_list) @@ -628,6 +636,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): response_dict = json.loads(response.body) response_list = response_dict["images"] + server_href = "http://localhost/v1.1/servers/42" + server_bookmark = "http://localhost/servers/42" expected = [{ 'id': 123, @@ -652,10 +662,20 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): u'instance_ref': u'http://localhost/v1.1/servers/42', u'user_id': u'1', }, - 'serverRef': "http://localhost/v1.1/servers/42", 'updated': self.NOW_API_FORMAT, 'created': self.NOW_API_FORMAT, 'status': 'QUEUED', + 'server': { + 'id': 42, + "links": [{ + "rel": "self", + "href": server_href, + }, + { + "rel": "bookmark", + "href": server_bookmark, + }], + }, "links": [{ "rel": "self", "href": "http://localhost/v1.1/images/124", @@ -672,11 +692,21 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): u'instance_ref': u'http://localhost/v1.1/servers/42', u'user_id': u'1', }, - 'serverRef': "http://localhost/v1.1/servers/42", 'updated': self.NOW_API_FORMAT, 'created': self.NOW_API_FORMAT, 'status': 'SAVING', 'progress': 0, + 'server': { + 'id': 42, + "links": [{ + "rel": "self", + "href": server_href, + }, + { + "rel": "bookmark", + "href": server_bookmark, + }], + }, "links": [{ "rel": "self", "href": "http://localhost/v1.1/images/125", @@ -693,10 +723,20 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): u'instance_ref': u'http://localhost/v1.1/servers/42', u'user_id': u'1', }, - 'serverRef': "http://localhost/v1.1/servers/42", 'updated': self.NOW_API_FORMAT, 'created': self.NOW_API_FORMAT, 'status': 'ACTIVE', + 'server': { + 'id': 42, + "links": [{ + "rel": "self", + "href": server_href, + }, + { + "rel": "bookmark", + "href": server_bookmark, + }], + }, "links": [{ "rel": "self", "href": "http://localhost/v1.1/images/126", @@ -713,10 +753,20 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): u'instance_ref': u'http://localhost/v1.1/servers/42', u'user_id': u'1', }, - 'serverRef': "http://localhost/v1.1/servers/42", 'updated': self.NOW_API_FORMAT, 'created': self.NOW_API_FORMAT, 'status': 'FAILED', + 'server': { + 'id': 42, + "links": [{ + "rel": "self", + "href": server_href, + }, + { + "rel": "bookmark", + "href": server_bookmark, + }], + }, "links": [{ "rel": "self", "href": "http://localhost/v1.1/images/127", @@ -1036,6 +1086,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): def test_create_image_v1_1_actual_server_ref(self): serverRef = 'http://localhost/v1.1/servers/1' + serverBookmark = 'http://localhost/servers/1' body = dict(image=dict(serverRef=serverRef, name='Backup 1')) req = webob.Request.blank('/v1.1/images') req.method = 'POST' @@ -1044,11 +1095,25 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): response = req.get_response(fakes.wsgi_app()) self.assertEqual(200, response.status_int) result = json.loads(response.body) - self.assertEqual(result['image']['serverRef'], serverRef) + expected = { + 'id': 1, + 'links': [ + { + 'rel': 'self', + 'href': serverRef, + }, + { + 'rel': 'bookmark', + 'href': serverBookmark, + }, + ] + } + self.assertEqual(result['image']['server'], expected) def test_create_image_v1_1_actual_server_ref_port(self): serverRef = 'http://localhost:8774/v1.1/servers/1' + serverBookmark = 'http://localhost:8774/servers/1' body = dict(image=dict(serverRef=serverRef, name='Backup 1')) req = webob.Request.blank('/v1.1/images') req.method = 'POST' @@ -1057,7 +1122,20 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): response = req.get_response(fakes.wsgi_app()) self.assertEqual(200, response.status_int) result = json.loads(response.body) - self.assertEqual(result['image']['serverRef'], serverRef) + expected = { + 'id': 1, + 'links': [ + { + 'rel': 'self', + 'href': serverRef, + }, + { + 'rel': 'bookmark', + 'href': serverBookmark, + }, + ] + } + self.assertEqual(result['image']['server'], expected) def test_create_image_v1_1_server_ref_bad_hostname(self): @@ -1080,6 +1158,28 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): response = req.get_response(fakes.wsgi_app()) self.assertEqual(400, response.status_int) + def test_create_image_v1_1_server_ref_missing_version(self): + + serverRef = 'http://localhost/servers/1' + body = dict(image=dict(serverRef=serverRef, name='Backup 1')) + req = webob.Request.blank('/v1.1/images') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + response = req.get_response(fakes.wsgi_app()) + self.assertEqual(400, response.status_int) + + def test_create_image_v1_1_server_ref_missing_id(self): + + serverRef = 'http://localhost/v1.1/servers' + body = dict(image=dict(serverRef=serverRef, name='Backup 1')) + req = webob.Request.blank('/v1.1/images') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + response = req.get_response(fakes.wsgi_app()) + self.assertEqual(400, response.status_int) + @classmethod def _make_image_fixtures(cls): image_id = 123 @@ -1128,7 +1228,9 @@ class ImageXMLSerializationTest(test.TestCase): TIMESTAMP = "2010-10-11T10:30:22Z" SERVER_HREF = 'http://localhost/v1.1/servers/123' + SERVER_BOOKMARK = 'http://localhost/servers/123' IMAGE_HREF = 'http://localhost/v1.1/images/%s' + IMAGE_BOOKMARK = 'http://localhost/images/%s' def test_show(self): serializer = images.ImageXMLSerializer() @@ -1139,16 +1241,32 @@ class ImageXMLSerializationTest(test.TestCase): 'name': 'Image1', 'created': self.TIMESTAMP, 'updated': self.TIMESTAMP, - 'serverRef': self.SERVER_HREF, 'status': 'ACTIVE', + 'progress': 80, + 'server': { + 'id': 1, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + }, 'metadata': { 'key1': 'value1', }, 'links': [ { - 'href': self.IMAGE_HREF % (1,), + 'href': self.IMAGE_HREF % 1, + 'rel': 'self', + }, + { + 'href': self.IMAGE_BOOKMARK % 1, 'rel': 'bookmark', - 'type': 'application/json', }, ], }, @@ -1158,25 +1276,30 @@ class ImageXMLSerializationTest(test.TestCase): actual = minidom.parseString(output.replace(" ", "")) expected_server_href = self.SERVER_HREF - expected_href = self.IMAGE_HREF % (1, ) + expected_server_bookmark = self.SERVER_BOOKMARK + expected_href = self.IMAGE_HREF % 1 + expected_bookmark = self.IMAGE_BOOKMARK % 1 expected_now = self.TIMESTAMP expected = minidom.parseString(""" <image id="1" + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" name="Image1" - serverRef="%(expected_server_href)s" updated="%(expected_now)s" created="%(expected_now)s" status="ACTIVE" - xmlns="http://docs.openstack.org/compute/api/v1.1"> - <links> - <link href="%(expected_href)s" rel="bookmark" - type="application/json" /> - </links> + progress="80"> + <server id="1"> + <atom:link rel="self" href="%(expected_server_href)s"/> + <atom:link rel="bookmark" href="%(expected_server_bookmark)s"/> + </server> <metadata> <meta key="key1"> value1 </meta> </metadata> + <atom:link href="%(expected_href)s" rel="self"/> + <atom:link href="%(expected_bookmark)s" rel="bookmark"/> </image> """.replace(" ", "") % (locals())) @@ -1191,14 +1314,29 @@ class ImageXMLSerializationTest(test.TestCase): 'name': 'Image1', 'created': self.TIMESTAMP, 'updated': self.TIMESTAMP, - 'serverRef': self.SERVER_HREF, 'status': 'ACTIVE', + 'server': { + 'id': 1, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + }, 'metadata': {}, 'links': [ { - 'href': self.IMAGE_HREF % (1,), + 'href': self.IMAGE_HREF % 1, + 'rel': 'self', + }, + { + 'href': self.IMAGE_BOOKMARK % 1, 'rel': 'bookmark', - 'type': 'application/json', }, ], }, @@ -1208,21 +1346,24 @@ class ImageXMLSerializationTest(test.TestCase): actual = minidom.parseString(output.replace(" ", "")) expected_server_href = self.SERVER_HREF - expected_href = self.IMAGE_HREF % (1, ) + expected_server_bookmark = self.SERVER_BOOKMARK + expected_href = self.IMAGE_HREF % 1 + expected_bookmark = self.IMAGE_BOOKMARK % 1 expected_now = self.TIMESTAMP expected = minidom.parseString(""" <image id="1" + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" name="Image1" - serverRef="%(expected_server_href)s" updated="%(expected_now)s" created="%(expected_now)s" - status="ACTIVE" - xmlns="http://docs.openstack.org/compute/api/v1.1"> - <links> - <link href="%(expected_href)s" rel="bookmark" - type="application/json" /> - </links> - <metadata /> + status="ACTIVE"> + <server id="1"> + <atom:link rel="self" href="%(expected_server_href)s"/> + <atom:link rel="bookmark" href="%(expected_server_bookmark)s"/> + </server> + <atom:link href="%(expected_href)s" rel="self"/> + <atom:link href="%(expected_bookmark)s" rel="bookmark"/> </image> """.replace(" ", "") % (locals())) @@ -1237,16 +1378,30 @@ class ImageXMLSerializationTest(test.TestCase): 'name': 'Image1', 'created': self.TIMESTAMP, 'updated': self.TIMESTAMP, - 'serverRef': self.SERVER_HREF, 'status': 'ACTIVE', + 'server': { + 'id': 1, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + }, 'links': [ { - 'href': self.IMAGE_HREF % (1,), + 'href': self.IMAGE_HREF % 1, + 'rel': 'self', + }, + { + 'href': self.IMAGE_BOOKMARK % 1, 'rel': 'bookmark', - 'type': 'application/json', }, ], - }, } @@ -1254,21 +1409,76 @@ class ImageXMLSerializationTest(test.TestCase): actual = minidom.parseString(output.replace(" ", "")) expected_server_href = self.SERVER_HREF - expected_href = self.IMAGE_HREF % (1, ) + expected_server_bookmark = self.SERVER_BOOKMARK + expected_href = self.IMAGE_HREF % 1 + expected_bookmark = self.IMAGE_BOOKMARK % 1 expected_now = self.TIMESTAMP expected = minidom.parseString(""" <image id="1" + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" name="Image1" - serverRef="%(expected_server_href)s" updated="%(expected_now)s" created="%(expected_now)s" - status="ACTIVE" - xmlns="http://docs.openstack.org/compute/api/v1.1"> - <links> - <link href="%(expected_href)s" rel="bookmark" - type="application/json" /> - </links> - <metadata /> + status="ACTIVE"> + <server id="1"> + <atom:link rel="self" href="%(expected_server_href)s"/> + <atom:link rel="bookmark" href="%(expected_server_bookmark)s"/> + </server> + <atom:link href="%(expected_href)s" rel="self"/> + <atom:link href="%(expected_bookmark)s" rel="bookmark"/> + </image> + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_show_no_server(self): + serializer = images.ImageXMLSerializer() + + fixture = { + 'image': { + 'id': 1, + 'name': 'Image1', + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + 'status': 'ACTIVE', + 'metadata': { + 'key1': 'value1', + }, + 'links': [ + { + 'href': self.IMAGE_HREF % 1, + 'rel': 'self', + }, + { + 'href': self.IMAGE_BOOKMARK % 1, + 'rel': 'bookmark', + }, + ], + }, + } + + output = serializer.serialize(fixture, 'show') + actual = minidom.parseString(output.replace(" ", "")) + + expected_href = self.IMAGE_HREF % 1 + expected_bookmark = self.IMAGE_BOOKMARK % 1 + expected_now = self.TIMESTAMP + expected = minidom.parseString(""" + <image id="1" + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" + name="Image1" + updated="%(expected_now)s" + created="%(expected_now)s" + status="ACTIVE"> + <metadata> + <meta key="key1"> + value1 + </meta> + </metadata> + <atom:link href="%(expected_href)s" rel="self"/> + <atom:link href="%(expected_bookmark)s" rel="bookmark"/> </image> """.replace(" ", "") % (locals())) @@ -1277,70 +1487,51 @@ class ImageXMLSerializationTest(test.TestCase): def test_index(self): serializer = images.ImageXMLSerializer() - fixtures = { + fixture = { 'images': [ { 'id': 1, 'name': 'Image1', - 'created': self.TIMESTAMP, - 'updated': self.TIMESTAMP, - 'serverRef': self.SERVER_HREF, - 'status': 'ACTIVE', 'links': [ { - 'href': 'http://localhost/v1.1/images/1', - 'rel': 'bookmark', - 'type': 'application/json', + 'href': self.IMAGE_HREF % 1, + 'rel': 'self', }, ], }, { 'id': 2, - 'name': 'queued image', - 'created': self.TIMESTAMP, - 'updated': self.TIMESTAMP, - 'serverRef': self.SERVER_HREF, - 'status': 'QUEUED', + 'name': 'Image2', 'links': [ { - 'href': 'http://localhost/v1.1/images/2', - 'rel': 'bookmark', - 'type': 'application/json', + 'href': self.IMAGE_HREF % 2, + 'rel': 'self', }, ], }, - ], + ] } - output = serializer.serialize(fixtures, 'index') + output = serializer.serialize(fixture, 'index') actual = minidom.parseString(output.replace(" ", "")) - expected_serverRef = self.SERVER_HREF + expected_server_href = self.SERVER_HREF + expected_server_bookmark = self.SERVER_BOOKMARK + expected_href = self.IMAGE_HREF % 1 + expected_bookmark = self.IMAGE_BOOKMARK % 1 + expected_href_two = self.IMAGE_HREF % 2 + expected_bookmark_two = self.IMAGE_BOOKMARK % 2 expected_now = self.TIMESTAMP expected = minidom.parseString(""" - <images xmlns="http://docs.openstack.org/compute/api/v1.1"> - <image id="1" - name="Image1" - serverRef="%(expected_serverRef)s" - updated="%(expected_now)s" - created="%(expected_now)s" - status="ACTIVE"> - <links> - <link href="http://localhost/v1.1/images/1" rel="bookmark" - type="application/json" /> - </links> - </image> - <image id="2" - name="queued image" - serverRef="%(expected_serverRef)s" - updated="%(expected_now)s" - created="%(expected_now)s" - status="QUEUED"> - <links> - <link href="http://localhost/v1.1/images/2" rel="bookmark" - type="application/json" /> - </links> - </image> + <images + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom"> + <image id="1" name="Image1"> + <atom:link href="%(expected_href)s" rel="self"/> + </image> + <image id="2" name="Image2"> + <atom:link href="%(expected_href_two)s" rel="self"/> + </image> </images> """.replace(" ", "") % (locals())) @@ -1356,10 +1547,10 @@ class ImageXMLSerializationTest(test.TestCase): output = serializer.serialize(fixtures, 'index') actual = minidom.parseString(output.replace(" ", "")) - expected_serverRef = self.SERVER_HREF - expected_now = self.TIMESTAMP expected = minidom.parseString(""" - <images xmlns="http://docs.openstack.org/compute/api/v1.1" /> + <images + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" /> """.replace(" ", "") % (locals())) self.assertEqual(expected.toxml(), actual.toxml()) @@ -1367,84 +1558,102 @@ class ImageXMLSerializationTest(test.TestCase): def test_detail(self): serializer = images.ImageXMLSerializer() - fixtures = { + fixture = { 'images': [ { 'id': 1, 'name': 'Image1', 'created': self.TIMESTAMP, 'updated': self.TIMESTAMP, - 'serverRef': self.SERVER_HREF, 'status': 'ACTIVE', - 'metadata': { - 'key1': 'value1', - 'key2': 'value2', + 'server': { + 'id': 1, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], }, 'links': [ { - 'href': 'http://localhost/v1.1/images/1', + 'href': self.IMAGE_HREF % 1, + 'rel': 'self', + }, + { + 'href': self.IMAGE_BOOKMARK % 1, 'rel': 'bookmark', - 'type': 'application/json', }, ], }, { 'id': 2, - 'name': 'queued image', + 'name': 'Image2', 'created': self.TIMESTAMP, 'updated': self.TIMESTAMP, - 'serverRef': self.SERVER_HREF, - 'metadata': {}, - 'status': 'QUEUED', + 'status': 'SAVING', + 'progress': 80, + 'metadata': { + 'key1': 'value1', + }, 'links': [ { - 'href': 'http://localhost/v1.1/images/2', + 'href': self.IMAGE_HREF % 2, + 'rel': 'self', + }, + { + 'href': self.IMAGE_BOOKMARK % 2, 'rel': 'bookmark', - 'type': 'application/json', }, ], }, - ], + ] } - output = serializer.serialize(fixtures, 'detail') + output = serializer.serialize(fixture, 'detail') actual = minidom.parseString(output.replace(" ", "")) - expected_serverRef = self.SERVER_HREF + expected_server_href = self.SERVER_HREF + expected_server_bookmark = self.SERVER_BOOKMARK + expected_href = self.IMAGE_HREF % 1 + expected_bookmark = self.IMAGE_BOOKMARK % 1 + expected_href_two = self.IMAGE_HREF % 2 + expected_bookmark_two = self.IMAGE_BOOKMARK % 2 expected_now = self.TIMESTAMP expected = minidom.parseString(""" - <images xmlns="http://docs.openstack.org/compute/api/v1.1"> - <image id="1" - name="Image1" - serverRef="%(expected_serverRef)s" - updated="%(expected_now)s" - created="%(expected_now)s" - status="ACTIVE"> - <links> - <link href="http://localhost/v1.1/images/1" rel="bookmark" - type="application/json" /> - </links> - <metadata> - <meta key="key2"> - value2 - </meta> - <meta key="key1"> - value1 - </meta> - </metadata> - </image> - <image id="2" - name="queued image" - serverRef="%(expected_serverRef)s" - updated="%(expected_now)s" - created="%(expected_now)s" - status="QUEUED"> - <links> - <link href="http://localhost/v1.1/images/2" rel="bookmark" - type="application/json" /> - </links> - <metadata /> - </image> + <images + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom"> + <image id="1" + name="Image1" + updated="%(expected_now)s" + created="%(expected_now)s" + status="ACTIVE"> + <server id="1"> + <atom:link rel="self" href="%(expected_server_href)s"/> + <atom:link rel="bookmark" href="%(expected_server_bookmark)s"/> + </server> + <atom:link href="%(expected_href)s" rel="self"/> + <atom:link href="%(expected_bookmark)s" rel="bookmark"/> + </image> + <image id="2" + name="Image2" + updated="%(expected_now)s" + created="%(expected_now)s" + status="SAVING" + progress="80"> + <metadata> + <meta key="key1"> + value1 + </meta> + </metadata> + <atom:link href="%(expected_href_two)s" rel="self"/> + <atom:link href="%(expected_bookmark_two)s" rel="bookmark"/> + </image> </images> """.replace(" ", "") % (locals())) @@ -1459,16 +1668,32 @@ class ImageXMLSerializationTest(test.TestCase): 'name': 'Image1', 'created': self.TIMESTAMP, 'updated': self.TIMESTAMP, - 'serverRef': self.SERVER_HREF, - 'status': 'ACTIVE', + 'status': 'SAVING', + 'progress': 80, + 'server': { + 'id': 1, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + }, 'metadata': { 'key1': 'value1', }, 'links': [ { - 'href': self.IMAGE_HREF % (1,), + 'href': self.IMAGE_HREF % 1, + 'rel': 'self', + }, + { + 'href': self.IMAGE_BOOKMARK % 1, 'rel': 'bookmark', - 'type': 'application/json', }, ], }, @@ -1478,25 +1703,30 @@ class ImageXMLSerializationTest(test.TestCase): actual = minidom.parseString(output.replace(" ", "")) expected_server_href = self.SERVER_HREF - expected_href = self.IMAGE_HREF % (1, ) + expected_server_bookmark = self.SERVER_BOOKMARK + expected_href = self.IMAGE_HREF % 1 + expected_bookmark = self.IMAGE_BOOKMARK % 1 expected_now = self.TIMESTAMP expected = minidom.parseString(""" <image id="1" + xmlns="http://docs.openstack.org/compute/api/v1.1" + xmlns:atom="http://www.w3.org/2005/Atom" name="Image1" - serverRef="%(expected_server_href)s" updated="%(expected_now)s" created="%(expected_now)s" - status="ACTIVE" - xmlns="http://docs.openstack.org/compute/api/v1.1"> - <links> - <link href="%(expected_href)s" rel="bookmark" - type="application/json" /> - </links> + status="SAVING" + progress="80"> + <server id="1"> + <atom:link rel="self" href="%(expected_server_href)s"/> + <atom:link rel="bookmark" href="%(expected_server_bookmark)s"/> + </server> <metadata> <meta key="key1"> value1 </meta> </metadata> + <atom:link href="%(expected_href)s" rel="self"/> + <atom:link href="%(expected_bookmark)s" rel="bookmark"/> </image> """.replace(" ", "") % (locals())) |