]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add backup RPC API v2.0
authorMichał Dulko <michal.dulko@intel.com>
Mon, 22 Feb 2016 13:06:37 +0000 (14:06 +0100)
committerMichal Dulko <michal.dulko@intel.com>
Mon, 14 Mar 2016 15:49:12 +0000 (15:49 +0000)
This patch creates backup RPC API version 2.0, while retaining
compatibility in rpcapi and manager for 1.x, allowing for continuous
deployment scenarios.

This should be merged just before the Mitaka release.

UpgradeImpact - Deployments doing continous deployment should not
upgrade into Newton before doing an upgrade which includes all the
Mitaka's RPC API version bump commits (scheduler, volume, backup).

Related-Blueprint: rpc-object-compatibility

Change-Id: I0c66e4126901e6d60054d093cf87d43f4b9df666

cinder/backup/manager.py
cinder/backup/rpcapi.py
cinder/tests/unit/backup/test_rpcapi.py

index f29b1424c6bebe8dcd7848f90c9738205a12d598..02d2a88b64139b99980a5a7e04681e3fad113716 100644 (file)
@@ -93,6 +93,7 @@ class BackupManager(manager.SchedulerDependentManager):
         self.volume_rpcapi = volume_rpcapi.VolumeAPI()
         super(BackupManager, self).__init__(service_name='backup',
                                             *args, **kwargs)
+        self.additional_endpoints.append(_BackupV2Proxy(self))
 
     @property
     def driver_name(self):
@@ -855,3 +856,36 @@ class BackupManager(manager.SchedulerDependentManager):
         rpcapi = self.volume_rpcapi
         rpcapi.terminate_connection(context, volume, properties, force=force)
         rpcapi.remove_export(context, volume)
+
+
+# TODO(dulek): This goes away immediately in Newton and is just present in
+# Mitaka so that we can receive v1.x and v2.0 messages.
+class _BackupV2Proxy(object):
+
+    target = messaging.Target(version='2.0')
+
+    def __init__(self, manager):
+        self.manager = manager
+
+    def create_backup(self, context, backup):
+        return self.manager.create_backup(context, backup)
+
+    def restore_backup(self, context, backup, volume_id):
+        return self.manager.restore_backup(context, backup, volume_id)
+
+    def delete_backup(self, context, backup):
+        return self.manager.delete_backup(context, backup)
+
+    def export_record(self, context, backup):
+        return self.manager.export_record(context, backup)
+
+    def import_record(self, context, backup, backup_service, backup_url,
+                      backup_hosts):
+        return self.manager.import_record(context, backup, backup_service,
+                                          backup_url, backup_hosts)
+
+    def reset_status(self, context, backup, status):
+        return self.manager.reset_status(context, backup, status)
+
+    def check_support_to_force_delete(self, context):
+        return self.manager.check_support_to_force_delete(context)
index 245cc07b8247368ac40d97e59ed0cb53f5e12bb4..20f70c3d178b1815350cae906052b7e4c7e6f600 100644 (file)
@@ -38,26 +38,41 @@ class BackupAPI(rpc.RPCAPI):
         1.2 - A version that got in by mistake (without breaking anything).
         1.3 - Dummy version bump to mark start of having cinder-backup service
               decoupled from cinder-volume.
+
+        ... Mitaka supports messaging 1.3. Any changes to existing methods in
+        1.x after this point should be done so that they can handle version cap
+        set to 1.3.
+
+        2.0 - Remove 1.x compatibility
     """
 
     RPC_API_VERSION = '1.3'
     TOPIC = CONF.backup_topic
     BINARY = 'cinder-backup'
 
+    def _compat_ver(self, current, legacy):
+        if self.client.can_send_version(current):
+            return current
+        else:
+            return legacy
+
     def create_backup(self, ctxt, backup):
         LOG.debug("create_backup in rpcapi backup_id %s", backup.id)
-        cctxt = self.client.prepare(server=backup.host, version='1.1')
+        version = self._compat_ver('2.0', '1.1')
+        cctxt = self.client.prepare(server=backup.host, version=version)
         cctxt.cast(ctxt, 'create_backup', backup=backup)
 
     def restore_backup(self, ctxt, volume_host, backup, volume_id):
         LOG.debug("restore_backup in rpcapi backup_id %s", backup.id)
-        cctxt = self.client.prepare(server=volume_host, version='1.1')
+        version = self._compat_ver('2.0', '1.1')
+        cctxt = self.client.prepare(server=volume_host, version=version)
         cctxt.cast(ctxt, 'restore_backup', backup=backup,
                    volume_id=volume_id)
 
     def delete_backup(self, ctxt, backup):
         LOG.debug("delete_backup  rpcapi backup_id %s", backup.id)
-        cctxt = self.client.prepare(server=backup.host, version='1.1')
+        version = self._compat_ver('2.0', '1.1')
+        cctxt = self.client.prepare(server=backup.host, version=version)
         cctxt.cast(ctxt, 'delete_backup', backup=backup)
 
     def export_record(self, ctxt, backup):
@@ -65,7 +80,8 @@ class BackupAPI(rpc.RPCAPI):
                   "on host %(host)s.",
                   {'id': backup.id,
                    'host': backup.host})
-        cctxt = self.client.prepare(server=backup.host, version='1.1')
+        version = self._compat_ver('2.0', '1.1')
+        cctxt = self.client.prepare(server=backup.host, version=version)
         return cctxt.call(ctxt, 'export_record', backup=backup)
 
     def import_record(self,
@@ -80,7 +96,8 @@ class BackupAPI(rpc.RPCAPI):
                   {'id': backup.id,
                    'host': host,
                    'url': backup_url})
-        cctxt = self.client.prepare(server=host, version='1.1')
+        version = self._compat_ver('2.0', '1.1')
+        cctxt = self.client.prepare(server=host, version=version)
         cctxt.cast(ctxt, 'import_record',
                    backup=backup,
                    backup_service=backup_service,
@@ -92,11 +109,13 @@ class BackupAPI(rpc.RPCAPI):
                   "on host %(host)s.",
                   {'id': backup.id,
                    'host': backup.host})
-        cctxt = self.client.prepare(server=backup.host, version='1.1')
+        version = self._compat_ver('2.0', '1.1')
+        cctxt = self.client.prepare(server=backup.host, version=version)
         return cctxt.cast(ctxt, 'reset_status', backup=backup, status=status)
 
     def check_support_to_force_delete(self, ctxt, host):
         LOG.debug("Check if backup driver supports force delete "
                   "on host %(host)s.", {'host': host})
-        cctxt = self.client.prepare(server=host, version='1.1')
+        version = self._compat_ver('2.0', '1.1')
+        cctxt = self.client.prepare(server=host, version=version)
         return cctxt.call(ctxt, 'check_support_to_force_delete')
index d85c2710adb3978eb750c97473e72bf819256d25..13ccd3ca3e8769104ea2f6e8b2c717280caa4c74 100644 (file)
@@ -80,14 +80,32 @@ class BackupRpcAPITestCase(test.TestCase):
                     else:
                         self.assertEqual(expected_msg[kwarg], value)
 
-    def test_create_backup(self):
+    @mock.patch('oslo_messaging.RPCClient.can_send_version', return_value=True)
+    def test_create_backup(self, can_send_version):
+        self._test_backup_api('create_backup',
+                              rpc_method='cast',
+                              server=self.fake_backup_obj.host,
+                              backup=self.fake_backup_obj,
+                              version='2.0')
+
+        can_send_version.return_value = False
         self._test_backup_api('create_backup',
                               rpc_method='cast',
                               server=self.fake_backup_obj.host,
                               backup=self.fake_backup_obj,
                               version='1.1')
 
-    def test_restore_backup(self):
+    @mock.patch('oslo_messaging.RPCClient.can_send_version', return_value=True)
+    def test_restore_backup(self, can_send_version):
+        self._test_backup_api('restore_backup',
+                              rpc_method='cast',
+                              server='fake_volume_host',
+                              volume_host='fake_volume_host',
+                              backup=self.fake_backup_obj,
+                              volume_id='fake_volume_id',
+                              version='2.0')
+
+        can_send_version.return_value = False
         self._test_backup_api('restore_backup',
                               rpc_method='cast',
                               server='fake_volume_host',
@@ -96,21 +114,49 @@ class BackupRpcAPITestCase(test.TestCase):
                               volume_id=fake.volume_id,
                               version='1.1')
 
-    def test_delete_backup(self):
+    @mock.patch('oslo_messaging.RPCClient.can_send_version', return_value=True)
+    def test_delete_backup(self, can_send_version):
+        self._test_backup_api('delete_backup',
+                              rpc_method='cast',
+                              server=self.fake_backup_obj.host,
+                              backup=self.fake_backup_obj,
+                              version='2.0')
+
+        can_send_version.return_value = False
         self._test_backup_api('delete_backup',
                               rpc_method='cast',
                               server=self.fake_backup_obj.host,
                               backup=self.fake_backup_obj,
                               version='1.1')
 
-    def test_export_record(self):
+    @mock.patch('oslo_messaging.RPCClient.can_send_version', return_value=True)
+    def test_export_record(self, can_send_version):
+        self._test_backup_api('export_record',
+                              rpc_method='call',
+                              server=self.fake_backup_obj.host,
+                              backup=self.fake_backup_obj,
+                              version='2.0')
+
+        can_send_version.return_value = False
         self._test_backup_api('export_record',
                               rpc_method='call',
                               server=self.fake_backup_obj.host,
                               backup=self.fake_backup_obj,
                               version='1.1')
 
-    def test_import_record(self):
+    @mock.patch('oslo_messaging.RPCClient.can_send_version', return_value=True)
+    def test_import_record(self, can_send_version):
+        self._test_backup_api('import_record',
+                              rpc_method='cast',
+                              server='fake_volume_host',
+                              host='fake_volume_host',
+                              backup=self.fake_backup_obj,
+                              backup_service='fake_service',
+                              backup_url='fake_url',
+                              backup_hosts=['fake_host1', 'fake_host2'],
+                              version='2.0')
+
+        can_send_version.return_value = False
         self._test_backup_api('import_record',
                               rpc_method='cast',
                               server='fake_volume_host',
@@ -121,10 +167,34 @@ class BackupRpcAPITestCase(test.TestCase):
                               backup_hosts=['fake_host1', 'fake_host2'],
                               version='1.1')
 
-    def test_reset_status(self):
+    @mock.patch('oslo_messaging.RPCClient.can_send_version', return_value=True)
+    def test_reset_status(self, can_send_version):
+        self._test_backup_api('reset_status',
+                              rpc_method='cast',
+                              server=self.fake_backup_obj.host,
+                              backup=self.fake_backup_obj,
+                              status='error',
+                              version='2.0')
+
+        can_send_version.return_value = False
         self._test_backup_api('reset_status',
                               rpc_method='cast',
                               server=self.fake_backup_obj.host,
                               backup=self.fake_backup_obj,
                               status='error',
                               version='1.1')
+
+    @mock.patch('oslo_messaging.RPCClient.can_send_version', return_value=True)
+    def test_check_support_to_force_delete(self, can_send_version):
+        self._test_backup_api('check_support_to_force_delete',
+                              rpc_method='call',
+                              server='fake_volume_host',
+                              host='fake_volume_host',
+                              version='2.0')
+
+        can_send_version.return_value = False
+        self._test_backup_api('check_support_to_force_delete',
+                              rpc_method='call',
+                              server='fake_volume_host',
+                              host='fake_volume_host',
+                              version='1.1')