diff --git a/nova/compute/manager.py b/nova/compute/manager.py index a78d0fe7d9..ae9be994da 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -5003,8 +5003,13 @@ class ComputeManager(manager.Manager): migrate_data_obj.LiveMigrateData.detect_implementation( dest_check_data) dest_check_data.is_volume_backed = is_volume_backed - block_device_info = self._get_instance_block_device_info( + try: + block_device_info = self._get_instance_block_device_info( ctxt, instance, refresh_conn_info=True) + except cinder_exception.ClientException as exc: + raise exception.MigrationPreCheckClientException( + reason=six.text_type(exc)) + result = self.driver.check_can_live_migrate_source(ctxt, instance, dest_check_data, block_device_info) diff --git a/nova/conductor/manager.py b/nova/conductor/manager.py index b63bcb34f3..77df46aad5 100644 --- a/nova/conductor/manager.py +++ b/nova/conductor/manager.py @@ -172,6 +172,7 @@ class ComputeTaskManager(base.Base): exception.HypervisorUnavailable, exception.InstanceInvalidState, exception.MigrationPreCheckError, + exception.MigrationPreCheckClientException, exception.LiveMigrationWithOldNovaNotSupported, exception.UnsupportedPolicyException) def migrate_server(self, context, instance, scheduler_hint, live, rebuild, @@ -319,6 +320,7 @@ class ComputeTaskManager(base.Base): exception.HypervisorUnavailable, exception.InstanceInvalidState, exception.MigrationPreCheckError, + exception.MigrationPreCheckClientException, exception.LiveMigrationWithOldNovaNotSupported, exception.MigrationSchedulerRPCError) as ex: with excutils.save_and_reraise_exception(): diff --git a/nova/exception.py b/nova/exception.py index a427502145..b9dee4a9bf 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -1339,6 +1339,10 @@ class MigrationPreCheckError(MigrationError): msg_fmt = _("Migration pre-check error: %(reason)s") +class MigrationPreCheckClientException(MigrationError): + msg_fmt = _("Client exception during Migration Pre check: %(reason)s") + + class MigrationSchedulerRPCError(MigrationError): msg_fmt = _("Migration select destinations error: %(reason)s") diff --git a/nova/tests/unit/api/openstack/compute/test_migrate_server.py b/nova/tests/unit/api/openstack/compute/test_migrate_server.py index 923a8cb5fe..f56f8ab9c9 100644 --- a/nova/tests/unit/api/openstack/compute/test_migrate_server.py +++ b/nova/tests/unit/api/openstack/compute/test_migrate_server.py @@ -262,6 +262,12 @@ class MigrateServerTestsV21(admin_only_action_common.CommonTests): self._test_migrate_live_failed_with_exception( exception.MigrationPreCheckError(reason='')) + def test_migrate_live_migration_precheck_client_exception(self): + self._test_migrate_live_failed_with_exception( + exception.MigrationPreCheckClientException(reason=''), + expected_exc=webob.exc.HTTPInternalServerError, + check_response=False) + def test_migrate_live_migration_with_unexpected_error(self): self._test_migrate_live_failed_with_exception( exception.MigrationError(reason=''), diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index ab6278c6d1..163ac11dc5 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -1886,6 +1886,32 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): instance.uuid) self.assertTrue(dest_check_data.is_volume_backed) + def test_can_live_migrate_source_for_cinder_client_exception(self): + + is_volume_backed = 'volume_backed' + dest_check_data = migrate_data_obj.LiveMigrateData() + db_instance = fake_instance.fake_db_instance() + instance = objects.Instance._from_db_object( + self.context, objects.Instance(), db_instance) + + @mock.patch.object(compute_utils, 'EventReporter') + @mock.patch.object(compute_utils, 'add_instance_fault_from_exc') + @mock.patch.object(self.compute.compute_api, + 'is_volume_backed_instance') + @mock.patch.object(self.compute, + '_get_instance_block_device_info') + def do_test(mock_block_info, mock_volume_backed, + mock_inst_fault, mock_event): + mock_volume_backed.return_value = is_volume_backed + mock_block_info.side_effect = cinder_exception.ClientException( + 'test', 'test') + + self.assertRaises(exception.MigrationPreCheckClientException, + self.compute.check_can_live_migrate_source, + self.context, instance, + dest_check_data) + do_test() + @mock.patch.object(compute_utils, 'EventReporter') def _test_check_can_live_migrate_destination(self, event_mock, do_raise=False): diff --git a/nova/tests/unit/conductor/test_conductor.py b/nova/tests/unit/conductor/test_conductor.py index 58c68bf647..e57f9b85b8 100644 --- a/nova/tests/unit/conductor/test_conductor.py +++ b/nova/tests/unit/conductor/test_conductor.py @@ -1306,6 +1306,7 @@ class ConductorTaskTestCase(_BaseTaskTestCase, test_compute.BaseTestCase): exc.HypervisorUnavailable(host='dummy'), exc.LiveMigrationWithOldNovaNotSupported(), exc.MigrationPreCheckError(reason='dummy'), + exc.MigrationPreCheckClientException(reason='dummy'), exc.InvalidSharedStorage(path='dummy', reason='dummy'), exc.NoValidHost(reason='dummy'), exc.ComputeServiceUnavailable(host='dummy'),