diff --git a/cinder/rpc.py b/cinder/rpc.py index 11de4f0bd67..ab4d0325afb 100644 --- a/cinder/rpc.py +++ b/cinder/rpc.py @@ -31,10 +31,11 @@ from oslo_log import log as logging import oslo_messaging as messaging from oslo_utils import importutils profiler = importutils.try_import('osprofiler.profiler') +import six import cinder.context import cinder.exception -from cinder.i18n import _LE, _LI +from cinder.i18n import _, _LE, _LI from cinder import objects from cinder.objects import base @@ -170,6 +171,28 @@ def get_notifier(service=None, host=None, publisher_id=None): return NOTIFIER.prepare(publisher_id=publisher_id) +def assert_min_rpc_version(min_ver, exc=None): + """Decorator to block RPC calls when version cap is lower than min_ver.""" + + if exc is None: + exc = cinder.exception.ServiceTooOld + + def decorator(f): + @six.wraps(f) + def _wrapper(self, *args, **kwargs): + if not self.client.can_send_version(min_ver): + msg = _('One of %(binary)s services is too old to accept ' + '%(method)s request. Required RPC API version is ' + '%(version)s. Are you running mixed versions of ' + '%(binary)ss?') % {'binary': self.BINARY, + 'version': min_ver, + 'method': f.__name__} + raise exc(msg) + return f(self, *args, **kwargs) + return _wrapper + return decorator + + LAST_RPC_VERSIONS = {} LAST_OBJ_VERSIONS = {} diff --git a/cinder/scheduler/rpcapi.py b/cinder/scheduler/rpcapi.py index abf70411bcc..18e304bd439 100644 --- a/cinder/scheduler/rpcapi.py +++ b/cinder/scheduler/rpcapi.py @@ -20,8 +20,6 @@ from oslo_serialization import jsonutils from oslo_utils import timeutils from cinder.common import constants -from cinder import exception -from cinder.i18n import _ from cinder import rpc @@ -148,13 +146,10 @@ class SchedulerAPI(rpc.RPCAPI): } return cctxt.cast(ctxt, 'manage_existing', **msg_args) + @rpc.assert_min_rpc_version('3.2') def extend_volume(self, ctxt, volume, new_size, reservations, request_spec, filter_properties=None): cctxt = self._get_cctxt() - if not cctxt.can_send_version('3.2'): - msg = _('extend_volume requires cinder-scheduler ' - 'RPC API version >= 3.2.') - raise exception.ServiceTooOld(msg) request_spec_p = jsonutils.to_primitive(request_spec) msg_args = { @@ -194,14 +189,9 @@ class SchedulerAPI(rpc.RPCAPI): cctxt = self._get_cctxt(fanout=True, version=version) cctxt.cast(ctxt, 'update_service_capabilities', **msg_args) + @rpc.assert_min_rpc_version('3.1') def notify_service_capabilities(self, ctxt, service_name, backend, capabilities, timestamp=None): - version = '3.1' - if not self.client.can_send_version(version): - msg = _('notify_service_capabilities requires cinder-scheduler ' - 'RPC API version >= 3.1.') - raise exception.ServiceTooOld(msg) - parameters = {'service_name': service_name, 'capabilities': capabilities} if self.client.can_send_version('3.5'): @@ -209,32 +199,23 @@ class SchedulerAPI(rpc.RPCAPI): parameters.update(backend=backend, timestamp=self.prepare_timestamp(timestamp)) else: + version = '3.1' parameters['host'] = backend cctxt = self._get_cctxt(version=version) cctxt.cast(ctxt, 'notify_service_capabilities', **parameters) + @rpc.assert_min_rpc_version('3.4') def work_cleanup(self, ctxt, cleanup_request): """Generate individual service cleanup requests from user request.""" - if not self.client.can_send_version('3.4'): - msg = _('One of cinder-scheduler services is too old to accept ' - 'such request. Are you running mixed Newton-Ocata' - 'cinder-schedulers?') - raise exception.ServiceTooOld(msg) - cctxt = self.client.prepare(version='3.4') # Response will have services that are receiving the cleanup request # and services that couldn't receive it since they are down. return cctxt.call(ctxt, 'work_cleanup', cleanup_request=cleanup_request) + @rpc.assert_min_rpc_version('3.4') def do_cleanup(self, ctxt, cleanup_request): """Perform this scheduler's resource cleanup as per cleanup_request.""" - if not self.client.can_send_version('3.4'): - msg = _('One of cinder-scheduler services is too old to accept ' - 'such request. Are you running mixed Newton-Ocata' - 'cinder-schedulers?') - raise exception.ServiceTooOld(msg) - cctxt = self.client.prepare(version='3.4') cctxt.cast(ctxt, 'do_cleanup', cleanup_request=cleanup_request) diff --git a/cinder/volume/rpcapi.py b/cinder/volume/rpcapi.py index 2092bdebccf..9853c00cada 100644 --- a/cinder/volume/rpcapi.py +++ b/cinder/volume/rpcapi.py @@ -14,8 +14,6 @@ from cinder.common import constants -from cinder import exception -from cinder.i18n import _ from cinder import objects from cinder import quota from cinder import rpc @@ -429,13 +427,8 @@ class VolumeAPI(rpc.RPCAPI): cctxt.cast(ctxt, 'delete_group_snapshot', group_snapshot=group_snapshot) + @rpc.assert_min_rpc_version('3.9') def attachment_update(self, ctxt, vref, connector, attachment_id): - if not self.client.can_send_version('3.9'): - msg = _('One of cinder-volume services is too old to accept ' - 'such request. Are you running mixed Newton-Ocata' - 'cinder-schedulers?') - raise exception.ServiceTooOld(msg) - version = self._compat_ver('3.9') cctxt = self._get_cctxt(vref.host, version=version) return cctxt.call(ctxt, @@ -444,13 +437,8 @@ class VolumeAPI(rpc.RPCAPI): connector=connector, attachment_id=attachment_id) + @rpc.assert_min_rpc_version('3.9') def attachment_delete(self, ctxt, attachment_id, vref): - if not self.client.can_send_version('3.9'): - msg = _('One of cinder-volume services is too old to accept ' - 'such request. Are you running mixed Newton-Ocata' - 'cinder-schedulers?') - raise exception.ServiceTooOld(msg) - version = self._compat_ver('3.9') cctxt = self._get_cctxt(vref.host, version=version) return cctxt.call(ctxt, @@ -458,13 +446,9 @@ class VolumeAPI(rpc.RPCAPI): attachment_id=attachment_id, vref=vref) + @rpc.assert_min_rpc_version('3.7') def do_cleanup(self, ctxt, cleanup_request): """Perform this service/cluster resource cleanup as requested.""" - if not self.client.can_send_version('3.7'): - msg = _('One of cinder-volume services is too old to accept such ' - 'a request. Are you running mixed Newton-Ocata services?') - raise exception.ServiceTooOld(msg) - destination = cleanup_request.service_topic_queue cctxt = self._get_cctxt(destination, '3.7') # NOTE(geguileo): This call goes to do_cleanup code in