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 534b4f3895)
This commit is contained in:
Lee Yarwood 2021-01-15 10:58:52 +00:00
parent d3968f17df
commit 3d84097eab
4 changed files with 44 additions and 2 deletions

View File

@ -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()

View File

@ -70,3 +70,4 @@ LOCK = 'lock'
UNLOCK = 'unlock'
BACKUP = 'createBackup'
CREATE_IMAGE = 'createImage'
RESET_STATE = 'resetState'

View File

@ -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()

View File

@ -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