LOG.exception(_LE("Problem cleaning incomplete backup "
"operations."))
+ def reset(self):
+ super(BackupManager, self).reset()
+ self.backup_rpcapi = backup_rpcapi.BackupAPI()
+ self.volume_rpcapi = volume_rpcapi.VolumeAPI()
+
def _cleanup_incomplete_backup_operations(self, ctxt):
LOG.info(_LI("Cleaning up incomplete backup operations."))
from oslo_service import periodic_task
from cinder.db import base
+from cinder.i18n import _LI
+from cinder import rpc
from cinder.scheduler import rpcapi as scheduler_rpcapi
from cinder import version
"""
return True
+ def reset(self):
+ """Method executed when SIGHUP is caught by the process.
+
+ We're utilizing it to reset RPC API version pins to avoid restart of
+ the service when rolling upgrade is completed.
+ """
+ LOG.info(_LI('Resetting cached RPC version pins.'))
+ rpc.LAST_OBJ_VERSIONS = {}
+ rpc.LAST_RPC_VERSIONS = {}
+
class SchedulerDependentManager(Manager):
"""Periodically send capability updates to the Scheduler services.
def _add_to_threadpool(self, func, *args, **kwargs):
self._tp.spawn_n(func, *args, **kwargs)
+
+ def reset(self):
+ super(SchedulerDependentManager, self).reset()
+ self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
CONF.scheduler_host_manager)
self.volume_rpcapi = volume_rpcapi.VolumeAPI()
+ def reset(self):
+ """Reset volume RPC API object to load new version pins."""
+ self.volume_rpcapi = volume_rpcapi.VolumeAPI()
+
def is_ready(self):
"""Returns True if Scheduler is ready to accept requests.
eventlet.sleep(CONF.periodic_interval)
self._startup_delay = False
+ def reset(self):
+ super(SchedulerManager, self).reset()
+ self.driver.reset()
+
def update_service_capabilities(self, context, service_name=None,
host=None, capabilities=None, **kwargs):
"""Process a capability update from a service node."""
self.model_disconnected = True
LOG.exception(_LE('Exception encountered: '))
+ def reset(self):
+ self.manager.reset()
+ super(Service, self).reset()
+
class WSGIService(service.ServiceBase):
"""Provides ability to launch API from a 'paste' configuration."""
sleep_mock.assert_called_once_with(CONF.periodic_interval)
self.assertFalse(self.manager._startup_delay)
+ @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'cinder-volume': '1.3'})
+ @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'cinder-volume': '1.5'})
+ def test_reset(self):
+ mgr = self.manager_cls()
+
+ volume_rpcapi = mgr.driver.volume_rpcapi
+ self.assertEqual('1.3', volume_rpcapi.client.version_cap)
+ self.assertEqual('1.5',
+ volume_rpcapi.client.serializer._base.version_cap)
+ mgr.reset()
+
+ volume_rpcapi = mgr.driver.volume_rpcapi
+ self.assertIsNone(volume_rpcapi.client.version_cap)
+ self.assertIsNone(volume_rpcapi.client.serializer._base.version_cap)
+
@mock.patch('cinder.scheduler.driver.Scheduler.'
'update_service_capabilities')
def test_update_service_capabilities_empty_dict(self, _mock_update_cap):
mock_add_threadpool.assert_has_calls(calls, any_order=True)
self.assertEqual(2, mock_add_threadpool.call_count)
+ @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'cinder-backup': '1.3',
+ 'cinder-volume': '1.7'})
+ @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'cinder-backup': '1.5',
+ 'cinder-volume': '1.4'})
+ def test_reset(self):
+ backup_mgr = manager.BackupManager()
+
+ backup_rpcapi = backup_mgr.backup_rpcapi
+ volume_rpcapi = backup_mgr.volume_rpcapi
+ self.assertEqual('1.3', backup_rpcapi.client.version_cap)
+ self.assertEqual('1.5',
+ backup_rpcapi.client.serializer._base.version_cap)
+ self.assertEqual('1.7', volume_rpcapi.client.version_cap)
+ self.assertEqual('1.4',
+ volume_rpcapi.client.serializer._base.version_cap)
+ backup_mgr.reset()
+
+ backup_rpcapi = backup_mgr.backup_rpcapi
+ volume_rpcapi = backup_mgr.volume_rpcapi
+ self.assertIsNone(backup_rpcapi.client.version_cap)
+ self.assertIsNone(backup_rpcapi.client.serializer._base.version_cap)
+ self.assertIsNone(volume_rpcapi.client.version_cap)
+ self.assertIsNone(volume_rpcapi.client.serializer._base.version_cap)
+
def test_is_working(self):
self.assertTrue(self.backup_mgr.is_working())
serv.start()
self.assertEqual('service', serv.test_method())
+ @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'test': '1.5'})
+ @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'test': '1.3'})
+ def test_reset(self):
+ serv = service.Service('test',
+ 'test',
+ 'test',
+ 'cinder.tests.unit.test_service.FakeManager')
+ serv.start()
+ serv.reset()
+ self.assertEqual({}, rpc.LAST_OBJ_VERSIONS)
+ self.assertEqual({}, rpc.LAST_RPC_VERSIONS)
+
class ServiceFlagsTestCase(test.TestCase):
def test_service_enabled_on_create_based_on_flag(self):
manager.init_host()
self.assertEqual(0, mock_add_p_task.call_count)
+ @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'cinder-scheduler': '1.3'})
+ @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'cinder-scheduler': '1.5'})
+ def test_reset(self):
+ vol_mgr = vol_manager.VolumeManager()
+
+ scheduler_rpcapi = vol_mgr.scheduler_rpcapi
+ self.assertEqual('1.3', scheduler_rpcapi.client.version_cap)
+ self.assertEqual('1.5',
+ scheduler_rpcapi.client.serializer._base.version_cap)
+ vol_mgr.reset()
+
+ scheduler_rpcapi = vol_mgr.scheduler_rpcapi
+ self.assertIsNone(scheduler_rpcapi.client.version_cap)
+ self.assertIsNone(scheduler_rpcapi.client.serializer._base.version_cap)
+
@mock.patch.object(vol_manager.VolumeManager,
'update_service_capabilities')
def test_report_filter_goodness_function(self, mock_update):
--- /dev/null
+---
+features:
+ - Added RPC backward compatibility layer similar to the
+ one implemented in Nova. This means that Cinder
+ services can be upgraded one-by-one without breakage.
+ After all the services are upgraded SIGHUP signals
+ should be issued to all the services to signal them
+ to reload cached minimum RPC versions. Alternative
+ is of course restart of them. Please note that
+ cinder-api service doesn't support SIGHUP yet.
+ Please also take into account that all the rolling
+ upgrades capabilities are considered tech preview,
+ as we don't have a CI testing it yet.
+upgrade:
+ - Starting from Mitaka release Cinder is having a tech
+ preview of rolling upgrades support.