From b65d678f4d475a62f9a83f96bddbeb6f694d1e5b Mon Sep 17 00:00:00 2001 From: Pascal Wehrle Date: Mon, 17 Nov 2014 23:20:17 +0100 Subject: [PATCH] allow image_id for imageRef in create volume API v2 The create volume request for the V2 API has a property named "imageRef" with the ID of the image to be used when creating the volume. The name of this property is inconsistent as all multi word properties use snake case and the property in the reponse is named "image_id". This adds support for aliasing the imageRef key with image_id when creating a volume in v2 of the Cinder API in a backward-compatible way. Change-Id: I85a5c6734ba05a8a7ea9eff3f849d12fb3d167fb Closes-Bug: 1375867 --- cinder/api/v2/volumes.py | 7 +- cinder/tests/api/v2/test_volumes.py | 100 ++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/cinder/api/v2/volumes.py b/cinder/api/v2/volumes.py index 8addd0f3d..96ef3150e 100644 --- a/cinder/api/v2/volumes.py +++ b/cinder/api/v2/volumes.py @@ -122,7 +122,8 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer): attributes = ['name', 'description', 'size', 'volume_type', 'availability_zone', 'imageRef', - 'snapshot_id', 'source_volid', 'consistencygroup_id'] + 'image_id', 'snapshot_id', 'source_volid', + 'consistencygroup_id'] for attr in attributes: if volume_node.getAttribute(attr): volume[attr] = volume_node.getAttribute(attr) @@ -290,6 +291,10 @@ class VolumeController(wsgi.Controller): volume['display_description'] = volume.get('description') del volume['description'] + if 'image_id' in volume: + volume['imageRef'] = volume.get('image_id') + del volume['image_id'] + req_volume_type = volume.get('volume_type', None) if req_volume_type: try: diff --git a/cinder/tests/api/v2/test_volumes.py b/cinder/tests/api/v2/test_volumes.py index 1fded8937..ded01d812 100644 --- a/cinder/tests/api/v2/test_volumes.py +++ b/cinder/tests/api/v2/test_volumes.py @@ -211,7 +211,7 @@ class VolumeApiTest(test.TestCase): self.controller.create, req, body) - def test_volume_create_with_image_id(self): + def test_volume_create_with_image_ref(self): self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get) self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create) @@ -250,9 +250,9 @@ class VolumeApiTest(test.TestCase): body = {"volume": vol} req = fakes.HTTPRequest.blank('/v2/volumes') res_dict = self.controller.create(req, body) - self.assertEqual(res_dict, ex) + self.assertEqual(ex, res_dict) - def test_volume_create_with_image_id_is_integer(self): + def test_volume_create_with_image_ref_is_integer(self): self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create) self.ext_mgr.extensions = {'os-image-create': 'fake'} vol = { @@ -269,7 +269,7 @@ class VolumeApiTest(test.TestCase): req, body) - def test_volume_create_with_image_id_not_uuid_format(self): + def test_volume_create_with_image_ref_not_uuid_format(self): self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create) self.ext_mgr.extensions = {'os-image-create': 'fake'} vol = { @@ -286,7 +286,7 @@ class VolumeApiTest(test.TestCase): req, body) - def test_volume_create_with_image_id_with_empty_string(self): + def test_volume_create_with_image_ref_with_empty_string(self): self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create) self.ext_mgr.extensions = {'os-image-create': 'fake'} vol = {"size": 1, @@ -301,6 +301,96 @@ class VolumeApiTest(test.TestCase): req, body) + def test_volume_create_with_image_id(self): + self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get) + self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create) + + self.ext_mgr.extensions = {'os-image-create': 'fake'} + vol = {"size": '1', + "name": "Volume Test Name", + "description": "Volume Test Desc", + "availability_zone": "nova", + "image_id": 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'} + ex = {'volume': {'attachments': [{'device': '/', + 'host_name': None, + 'id': '1', + 'server_id': 'fakeuuid', + 'volume_id': '1'}], + 'availability_zone': 'nova', + 'bootable': 'false', + 'consistencygroup_id': None, + 'created_at': datetime.datetime(1, 1, 1, 1, 1, 1), + 'description': 'Volume Test Desc', + 'encrypted': False, + 'id': '1', + 'links': + [{'href': 'http://localhost/v2/fakeproject/volumes/1', + 'rel': 'self'}, + {'href': 'http://localhost/fakeproject/volumes/1', + 'rel': 'bookmark'}], + 'metadata': {}, + 'name': 'Volume Test Name', + 'replication_status': 'disabled', + 'size': '1', + 'snapshot_id': None, + 'source_volid': None, + 'status': 'fakestatus', + 'user_id': 'fakeuser', + 'volume_type': 'vol_type_name'}} + body = {"volume": vol} + req = fakes.HTTPRequest.blank('/v2/volumes') + res_dict = self.controller.create(req, body) + self.assertEqual(ex, res_dict) + + def test_volume_create_with_image_id_is_integer(self): + self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create) + self.ext_mgr.extensions = {'os-image-create': 'fake'} + vol = { + "size": '1', + "name": "Volume Test Name", + "description": "Volume Test Desc", + "availability_zone": "cinder", + "image_id": 1234, + } + body = {"volume": vol} + req = fakes.HTTPRequest.blank('/v2/volumes') + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, + req, + body) + + def test_volume_create_with_image_id_not_uuid_format(self): + self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create) + self.ext_mgr.extensions = {'os-image-create': 'fake'} + vol = { + "size": '1', + "name": "Volume Test Name", + "description": "Volume Test Desc", + "availability_zone": "cinder", + "image_id": '12345' + } + body = {"volume": vol} + req = fakes.HTTPRequest.blank('/v2/volumes') + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, + req, + body) + + def test_volume_create_with_image_id_with_empty_string(self): + self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create) + self.ext_mgr.extensions = {'os-image-create': 'fake'} + vol = {"size": 1, + "display_name": "Volume Test Name", + "display_description": "Volume Test Desc", + "availability_zone": "cinder", + "image_id": ''} + body = {"volume": vol} + req = fakes.HTTPRequest.blank('/v2/volumes') + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, + req, + body) + def test_volume_update(self): self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get) self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update) -- 2.45.2