From c6ffec00037fd0def2f072dcdc3619aa9437b32b Mon Sep 17 00:00:00 2001 From: Timofey Durakov Date: Thu, 3 Dec 2015 12:48:23 +0300 Subject: [PATCH] Handle SetAdminPasswdNotSupported raised by libvirt driver When admin-password operation is not supported by libvirt qemu/kvm SetAdminPasswdNotSupported exception is raised, compute manager doesn't handle it, which cause instance state to be set to error. Closes-bug: #1522338 Change-Id: Ic63e8f723ff19dfa63199e77ea76680bff5a123b --- nova/api/openstack/compute/admin_password.py | 4 +++- nova/compute/manager.py | 15 +++++++++++++++ nova/exception.py | 8 +++++++- .../openstack/compute/test_admin_password.py | 19 +++++++++++++++++++ nova/tests/unit/compute/test_compute_mgr.py | 16 +++++++++++++++- 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/nova/api/openstack/compute/admin_password.py b/nova/api/openstack/compute/admin_password.py index ed1bd2050a..509ccbf108 100644 --- a/nova/api/openstack/compute/admin_password.py +++ b/nova/api/openstack/compute/admin_password.py @@ -51,7 +51,9 @@ class AdminPasswordController(wsgi.Controller): self.compute_api.set_admin_password(context, instance, password) except exception.InstanceUnknownCell as e: raise exc.HTTPNotFound(explanation=e.format_message()) - except exception.InstancePasswordSetFailed as e: + except (exception.InstancePasswordSetFailed, + exception.SetAdminPasswdNotSupported, + exception.InstanceAgentNotEnabled) as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as e: raise common.raise_http_conflict_for_instance_invalid_state( diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 5a5282434b..ef0427a7a9 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -3126,6 +3126,21 @@ class ComputeManager(manager.Manager): instance.task_state = None instance.save( expected_task_state=task_states.UPDATING_PASSWORD) + except exception.InstanceAgentNotEnabled: + with excutils.save_and_reraise_exception(): + LOG.debug('Guest agent is not enabled for the instance.', + instance=instance) + instance.task_state = None + instance.save( + expected_task_state=task_states.UPDATING_PASSWORD) + except exception.SetAdminPasswdNotSupported: + with excutils.save_and_reraise_exception(): + LOG.info(_LI('set_admin_password is not supported ' + 'by this driver or guest instance.'), + instance=instance) + instance.task_state = None + instance.save( + expected_task_state=task_states.UPDATING_PASSWORD) except NotImplementedError: LOG.warning(_LW('set_admin_password is not implemented ' 'by this driver or guest instance.'), diff --git a/nova/exception.py b/nova/exception.py index 63d80a9c07..0d5de9272c 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -1998,12 +1998,18 @@ class InstanceQuiesceNotSupported(Invalid): msg_fmt = _('Quiescing is not supported in instance %(instance_id)s') -class QemuGuestAgentNotEnabled(Invalid): +class InstanceAgentNotEnabled(Invalid): + msg_fmt = _('Guest agent is not enabled for the instance') + safe = True + + +class QemuGuestAgentNotEnabled(InstanceAgentNotEnabled): msg_fmt = _('QEMU guest agent is not enabled') class SetAdminPasswdNotSupported(Invalid): msg_fmt = _('Set admin password is not supported') + safe = True class MemoryPageSizeInvalid(Invalid): diff --git a/nova/tests/unit/api/openstack/compute/test_admin_password.py b/nova/tests/unit/api/openstack/compute/test_admin_password.py index 7c30f2edf1..0e0140ddb6 100644 --- a/nova/tests/unit/api/openstack/compute/test_admin_password.py +++ b/nova/tests/unit/api/openstack/compute/test_admin_password.py @@ -87,6 +87,25 @@ class AdminPasswordTestV21(test.NoDBTestCase): self._get_action(), self.fake_req, '1', body=body) + @mock.patch('nova.compute.api.API.set_admin_password', + side_effect=exception.SetAdminPasswdNotSupported(instance="1", + reason='')) + def test_change_password_not_supported(self, mock_set_admin_password): + body = {'changePassword': {'adminPass': 'test'}} + self.assertRaises(webob.exc.HTTPConflict, + self._get_action(), + self.fake_req, '1', body=body) + + @mock.patch('nova.compute.api.API.set_admin_password', + side_effect=exception.InstanceAgentNotEnabled(instance="1", + reason='')) + def test_change_password_guest_agent_disabled(self, + mock_set_admin_password): + body = {'changePassword': {'adminPass': 'test'}} + self.assertRaises(webob.exc.HTTPConflict, + self._get_action(), + self.fake_req, '1', body=body) + def test_change_password_without_admin_password(self): body = {'changPassword': {}} self.assertRaises(self.validiation_error, diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index 94daaad8ed..b1fd71ac1a 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -2626,7 +2626,9 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): instance=instance, new_pass=None) - if expected_exception == NotImplementedError: + if (expected_exception == exception.SetAdminPasswdNotSupported or + expected_exception == exception.InstanceAgentNotEnabled or + expected_exception == NotImplementedError): instance_save_mock.assert_called_once_with( expected_task_state=task_states.UPDATING_PASSWORD) else: @@ -2659,6 +2661,18 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): self._do_test_set_admin_password_driver_error( exc, vm_states.ACTIVE, None, expected_exception) + def test_set_admin_password_driver_not_supported(self): + exc = exception.SetAdminPasswdNotSupported() + expected_exception = exception.SetAdminPasswdNotSupported + self._do_test_set_admin_password_driver_error( + exc, vm_states.ACTIVE, None, expected_exception) + + def test_set_admin_password_guest_agent_no_enabled(self): + exc = exception.QemuGuestAgentNotEnabled() + expected_exception = exception.InstanceAgentNotEnabled + self._do_test_set_admin_password_driver_error( + exc, vm_states.ACTIVE, None, expected_exception) + def test_destroy_evacuated_instances(self): our_host = self.compute.host instance_1 = objects.Instance(self.context)