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
This commit is contained in:
Michał Dulko 2016-08-02 18:25:45 +02:00
parent 0f1ea3cfda
commit 9e9b3ec7ea
4 changed files with 23 additions and 4 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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')

View File

@ -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):