diff --git a/cinder/manager.py b/cinder/manager.py index ac1499328df..94651056bb8 100644 --- a/cinder/manager.py +++ b/cinder/manager.py @@ -174,11 +174,20 @@ class SchedulerDependentManager(Manager): self.service_name, self.host, self.last_capabilities) - self.scheduler_rpcapi.notify_service_capabilities( - context, - self.service_name, - self.host, - self.last_capabilities) + try: + self.scheduler_rpcapi.notify_service_capabilities( + context, + self.service_name, + self.host, + self.last_capabilities) + except exception.ServiceTooOld as e: + # This means we have Newton's c-sch in the deployment, so + # rpcapi cannot send the message. We can safely ignore the + # error. Log it because it shouldn't happen after upgrade. + msg = _LW("Failed to notify about cinder-volume service " + "capabilities for host %(host)s. This is normal " + "during a live upgrade. Error: %(e)s") + LOG.warning(msg, {'host': self.host, 'e': e}) def _add_to_threadpool(self, func, *args, **kwargs): self._tp.spawn_n(func, *args, **kwargs) diff --git a/cinder/scheduler/rpcapi.py b/cinder/scheduler/rpcapi.py index 363c7495648..db1e89f1db8 100644 --- a/cinder/scheduler/rpcapi.py +++ b/cinder/scheduler/rpcapi.py @@ -19,6 +19,8 @@ Client side of the scheduler manager RPC API. from oslo_serialization import jsonutils from cinder.common import constants +from cinder import exception +from cinder.i18n import _ from cinder import rpc @@ -144,6 +146,10 @@ class SchedulerAPI(rpc.RPCAPI): def notify_service_capabilities(self, ctxt, service_name, host, capabilities): cctxt = self._get_cctxt(version='3.1') + if not cctxt.can_send_version('3.1'): + msg = _('notify_service_capabilities requires cinder-scheduler ' + 'RPC API version >= 3.1.') + raise exception.ServiceTooOld(msg) cctxt.cast(ctxt, 'notify_service_capabilities', service_name=service_name, host=host, capabilities=capabilities) diff --git a/cinder/tests/unit/scheduler/test_rpcapi.py b/cinder/tests/unit/scheduler/test_rpcapi.py index 9b280e8cb77..16d7c55f4fc 100644 --- a/cinder/tests/unit/scheduler/test_rpcapi.py +++ b/cinder/tests/unit/scheduler/test_rpcapi.py @@ -20,6 +20,7 @@ Unit Tests for cinder.scheduler.rpcapi import mock from cinder import context +from cinder import exception from cinder.scheduler import rpcapi as scheduler_rpcapi from cinder import test from cinder.tests.unit import fake_constants @@ -96,7 +97,8 @@ class SchedulerRpcAPITestCase(test.TestCase): version='3.0') create_worker_mock.assert_called_once() - def test_notify_service_capabilities(self): + @mock.patch('oslo_messaging.RPCClient.can_send_version', return_value=True) + def test_notify_service_capabilities(self, can_send_version_mock): capabilities = {'host': 'fake_host', 'total': '10.01', } self._test_scheduler_api('notify_service_capabilities', @@ -106,6 +108,20 @@ class SchedulerRpcAPITestCase(test.TestCase): capabilities=capabilities, version='3.1') + @mock.patch('oslo_messaging.RPCClient.can_send_version', + return_value=False) + def test_notify_service_capabilities_capped(self, can_send_version_mock): + capabilities = {'host': 'fake_host', + 'total': '10.01', } + self.assertRaises(exception.ServiceTooOld, + self._test_scheduler_api, + 'notify_service_capabilities', + rpc_method='cast', + service_name='fake_name', + host='fake_host', + capabilities=capabilities, + version='3.1') + def test_create_volume_serialization(self): volume = fake_volume.fake_volume_obj(self.context) create_worker_mock = self.mock_object(volume, 'create_worker')