Merge "Allow status_message updates for actions in SKIPPED state"
This commit is contained in:
@@ -192,6 +192,9 @@ action_state:
|
||||
action_status_message:
|
||||
description: |
|
||||
Message with additional information about the Action state.
|
||||
This field can be set when transitioning an action to SKIPPED state,
|
||||
or updated for actions that are already in SKIPPED state to provide
|
||||
more detailed explanations, fix typos, or expand on initial reasons.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
|
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"op": "replace",
|
||||
"value": "Action skipped due to scheduled maintenance window",
|
||||
"path": "/status_message"
|
||||
}
|
||||
]
|
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"state": "SKIPPED",
|
||||
"description": "Migrate instance to another compute node",
|
||||
"parents": [
|
||||
"b4529294-1de6-4302-b57a-9b5d5dc363c6"
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://controller:9322/v1/actions/54acc7a0-91b0-46ea-a5f7-4ae2b9df0b0a"
|
||||
},
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": "http://controller:9322/actions/54acc7a0-91b0-46ea-a5f7-4ae2b9df0b0a"
|
||||
}
|
||||
],
|
||||
"action_plan_uuid": "4cbc4ede-0d25-481b-b86e-998dbbd4f8bf",
|
||||
"uuid": "54acc7a0-91b0-46ea-a5f7-4ae2b9df0b0a",
|
||||
"deleted_at": null,
|
||||
"updated_at": "2018-04-10T12:20:15.123456+00:00",
|
||||
"input_parameters": {
|
||||
"migration_type": "live",
|
||||
"destination_node": "compute-2",
|
||||
"resource_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
|
||||
},
|
||||
"action_type": "migrate",
|
||||
"created_at": "2018-04-10T11:59:12.725147+00:00",
|
||||
"status_message": "Action skipped by user. Reason: Action skipped due to scheduled maintenance window"
|
||||
}
|
@@ -210,4 +210,53 @@ Response
|
||||
**Example JSON representation of a skipped Action:**
|
||||
|
||||
.. literalinclude:: samples/action-skip-response.json
|
||||
:language: javascript
|
||||
|
||||
Update Action Status Message
|
||||
============================
|
||||
|
||||
.. rest_method:: PATCH /v1/actions/{action_ident}
|
||||
|
||||
Updates the status_message of an Action that is already in SKIPPED state.
|
||||
|
||||
.. note::
|
||||
The status_message field can only be updated for Actions that are currently
|
||||
in SKIPPED state. This allows administrators to fix typos, provide more
|
||||
detailed explanations, or expand on reasons that were initially omitted.
|
||||
This operation requires API microversion 1.5 or later.
|
||||
|
||||
Normal response codes: 200
|
||||
|
||||
Error codes: 400,404,403,409
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- action_ident: action_ident
|
||||
|
||||
**Example status_message update request for a SKIPPED action:**
|
||||
|
||||
.. literalinclude:: samples/action-update-status-message-request.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- uuid: uuid
|
||||
- action_type: action_type
|
||||
- state: action_state
|
||||
- action_plan_uuid: action_action_plan_uuid
|
||||
- parents: action_parents
|
||||
- description: action_description
|
||||
- input_parameters: action_input_parameters
|
||||
- links: links
|
||||
- status_message: action_status_message
|
||||
|
||||
**Example JSON representation of an Action with updated status_message:**
|
||||
|
||||
.. literalinclude:: samples/action-update-status-message-response.json
|
||||
:language: javascript
|
@@ -0,0 +1,11 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixed action status_message update restrictions to allow updates when
|
||||
action is in SKIPPED state. Previously, users could only update the
|
||||
status_message when initially changing the action state to SKIPPED.
|
||||
Now users can update the status_message field at any time while the
|
||||
action remains in SKIPPED state, enabling them to fix typos, provide
|
||||
more detailed explanations, or expand on reasons that were initially
|
||||
omitted. For more details, see the bug report:
|
||||
https://bugs.launchpad.net/watcher/+bug/2121601
|
@@ -44,4 +44,7 @@ with ``event`` type.
|
||||
---
|
||||
Added support for SKIPPED actions status via PATCH support for Actions API.
|
||||
This feature also introduces the ``status_message`` field to audits, actions
|
||||
and action plans.
|
||||
and action plans. The ``status_message`` field can be set when transitioning
|
||||
an action to SKIPPED state, and can also be updated for actions that are
|
||||
already in SKIPPED state, allowing administrators to fix typos, provide more
|
||||
detailed explanations, or expand on reasons that were initially omitted.
|
||||
|
@@ -439,15 +439,18 @@ class ActionsController(rest.RestController):
|
||||
ap_state=action_plan.state))
|
||||
|
||||
status_message = _("Action skipped by user.")
|
||||
# status_message update only allowed with status update
|
||||
# status_message update only allowed with status update or when
|
||||
# already SKIPPED
|
||||
# NOTE(dviroel): status_message is an exposed field.
|
||||
if action.status_message != action_to_update.status_message:
|
||||
if action.state == action_to_update.state:
|
||||
if (action.state == action_to_update.state and
|
||||
action_to_update.state != objects.action.State.SKIPPED):
|
||||
error_message = _(
|
||||
"status_message update only allowed with state change")
|
||||
raise exception.PatchError(
|
||||
"status_message update only allowed when action state "
|
||||
"is SKIPPED")
|
||||
raise exception.Conflict(
|
||||
patch=patch,
|
||||
reason=error_message)
|
||||
message=error_message)
|
||||
else:
|
||||
status_message = (_("%(status_message)s Reason: %(reason)s")
|
||||
% dict(status_message=status_message,
|
||||
|
@@ -656,17 +656,17 @@ class TestPatchAction(api_base.FunctionalTest):
|
||||
response.json['error_message'])
|
||||
|
||||
def test_patch_action_status_message_not_allowed(self):
|
||||
"""Test that status_message cannot be patched directly"""
|
||||
"""Test status_message cannot be patched directly when not SKIPPED"""
|
||||
response = self.patch_json(
|
||||
'/actions/%s' % self.action.uuid,
|
||||
[{'path': '/status_message', 'value': 'test message',
|
||||
'op': 'replace'}],
|
||||
headers={'OpenStack-API-Version': 'infra-optim 1.5'},
|
||||
expect_errors=True)
|
||||
self.assertEqual(HTTPStatus.BAD_REQUEST, response.status_int)
|
||||
self.assertEqual(HTTPStatus.CONFLICT, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertIn("status_message update only allowed with state change",
|
||||
response.json['error_message'])
|
||||
self.assertIn("status_message update only allowed when action state "
|
||||
"is SKIPPED", response.json['error_message'])
|
||||
self.assertIsNone(self.action.status_message)
|
||||
|
||||
def test_patch_action_one_allowed_one_not_allowed(self):
|
||||
@@ -685,6 +685,32 @@ class TestPatchAction(api_base.FunctionalTest):
|
||||
"can not be updated", response.json['error_message'])
|
||||
self.assertIsNone(self.action.status_message)
|
||||
|
||||
def test_patch_action_status_message_allowed_when_skipped(self):
|
||||
"""Test that status_message can be updated when action is SKIPPED"""
|
||||
# First transition to SKIPPED state
|
||||
new_state = objects.action.State.SKIPPED
|
||||
response = self.patch_json(
|
||||
'/actions/%s' % self.action.uuid,
|
||||
[{'path': '/state', 'value': new_state, 'op': 'replace'},
|
||||
{'path': '/status_message', 'value': 'initial message',
|
||||
'op': 'replace'}],
|
||||
headers={'OpenStack-API-Version': 'infra-optim 1.5'})
|
||||
self.assertEqual(HTTPStatus.OK, response.status_int)
|
||||
self.assertEqual(new_state, response.json['state'])
|
||||
|
||||
# Now update status_message while in SKIPPED state
|
||||
response = self.patch_json(
|
||||
'/actions/%s' % self.action.uuid,
|
||||
[{'path': '/status_message', 'value': 'updated message',
|
||||
'op': 'replace'}],
|
||||
headers={'OpenStack-API-Version': 'infra-optim 1.5'})
|
||||
self.assertEqual(HTTPStatus.OK, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(new_state, response.json['state'])
|
||||
self.assertEqual(
|
||||
'Action skipped by user. Reason: updated message',
|
||||
response.json['status_message'])
|
||||
|
||||
|
||||
class TestActionPolicyEnforcement(api_base.FunctionalTest):
|
||||
|
||||
|
Reference in New Issue
Block a user