From 587eb5a6b9acc9f02eee1147dbaafb3782c295d5 Mon Sep 17 00:00:00 2001 From: Flaper Fesp Date: Wed, 4 Sep 2013 13:29:22 +0200 Subject: [PATCH] Call to_primitive on volumes.rpcapi.create_volume cinder.volume.rpcapi.create_volume does not convert the request_spec to primitive before casting the request. This makes requests containing non primitive types to fail. For example: cinder create --metadata=Type=test --source-volid $VOLID 1 This will create a new database record and call create_volume on volume.rpcapi. This will fail because VolumeMetadata won't be serialized correctly when calling cast. This, however, is not True when --source-volid is not passed because in such case, scheduler.rpcpai.create_volume will be called, which converts request_spec to primitive correctly. Closes-Bug: #1213964 Change-Id: I096d815254c9782390fba05ea9cd9af925635402 --- cinder/tests/test_volume_rpcapi.py | 21 +++++++++++++++++++++ cinder/volume/rpcapi.py | 5 ++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cinder/tests/test_volume_rpcapi.py b/cinder/tests/test_volume_rpcapi.py index dead83eff..1a596bb83 100644 --- a/cinder/tests/test_volume_rpcapi.py +++ b/cinder/tests/test_volume_rpcapi.py @@ -42,6 +42,7 @@ class VolumeRpcAPITestCase(test.TestCase): vol['availability_zone'] = CONF.storage_availability_zone vol['status'] = "available" vol['attach_status'] = "detached" + vol['metadata'] = {"test_key": "test_val"} volume = db.volume_create(self.context, vol) snpshot = { @@ -53,6 +54,7 @@ class VolumeRpcAPITestCase(test.TestCase): 'display_description': 'fake_description'} snapshot = db.snapshot_create(self.context, snpshot) self.fake_volume = jsonutils.to_primitive(volume) + self.fake_volume_metadata = volume["volume_metadata"] self.fake_snapshot = jsonutils.to_primitive(snapshot) def test_serialized_volume_has_id(self): @@ -70,6 +72,11 @@ class VolumeRpcAPITestCase(test.TestCase): expected_retval = 'foo' if method == 'call' else None expected_version = kwargs.pop('version', rpcapi.BASE_RPC_API_VERSION) + + if 'request_spec' in kwargs: + spec = jsonutils.to_primitive(kwargs['request_spec']) + kwargs['request_spec'] = spec + expected_msg = rpcapi.make_msg(method, **kwargs) if 'volume' in expected_msg['args']: volume = expected_msg['args']['volume'] @@ -131,6 +138,20 @@ class VolumeRpcAPITestCase(test.TestCase): source_volid='fake_src_id', version='1.4') + def test_create_volume_serialization(self): + request_spec = {"metadata": self.fake_volume_metadata} + self._test_volume_api('create_volume', + rpc_method='cast', + volume=self.fake_volume, + host='fake_host1', + request_spec=request_spec, + filter_properties='fake_properties', + allow_reschedule=True, + snapshot_id='fake_snapshot_id', + image_id='fake_image_id', + source_volid='fake_src_id', + version='1.4') + def test_delete_volume(self): self._test_volume_api('delete_volume', rpc_method='cast', diff --git a/cinder/volume/rpcapi.py b/cinder/volume/rpcapi.py index 4737319f8..c74005921 100644 --- a/cinder/volume/rpcapi.py +++ b/cinder/volume/rpcapi.py @@ -20,6 +20,7 @@ Client side of the volume RPC API. from oslo.config import cfg +from cinder.openstack.common import jsonutils from cinder.openstack.common import rpc import cinder.openstack.common.rpc.proxy @@ -61,10 +62,12 @@ class VolumeAPI(cinder.openstack.common.rpc.proxy.RpcProxy): allow_reschedule=True, snapshot_id=None, image_id=None, source_volid=None): + + request_spec_p = jsonutils.to_primitive(request_spec) self.cast(ctxt, self.make_msg('create_volume', volume_id=volume['id'], - request_spec=request_spec, + request_spec=request_spec_p, filter_properties=filter_properties, allow_reschedule=allow_reschedule, snapshot_id=snapshot_id, -- 2.45.2