diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-09-11 17:52:26 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-09-11 17:52:26 +0000 |
| commit | 511807ed248fbe63cb6642c1cff6e0bd4bb8ae5d (patch) | |
| tree | 75d9441b819c895ab3586a6173e50b5aa6c67a19 | |
| parent | 93c765219967c721717c51bf031ffc098e366121 (diff) | |
| parent | 1f82e30db8e628e956190ea76f71c8a6f4803e24 (diff) | |
| download | nova-511807ed248fbe63cb6642c1cff6e0bd4bb8ae5d.tar.gz nova-511807ed248fbe63cb6642c1cff6e0bd4bb8ae5d.tar.xz nova-511807ed248fbe63cb6642c1cff6e0bd4bb8ae5d.zip | |
Merge "Fix xml metadata for volumes api in nova-volume."
| -rw-r--r-- | nova/api/openstack/volume/volumes.py | 53 | ||||
| -rw-r--r-- | nova/tests/api/openstack/volume/test_volumes.py | 137 |
2 files changed, 181 insertions, 9 deletions
diff --git a/nova/api/openstack/volume/volumes.py b/nova/api/openstack/volume/volumes.py index 85bbbd374..e83030945 100644 --- a/nova/api/openstack/volume/volumes.py +++ b/nova/api/openstack/volume/volumes.py @@ -17,6 +17,7 @@ import webob from webob import exc +from xml.dom import minidom from nova.api.openstack import common from nova.api.openstack import wsgi @@ -100,10 +101,8 @@ def _translate_volume_summary_view(context, vol): LOG.audit(_("vol=%s"), vol, context=context) if vol.get('volume_metadata'): - meta_dict = {} - for i in vol['volume_metadata']: - meta_dict[i['key']] = i['value'] - d['metadata'] = meta_dict + metadata = vol.get('volume_metadata') + d['metadata'] = dict((item['key'], item['value']) for item in metadata) else: d['metadata'] = {} @@ -133,8 +132,8 @@ def make_volume(elem): selector='attachments') make_attachment(attachment) - metadata = xmlutil.make_flat_dict('metadata') - elem.append(metadata) + # Attach metadata node + elem.append(common.MetadataTemplate()) class VolumeTemplate(xmlutil.TemplateBuilder): @@ -152,6 +151,47 @@ class VolumesTemplate(xmlutil.TemplateBuilder): return xmlutil.MasterTemplate(root, 1) +class CommonDeserializer(wsgi.MetadataXMLDeserializer): + """Common deserializer to handle xml-formatted volume requests. + + Handles standard volume attributes as well as the optional metadata + attribute + """ + + metadata_deserializer = common.MetadataXMLDeserializer() + + def _extract_volume(self, node): + """Marshal the volume attribute of a parsed request.""" + volume = {} + volume_node = self.find_first_child_named(node, 'volume') + + attributes = ['display_name', 'display_description', 'size', + 'volume_type', 'availability_zone'] + for attr in attributes: + if volume_node.getAttribute(attr): + volume[attr] = volume_node.getAttribute(attr) + + metadata_node = self.find_first_child_named(volume_node, 'metadata') + if metadata_node is not None: + volume['metadata'] = self.extract_metadata(metadata_node) + + return volume + + +class CreateDeserializer(CommonDeserializer): + """Deserializer to handle xml-formatted create volume requests. + + Handles standard volume attributes as well as the optional metadata + attribute + """ + + def default(self, string): + """Deserialize an xml-formatted volume create request.""" + dom = minidom.parseString(string) + volume = self._extract_volume(dom) + return {'body': {'volume': volume}} + + class VolumeController(object): """The Volumes API controller for the OpenStack API.""" @@ -210,6 +250,7 @@ class VolumeController(object): return {'volumes': res} @wsgi.serializers(xml=VolumeTemplate) + @wsgi.deserializers(xml=CreateDeserializer) def create(self, req, body): """Creates a new volume.""" context = req.environ['nova.context'] diff --git a/nova/tests/api/openstack/volume/test_volumes.py b/nova/tests/api/openstack/volume/test_volumes.py index 6b162dcea..46a772fbd 100644 --- a/nova/tests/api/openstack/volume/test_volumes.py +++ b/nova/tests/api/openstack/volume/test_volumes.py @@ -253,10 +253,10 @@ class VolumeSerializerTest(test.TestCase): elif child.tag == 'metadata': not_seen = set(vol['metadata'].keys()) for gr_child in child: - self.assertTrue(gr_child.tag in not_seen) - self.assertEqual(str(vol['metadata'][gr_child.tag]), + self.assertTrue(gr_child.get("key") in not_seen) + self.assertEqual(str(vol['metadata'][gr_child.get("key")]), gr_child.text) - not_seen.remove(gr_child.tag) + not_seen.remove(gr_child.get("key")) self.assertEqual(0, len(not_seen)) def test_volume_show_create_serializer(self): @@ -339,3 +339,134 @@ class VolumeSerializerTest(test.TestCase): self.assertEqual(len(raw_volumes), len(tree)) for idx, child in enumerate(tree): self._verify_volume(raw_volumes[idx], child) + + +class TestVolumeCreateRequestXMLDeserializer(test.TestCase): + + def setUp(self): + super(TestVolumeCreateRequestXMLDeserializer, self).setUp() + self.deserializer = volumes.CreateDeserializer() + + def test_minimal_volume(self): + self_request = """ +<volume xmlns="http://docs.openstack.org/compute/api/v1.1" + size="1"></volume>""" + request = self.deserializer.deserialize(self_request) + expected = { + "volume": { + "size": "1", + }, + } + self.assertEquals(request['body'], expected) + + def test_display_name(self): + self_request = """ +<volume xmlns="http://docs.openstack.org/compute/api/v1.1" + size="1" + display_name="Volume-xml"></volume>""" + request = self.deserializer.deserialize(self_request) + expected = { + "volume": { + "size": "1", + "display_name": "Volume-xml", + }, + } + self.assertEquals(request['body'], expected) + + def test_display_description(self): + self_request = """ +<volume xmlns="http://docs.openstack.org/compute/api/v1.1" + size="1" + display_name="Volume-xml" + display_description="description"></volume>""" + request = self.deserializer.deserialize(self_request) + expected = { + "volume": { + "size": "1", + "display_name": "Volume-xml", + "display_description": "description", + }, + } + self.assertEquals(request['body'], expected) + + def test_volume_type(self): + self_request = """ +<volume xmlns="http://docs.openstack.org/compute/api/v1.1" + size="1" + display_name="Volume-xml" + display_description="description" + volume_type="289da7f8-6440-407c-9fb4-7db01ec49164"></volume>""" + request = self.deserializer.deserialize(self_request) + expected = { + "volume": { + "display_name": "Volume-xml", + "size": "1", + "display_name": "Volume-xml", + "display_description": "description", + "volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164", + }, + } + self.assertEquals(request['body'], expected) + + def test_availability_zone(self): + self_request = """ +<volume xmlns="http://docs.openstack.org/compute/api/v1.1" + size="1" + display_name="Volume-xml" + display_description="description" + volume_type="289da7f8-6440-407c-9fb4-7db01ec49164" + availability_zone="us-east1"></volume>""" + request = self.deserializer.deserialize(self_request) + expected = { + "volume": { + "size": "1", + "display_name": "Volume-xml", + "display_description": "description", + "volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164", + "availability_zone": "us-east1", + }, + } + self.assertEquals(request['body'], expected) + + def test_metadata(self): + self_request = """ +<volume xmlns="http://docs.openstack.org/compute/api/v1.1" + display_name="Volume-xml" + size="1"> + <metadata><meta key="Type">work</meta></metadata></volume>""" + request = self.deserializer.deserialize(self_request) + expected = { + "volume": { + "display_name": "Volume-xml", + "size": "1", + "metadata": { + "Type": "work", + }, + }, + } + self.assertEquals(request['body'], expected) + + def test_full_volume(self): + self_request = """ +<volume xmlns="http://docs.openstack.org/compute/api/v1.1" + size="1" + display_name="Volume-xml" + display_description="description" + volume_type="289da7f8-6440-407c-9fb4-7db01ec49164" + availability_zone="us-east1"> + <metadata><meta key="Type">work</meta></metadata></volume>""" + request = self.deserializer.deserialize(self_request) + expected = { + "volume": { + "size": "1", + "display_name": "Volume-xml", + "display_description": "description", + "volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164", + "availability_zone": "us-east1", + "metadata": { + "Type": "work", + }, + }, + } + self.maxDiff = None + self.assertEquals(request['body'], expected) |
