From 9e9b3ec7ea29a636f8847dc1022c37f0e442fc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dulko?= Date: Tue, 2 Aug 2016 18:25:45 +0200 Subject: [PATCH] Pin RPC server's serializer to min obj version We're passing object version pin on CinderObjectSerializer initialization in RPC clients (rpcapis), but not in RPC servers (managers). This means that objects returned from RPC calls aren't backported and older service can get a response with an object version it doesn't understand. As on RPC server side we don't know who called us, we need to consider minimum object version among all the binaries, not only the one we're running. This commit implements that behavior. Closes-Bug: 1609304 Change-Id: Ibc708eb6ca6d792bec0f38abb4e1b5f58488a414 --- cinder/objects/service.py | 2 +- cinder/service.py | 8 ++++++-- cinder/tests/unit/objects/test_service.py | 15 +++++++++++++++ cinder/tests/unit/test_service.py | 2 +- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/cinder/objects/service.py b/cinder/objects/service.py index 186c08cc896..aeae75b6176 100644 --- a/cinder/objects/service.py +++ b/cinder/objects/service.py @@ -183,7 +183,7 @@ class Service(base.CinderPersistentObject, base.CinderObject, return cls._get_minimum_version('rpc_current_version', context, binary) @classmethod - def get_minimum_obj_version(cls, context, binary): + def get_minimum_obj_version(cls, context, binary=None): return cls._get_minimum_version('object_current_version', context, binary) diff --git a/cinder/service.py b/cinder/service.py index 09b7aa71904..d979d42359a 100644 --- a/cinder/service.py +++ b/cinder/service.py @@ -231,10 +231,14 @@ class Service(service.Service): LOG.debug("Creating RPC server for service %s", self.topic) + ctxt = context.get_admin_context() target = messaging.Target(topic=self.topic, server=self.host) endpoints = [self.manager] endpoints.extend(self.manager.additional_endpoints) - serializer = objects_base.CinderObjectSerializer() + obj_version_cap = objects.Service.get_minimum_obj_version(ctxt) + LOG.debug("Pinning object versions for RPC server serializer to %s", + obj_version_cap) + serializer = objects_base.CinderObjectSerializer(obj_version_cap) self.rpcserver = rpc.get_server(target, endpoints, serializer) self.rpcserver.start() @@ -245,7 +249,7 @@ class Service(service.Service): {'topic': self.topic, 'version': version_string, 'cluster': self.cluster}) target = messaging.Target(topic=self.topic, server=self.cluster) - serializer = objects_base.CinderObjectSerializer() + serializer = objects_base.CinderObjectSerializer(obj_version_cap) self.cluster_rpcserver = rpc.get_server(target, endpoints, serializer) self.cluster_rpcserver.start() diff --git a/cinder/tests/unit/objects/test_service.py b/cinder/tests/unit/objects/test_service.py index f93e7c43459..0f485da012b 100644 --- a/cinder/tests/unit/objects/test_service.py +++ b/cinder/tests/unit/objects/test_service.py @@ -147,6 +147,21 @@ class TestService(test_objects.BaseObjectsTestCase): objects.Service.get_minimum_obj_version, self.context, 'foo') + @mock.patch('cinder.db.service_get_all') + def test_get_minimum_version_no_binary(self, service_get_all): + services_update = [ + {'rpc_current_version': '1.0', 'object_current_version': '1.3'}, + {'rpc_current_version': '1.1', 'object_current_version': '1.2'}, + {'rpc_current_version': '2.0', 'object_current_version': '2.5'}, + ] + services = [fake_service.fake_db_service(**s) for s in services_update] + service_get_all.return_value = services + + min_obj = objects.Service.get_minimum_obj_version(self.context) + self.assertEqual('1.2', min_obj) + service_get_all.assert_called_once_with(self.context, binary=None, + disabled=None) + class TestServiceList(test_objects.BaseObjectsTestCase): @mock.patch('cinder.db.service_get_all') diff --git a/cinder/tests/unit/test_service.py b/cinder/tests/unit/test_service.py index 2d5ef763717..55a592f5888 100644 --- a/cinder/tests/unit/test_service.py +++ b/cinder/tests/unit/test_service.py @@ -458,7 +458,7 @@ class ServiceTestCase(test.TestCase): cluster=None, topic=self.topic) self._check_rpc_servers_and_init_host(app, True, None) - @ddt.data('1.3', '1.8') + @ddt.data('1.3', '1.7') @mock.patch('cinder.objects.Service.get_minimum_obj_version') def test_start_rpc_and_init_host_cluster(self, obj_version, get_min_obj_mock):