summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/api/openstack/common.py17
-rw-r--r--nova/api/openstack/images.py111
-rw-r--r--nova/api/openstack/views/images.py28
-rw-r--r--nova/api/openstack/wsgi.py23
-rw-r--r--nova/tests/api/openstack/test_common.py33
-rw-r--r--nova/tests/api/openstack/test_images.py532
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()))