From 0b7c4cc54e0691beeff5c62cc43f8febf6064edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dulko?= Date: Tue, 24 Jan 2017 15:17:41 +0100 Subject: [PATCH] Add assert_min_rpc_version decorator We have multiple places in RPC APIs where we're blocking sending RPC calls if version cap is set to value lower than our minimal version. This commit implements this consistently by adding a reusable decorator that can be used with RPC API methods. Change-Id: I11c0d79c45294bd412feffd4b301359254d2e143 --- cinder/rpc.py | 25 ++++++++++++++++++++++++- cinder/scheduler/rpcapi.py | 29 +++++------------------------ cinder/volume/rpcapi.py | 22 +++------------------- 3 files changed, 32 insertions(+), 44 deletions(-) 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 9c4d0f708b4..c719f0f611e 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 ec28be9308b..af3907cd13f 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 @@ -407,13 +405,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, @@ -422,13 +415,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, @@ -436,13 +424,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