Merge "api: Log os-resetState as an instance action"

This commit is contained in:
Zuul 2021-01-25 11:44:15 +00:00 committed by Gerrit Code Review
commit 87d05fbae2
4 changed files with 44 additions and 2 deletions
nova
api/openstack/compute
compute
tests/unit/api/openstack/compute
releasenotes/notes

@ -19,8 +19,10 @@ from nova.api.openstack.compute.schemas import reset_server_state
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api import validation from nova.api import validation
from nova.compute import api as compute from nova.compute import api as compute
from nova.compute import instance_actions
from nova.compute import vm_states from nova.compute import vm_states
from nova import exception from nova import exception
from nova import objects
from nova.policies import admin_actions as aa_policies from nova.policies import admin_actions as aa_policies
# States usable in resetState action # States usable in resetState action
@ -65,9 +67,14 @@ class AdminActionsController(wsgi.Controller):
context.can(aa_policies.POLICY_ROOT % 'reset_state', context.can(aa_policies.POLICY_ROOT % 'reset_state',
target={'project_id': instance.project_id}) 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 # Identify the desired state from the body
state = state_map[body["os-resetState"]["state"]] state = state_map[body["os-resetState"]["state"]]
instance.vm_state = state instance.vm_state = state
instance.task_state = None instance.task_state = None
instance.save(admin_state_reset=True) instance.save(admin_state_reset=True)
instance_action.finish()

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

@ -18,6 +18,7 @@ import webob
from nova.api.openstack.compute import admin_actions \ from nova.api.openstack.compute import admin_actions \
as admin_actions_v21 as admin_actions_v21
from nova.compute import instance_actions
from nova.compute import vm_states from nova.compute import vm_states
from nova import exception from nova import exception
from nova import objects from nova import objects
@ -59,18 +60,27 @@ class ResetStateTestsV21(test.NoDBTestCase):
def _get_request(self): def _get_request(self):
return fakes.HTTPRequest.blank('') return fakes.HTTPRequest.blank('')
@mock.patch(
'nova.objects.instance_action.InstanceAction.action_start',
new=mock.Mock(spec=objects.InstanceAction))
def test_no_state(self): def test_no_state(self):
self.assertRaises(self.bad_request, self.assertRaises(self.bad_request,
self.admin_api._reset_state, self.admin_api._reset_state,
self.request, self.uuid, self.request, self.uuid,
body={"os-resetState": None}) body={"os-resetState": None})
@mock.patch(
'nova.objects.instance_action.InstanceAction.action_start',
new=mock.Mock(spec=objects.InstanceAction))
def test_bad_state(self): def test_bad_state(self):
self.assertRaises(self.bad_request, self.assertRaises(self.bad_request,
self.admin_api._reset_state, self.admin_api._reset_state,
self.request, self.uuid, self.request, self.uuid,
body={"os-resetState": {"state": "spam"}}) 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): def test_no_instance(self):
self.compute_api.get = mock.MagicMock( self.compute_api.get = mock.MagicMock(
side_effect=exception.InstanceNotFound(instance_id='inst_ud')) side_effect=exception.InstanceNotFound(instance_id='inst_ud'))
@ -84,11 +94,14 @@ class ResetStateTestsV21(test.NoDBTestCase):
self.context, self.uuid, expected_attrs=None, self.context, self.uuid, expected_attrs=None,
cell_down_support=False) 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) expected = dict(vm_state=vm_states.ACTIVE, task_state=None)
self.instance.save = mock.MagicMock( self.instance.save = mock.MagicMock(
side_effect=lambda **kw: self._check_instance_state(expected)) side_effect=lambda **kw: self._check_instance_state(expected))
self.compute_api.get = mock.MagicMock(return_value=self.instance) 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"}} body = {"os-resetState": {"state": "active"}}
result = self.admin_api._reset_state(self.request, self.uuid, result = self.admin_api._reset_state(self.request, self.uuid,
@ -107,11 +120,18 @@ class ResetStateTestsV21(test.NoDBTestCase):
cell_down_support=False) cell_down_support=False)
self.instance.save.assert_called_once_with(admin_state_reset=True) 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) expected = dict(vm_state=vm_states.ERROR, task_state=None)
self.instance.save = mock.MagicMock( self.instance.save = mock.MagicMock(
side_effect=lambda **kw: self._check_instance_state(expected)) side_effect=lambda **kw: self._check_instance_state(expected))
self.compute_api.get = mock.MagicMock(return_value=self.instance) 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"}} body = {"os-resetState": {"state": "error"}}
result = self.admin_api._reset_state(self.request, self.uuid, 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, self.context, self.instance.uuid, expected_attrs=None,
cell_down_support=False) cell_down_support=False)
self.instance.save.assert_called_once_with(admin_state_reset=True) 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()

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