From 01b58781292ca8da97019594b6dc155817c46ca1 Mon Sep 17 00:00:00 2001 From: rabi Date: Mon, 7 Aug 2017 15:05:50 +0530 Subject: [PATCH] Add REST api support for cancel without rollback We already have REST api support for cancelling a UPDATE_IN_PROGRESS stack with rollback. This adds a new action 'cancel_without_rollback' to allow for canceling a create/update in_progress stack without rollback. APIImpact Change-Id: I6c6ffa0502ab8745cfb2f9c5ef263f1e02dfc4ca Closes-Bug: #1709041 --- api-ref/source/v1/parameters.yaml | 7 +++ ...ction-cancel-without-rollback-request.json | 3 ++ api-ref/source/v1/stack-actions.inc | 49 +++++++++++++++++++ heat/api/openstack/v1/actions.py | 12 +++-- heat/engine/service.py | 6 ++- heat/tests/api/openstack_v1/test_actions.py | 31 +++++++----- ...cel_without_rollback-e5d978a60d9baf45.yaml | 3 ++ 7 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 api-ref/source/v1/samples/stack-action-cancel-without-rollback-request.json create mode 100644 releasenotes/notes/cancel_without_rollback-e5d978a60d9baf45.yaml diff --git a/api-ref/source/v1/parameters.yaml b/api-ref/source/v1/parameters.yaml index 5667839deb..7722b0f441 100644 --- a/api-ref/source/v1/parameters.yaml +++ b/api-ref/source/v1/parameters.yaml @@ -431,6 +431,13 @@ cancel_update: in: body required: true type: string +cancel_without_rollback: + description: | + Specify the ``cancel_without_rollback`` action in + the request body.. + in: body + required: true + type: string capabilities: description: | List of stack capabilities for stack. diff --git a/api-ref/source/v1/samples/stack-action-cancel-without-rollback-request.json b/api-ref/source/v1/samples/stack-action-cancel-without-rollback-request.json new file mode 100644 index 0000000000..63ce670f5a --- /dev/null +++ b/api-ref/source/v1/samples/stack-action-cancel-without-rollback-request.json @@ -0,0 +1,3 @@ +{ + "cancel_without_rollback": null +} diff --git a/api-ref/source/v1/stack-actions.inc b/api-ref/source/v1/stack-actions.inc index 0efab0b863..bf6ad2d99f 100644 --- a/api-ref/source/v1/stack-actions.inc +++ b/api-ref/source/v1/stack-actions.inc @@ -154,6 +154,55 @@ Response Example This operation does not return a response body. +Cancel stack create/update without rollback +=========================================== + +.. rest_method:: POST /v1/{tenant_id}/stacks/{stack_name}/{stack_id}/actions + +Cancels a currently running create/update of a stack without rollback. + +Response Codes +-------------- + +.. rest_status_code:: success status.yaml + + - 200 + +.. rest_status_code:: error status.yaml + + - 400 + - 401 + - 404 + +Request Parameters +------------------ + +.. rest_parameters:: parameters.yaml + + - tenant_id: tenant_id + - stack_name: stack_name_url + - stack_id: stack_id_url + - cancel_without_rollback: cancel_without_rollback + +Request Example +--------------- + +.. literalinclude:: samples/stack-action-cancel-without-rollback-request.json + :language: javascript + +Response Parameters +------------------- + +.. rest_parameters:: parameters.yaml + + - X-Openstack-Request-Id: request_id + +Response Example +---------------- + +This operation does not return a response body. + + Check stack resources ===================== diff --git a/heat/api/openstack/v1/actions.py b/heat/api/openstack/v1/actions.py index 5f002c2b31..fcc4a5236c 100644 --- a/heat/api/openstack/v1/actions.py +++ b/heat/api/openstack/v1/actions.py @@ -30,9 +30,11 @@ class ActionController(object): REQUEST_SCOPE = 'actions' ACTIONS = ( - SUSPEND, RESUME, CHECK, CANCEL_UPDATE + SUSPEND, RESUME, CHECK, + CANCEL_UPDATE, CANCEL_WITHOUT_ROLLBACK ) = ( - 'suspend', 'resume', 'check', 'cancel_update' + 'suspend', 'resume', 'check', + 'cancel_update', 'cancel_without_rollback' ) def __init__(self, options): @@ -64,7 +66,11 @@ class ActionController(object): elif ac == self.CHECK: self.rpc_client.stack_check(req.context, identity) elif ac == self.CANCEL_UPDATE: - self.rpc_client.stack_cancel_update(req.context, identity) + self.rpc_client.stack_cancel_update(req.context, identity, + cancel_with_rollback=True) + elif ac == self.CANCEL_WITHOUT_ROLLBACK: + self.rpc_client.stack_cancel_update(req.context, identity, + cancel_with_rollback=False) else: raise exc.HTTPInternalServerError(_("Unexpected action %s") % ac) diff --git a/heat/engine/service.py b/heat/engine/service.py index 4fc2130692..5c6e2eb41e 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -1151,10 +1151,12 @@ class EngineService(service.ServiceBase): db_stack = self._get_stack(cnxt, stack_identity) current_stack = parser.Stack.load(cnxt, stack=db_stack) - if cancel_with_rollback: # Commanded by user + + if cancel_with_rollback: allowed_actions = (current_stack.UPDATE,) - else: # Cancelled by parent stack + else: allowed_actions = (current_stack.UPDATE, current_stack.CREATE) + if not (current_stack.status == current_stack.IN_PROGRESS and current_stack.action in allowed_actions): state = '_'.join(current_stack.state) diff --git a/heat/tests/api/openstack_v1/test_actions.py b/heat/tests/api/openstack_v1/test_actions.py index 701f0cc693..cf97c594de 100644 --- a/heat/tests/api/openstack_v1/test_actions.py +++ b/heat/tests/api/openstack_v1/test_actions.py @@ -88,30 +88,35 @@ class ActionControllerTest(tools.ControllerTest, common.HeatTestCase): self.assertIsNone(result) self.m.VerifyAll() - def test_action_cancel_update(self, mock_enforce): + def _test_action_cancel_update(self, mock_enforce, with_rollback=True): self._mock_enforce_setup(mock_enforce, 'action', True) stack_identity = identifier.HeatIdentifier(self.tenant, 'wordpress', '1') - body = {'cancel_update': None} + if with_rollback: + body = {'cancel_update': None} + else: + body = {'cancel_without_rollback': None} req = self._post(stack_identity._tenant_path() + '/actions', data=json.dumps(body)) - self.m.StubOutWithMock(rpc_client.EngineClient, 'call') - rpc_client.EngineClient.call( - req.context, - ('stack_cancel_update', - {'stack_identity': stack_identity, - 'cancel_with_rollback': True}), - version='1.14' - ).AndReturn(None) - self.m.ReplayAll() - + client = self.patchobject(rpc_client.EngineClient, 'call') result = self.controller.action(req, tenant_id=self.tenant, stack_name=stack_identity.stack_name, stack_id=stack_identity.stack_id, body=body) self.assertIsNone(result) - self.m.VerifyAll() + client.assert_called_with( + req.context, + ('stack_cancel_update', + {'stack_identity': stack_identity, + 'cancel_with_rollback': with_rollback}), + version='1.14') + + def test_action_cancel_update(self, mock_enforce): + self._test_action_cancel_update(mock_enforce) + + def test_action_cancel_without_rollback(self, mock_enforce): + self._test_action_cancel_update(mock_enforce, False) def test_action_badaction(self, mock_enforce): self._mock_enforce_setup(mock_enforce, 'action', True) diff --git a/releasenotes/notes/cancel_without_rollback-e5d978a60d9baf45.yaml b/releasenotes/notes/cancel_without_rollback-e5d978a60d9baf45.yaml new file mode 100644 index 0000000000..6c742654e4 --- /dev/null +++ b/releasenotes/notes/cancel_without_rollback-e5d978a60d9baf45.yaml @@ -0,0 +1,3 @@ +--- +features: + Adds REST api support to cancel a stack create/update without rollback.