From 3d84097eab617d8e29754160c2f6eb6e1a024f76 Mon Sep 17 00:00:00 2001 From: Lee Yarwood Date: Fri, 15 Jan 2021 10:58:52 +0000 Subject: [PATCH] api: Log os-resetState as an instance action It appears this was missed as this action never hits the compute API and is fully handled within the API itself. This change simply records an instance action directly in the API for this admin action providing a breadcrumb to operators and users. Closes-Bug: #1911924 Change-Id: Ifd9657f3357bc39cb904caa65168d38def8c9184 (cherry picked from commit 534b4f38958af2fbf4392e445ddb1b2bad4179ed) --- nova/api/openstack/compute/admin_actions.py | 7 +++++ nova/compute/instance_actions.py | 1 + .../compute/test_server_reset_state.py | 28 +++++++++++++++++-- .../notes/bug-1911924-6e93d8a5038d18c1.yaml | 10 +++++++ 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/bug-1911924-6e93d8a5038d18c1.yaml diff --git a/nova/api/openstack/compute/admin_actions.py b/nova/api/openstack/compute/admin_actions.py index 6de6956bcfde..f6df60e78c92 100644 --- a/nova/api/openstack/compute/admin_actions.py +++ b/nova/api/openstack/compute/admin_actions.py @@ -19,8 +19,10 @@ from nova.api.openstack.compute.schemas import reset_server_state from nova.api.openstack import wsgi from nova.api import validation from nova.compute import api as compute +from nova.compute import instance_actions from nova.compute import vm_states from nova import exception +from nova import objects from nova.policies import admin_actions as aa_policies # States usable in resetState action @@ -73,9 +75,14 @@ class AdminActionsController(wsgi.Controller): context.can(aa_policies.POLICY_ROOT % 'reset_state', target={'project_id': instance.project_id}) + # Log os-resetState as an instance action + instance_action = objects.InstanceAction.action_start( + context, instance.uuid, instance_actions.RESET_STATE) + # Identify the desired state from the body state = state_map[body["os-resetState"]["state"]] instance.vm_state = state instance.task_state = None instance.save(admin_state_reset=True) + instance_action.finish() diff --git a/nova/compute/instance_actions.py b/nova/compute/instance_actions.py index e6e51c95e46f..10899750495a 100644 --- a/nova/compute/instance_actions.py +++ b/nova/compute/instance_actions.py @@ -70,3 +70,4 @@ LOCK = 'lock' UNLOCK = 'unlock' BACKUP = 'createBackup' CREATE_IMAGE = 'createImage' +RESET_STATE = 'resetState' diff --git a/nova/tests/unit/api/openstack/compute/test_server_reset_state.py b/nova/tests/unit/api/openstack/compute/test_server_reset_state.py index 591ab493a466..3462cf21acc5 100644 --- a/nova/tests/unit/api/openstack/compute/test_server_reset_state.py +++ b/nova/tests/unit/api/openstack/compute/test_server_reset_state.py @@ -18,6 +18,7 @@ import webob from nova.api.openstack.compute import admin_actions \ as admin_actions_v21 +from nova.compute import instance_actions from nova.compute import vm_states from nova import exception from nova import objects @@ -59,18 +60,27 @@ class ResetStateTestsV21(test.NoDBTestCase): def _get_request(self): return fakes.HTTPRequest.blank('') + @mock.patch( + 'nova.objects.instance_action.InstanceAction.action_start', + new=mock.Mock(spec=objects.InstanceAction)) def test_no_state(self): self.assertRaises(self.bad_request, self.admin_api._reset_state, self.request, self.uuid, body={"os-resetState": None}) + @mock.patch( + 'nova.objects.instance_action.InstanceAction.action_start', + new=mock.Mock(spec=objects.InstanceAction)) def test_bad_state(self): self.assertRaises(self.bad_request, self.admin_api._reset_state, self.request, self.uuid, body={"os-resetState": {"state": "spam"}}) + @mock.patch( + 'nova.objects.instance_action.InstanceAction.action_start', + new=mock.Mock(spec=objects.InstanceAction)) def test_no_instance(self): self.compute_api.get = mock.MagicMock( side_effect=exception.InstanceNotFound(instance_id='inst_ud')) @@ -84,11 +94,14 @@ class ResetStateTestsV21(test.NoDBTestCase): self.context, self.uuid, expected_attrs=None, cell_down_support=False) - def test_reset_active(self): + @mock.patch('nova.objects.instance_action.InstanceAction.action_start') + def test_reset_active(self, mock_instance_action_start): expected = dict(vm_state=vm_states.ACTIVE, task_state=None) self.instance.save = mock.MagicMock( side_effect=lambda **kw: self._check_instance_state(expected)) self.compute_api.get = mock.MagicMock(return_value=self.instance) + mock_instance_action = mock.Mock(spec=objects.InstanceAction) + mock_instance_action_start.return_value = mock_instance_action body = {"os-resetState": {"state": "active"}} result = self.admin_api._reset_state(self.request, self.uuid, @@ -107,11 +120,18 @@ class ResetStateTestsV21(test.NoDBTestCase): cell_down_support=False) self.instance.save.assert_called_once_with(admin_state_reset=True) - def test_reset_error(self): + mock_instance_action_start.assert_called_once_with( + self.context, self.instance.uuid, instance_actions.RESET_STATE) + mock_instance_action.finish.assert_called_once() + + @mock.patch('nova.objects.instance_action.InstanceAction.action_start') + def test_reset_error(self, mock_instance_action_start): expected = dict(vm_state=vm_states.ERROR, task_state=None) self.instance.save = mock.MagicMock( side_effect=lambda **kw: self._check_instance_state(expected)) self.compute_api.get = mock.MagicMock(return_value=self.instance) + mock_instance_action = mock.Mock(spec=objects.InstanceAction) + mock_instance_action_start.return_value = mock_instance_action body = {"os-resetState": {"state": "error"}} result = self.admin_api._reset_state(self.request, self.uuid, @@ -129,3 +149,7 @@ class ResetStateTestsV21(test.NoDBTestCase): self.context, self.instance.uuid, expected_attrs=None, cell_down_support=False) self.instance.save.assert_called_once_with(admin_state_reset=True) + + mock_instance_action_start.assert_called_once_with( + self.context, self.instance.uuid, instance_actions.RESET_STATE) + mock_instance_action.finish.assert_called_once() diff --git a/releasenotes/notes/bug-1911924-6e93d8a5038d18c1.yaml b/releasenotes/notes/bug-1911924-6e93d8a5038d18c1.yaml new file mode 100644 index 000000000000..ff27f936aa6b --- /dev/null +++ b/releasenotes/notes/bug-1911924-6e93d8a5038d18c1.yaml @@ -0,0 +1,10 @@ +--- +fixes: + - | + The `os-resetState`_ API will now log an instance action when called. The + resulting instance action being visable via the `os-instance-actions`_ API + to users and admins, resolving `bug 1911924`_. + + .. _bug 1911924: https://launchpad.net/bugs/1911924 + .. _os-instance-actions: https://docs.openstack.org/api-ref/compute/?expanded=reset-server-state-os-resetstate-action-detail,list-actions-for-server-detail + .. _os-resetState: https://docs.openstack.org/api-ref/compute/?expanded=reset-server-state-os-resetstate-action-detail