From: Steven Hardy Date: Fri, 5 Jul 2013 11:25:50 +0000 (+0100) Subject: api : Implement OnFailure option to cfn API CreateStack call X-Git-Tag: 2014.1~333^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=5056908945edb721b04713347b780dfa8e28a21a;p=openstack-build%2Fheat-build.git api : Implement OnFailure option to cfn API CreateStack call blueprint createstack-onfailure Change-Id: I8466493fbeba2023916f2d92814c1cc8f2827e51 --- diff --git a/heat/api/cfn/v1/stacks.py b/heat/api/cfn/v1/stacks.py index 19b9c0ad..764e6b0b 100644 --- a/heat/api/cfn/v1/stacks.py +++ b/heat/api/cfn/v1/stacks.py @@ -289,11 +289,24 @@ class StackController(object): keymap = {'TimeoutInMinutes': engine_api.PARAM_TIMEOUT, 'DisableRollback': engine_api.PARAM_DISABLE_ROLLBACK} + if 'DisableRollback' in params and 'OnFailure' in params: + msg = _('DisableRollback and OnFailure ' + 'may not be used together') + raise exception.HeatInvalidParameterCombinationError( + detail=msg) + result = {} for k in keymap: - if k in req.params: + if k in params: result[keymap[k]] = params[k] + if 'OnFailure' in params: + value = params['OnFailure'] + if value == 'DO_NOTHING': + result[engine_api.PARAM_DISABLE_ROLLBACK] = 'true' + elif value in ('ROLLBACK', 'DELETE'): + result[engine_api.PARAM_DISABLE_ROLLBACK] = 'false' + return result if action not in self.CREATE_OR_UPDATE_ACTION: diff --git a/heat/tests/test_api_cfn_v1.py b/heat/tests/test_api_cfn_v1.py index 5dd18f94..bb663efe 100644 --- a/heat/tests/test_api_cfn_v1.py +++ b/heat/tests/test_api_cfn_v1.py @@ -488,6 +488,213 @@ class CfnStackControllerTest(HeatTestCase): self.assertEqual(response, expected) self.m.VerifyAll() + def test_create_rollback(self): + # Format a dummy request + stack_name = "wordpress" + template = {u'Foo': u'bar'} + json_template = json.dumps(template) + params = {'Action': 'CreateStack', 'StackName': stack_name, + 'TemplateBody': '%s' % json_template, + 'TimeoutInMinutes': 30, + 'DisableRollback': 'false', + 'Parameters.member.1.ParameterKey': 'InstanceType', + 'Parameters.member.1.ParameterValue': 'm1.xlarge'} + engine_parms = {u'InstanceType': u'm1.xlarge'} + engine_args = {'timeout_mins': u'30', 'disable_rollback': 'false'} + dummy_req = self._dummy_GET_request(params) + + # Stub out the RPC call to the engine with a pre-canned response + engine_resp = {u'tenant': u't', + u'stack_name': u'wordpress', + u'stack_id': u'1', + u'path': u''} + + self.m.StubOutWithMock(rpc, 'call') + rpc.call(dummy_req.context, self.topic, + {'namespace': None, + 'method': 'create_stack', + 'args': {'stack_name': stack_name, + 'template': template, + 'params': engine_parms, + 'files': {}, + 'args': engine_args}, + 'version': self.api_version}, None).AndReturn(engine_resp) + + self.m.ReplayAll() + + response = self.controller.create(dummy_req) + + expected = { + 'CreateStackResponse': { + 'CreateStackResult': { + u'StackId': u'arn:openstack:heat::t:stacks/wordpress/1' + } + } + } + + self.assertEqual(response, expected) + self.m.VerifyAll() + + def test_create_onfailure_true(self): + # Format a dummy request + stack_name = "wordpress" + template = {u'Foo': u'bar'} + json_template = json.dumps(template) + params = {'Action': 'CreateStack', 'StackName': stack_name, + 'TemplateBody': '%s' % json_template, + 'TimeoutInMinutes': 30, + 'OnFailure': 'DO_NOTHING', + 'Parameters.member.1.ParameterKey': 'InstanceType', + 'Parameters.member.1.ParameterValue': 'm1.xlarge'} + engine_parms = {u'InstanceType': u'm1.xlarge'} + engine_args = {'timeout_mins': u'30', 'disable_rollback': 'true'} + dummy_req = self._dummy_GET_request(params) + + # Stub out the RPC call to the engine with a pre-canned response + engine_resp = {u'tenant': u't', + u'stack_name': u'wordpress', + u'stack_id': u'1', + u'path': u''} + + self.m.StubOutWithMock(rpc, 'call') + rpc.call(dummy_req.context, self.topic, + {'namespace': None, + 'method': 'create_stack', + 'args': {'stack_name': stack_name, + 'template': template, + 'params': engine_parms, + 'files': {}, + 'args': engine_args}, + 'version': self.api_version}, None).AndReturn(engine_resp) + + self.m.ReplayAll() + + response = self.controller.create(dummy_req) + + expected = { + 'CreateStackResponse': { + 'CreateStackResult': { + u'StackId': u'arn:openstack:heat::t:stacks/wordpress/1' + } + } + } + + self.assertEqual(response, expected) + self.m.VerifyAll() + + def test_create_onfailure_false_delete(self): + # Format a dummy request + stack_name = "wordpress" + template = {u'Foo': u'bar'} + json_template = json.dumps(template) + params = {'Action': 'CreateStack', 'StackName': stack_name, + 'TemplateBody': '%s' % json_template, + 'TimeoutInMinutes': 30, + 'OnFailure': 'DELETE', + 'Parameters.member.1.ParameterKey': 'InstanceType', + 'Parameters.member.1.ParameterValue': 'm1.xlarge'} + engine_parms = {u'InstanceType': u'm1.xlarge'} + engine_args = {'timeout_mins': u'30', 'disable_rollback': 'false'} + dummy_req = self._dummy_GET_request(params) + + # Stub out the RPC call to the engine with a pre-canned response + engine_resp = {u'tenant': u't', + u'stack_name': u'wordpress', + u'stack_id': u'1', + u'path': u''} + + self.m.StubOutWithMock(rpc, 'call') + rpc.call(dummy_req.context, self.topic, + {'namespace': None, + 'method': 'create_stack', + 'args': {'stack_name': stack_name, + 'template': template, + 'params': engine_parms, + 'files': {}, + 'args': engine_args}, + 'version': self.api_version}, None).AndReturn(engine_resp) + + self.m.ReplayAll() + + response = self.controller.create(dummy_req) + + expected = { + 'CreateStackResponse': { + 'CreateStackResult': { + u'StackId': u'arn:openstack:heat::t:stacks/wordpress/1' + } + } + } + + self.assertEqual(response, expected) + self.m.VerifyAll() + + def test_create_onfailure_false_rollback(self): + # Format a dummy request + stack_name = "wordpress" + template = {u'Foo': u'bar'} + json_template = json.dumps(template) + params = {'Action': 'CreateStack', 'StackName': stack_name, + 'TemplateBody': '%s' % json_template, + 'TimeoutInMinutes': 30, + 'OnFailure': 'ROLLBACK', + 'Parameters.member.1.ParameterKey': 'InstanceType', + 'Parameters.member.1.ParameterValue': 'm1.xlarge'} + engine_parms = {u'InstanceType': u'm1.xlarge'} + engine_args = {'timeout_mins': u'30', 'disable_rollback': 'false'} + dummy_req = self._dummy_GET_request(params) + + # Stub out the RPC call to the engine with a pre-canned response + engine_resp = {u'tenant': u't', + u'stack_name': u'wordpress', + u'stack_id': u'1', + u'path': u''} + + self.m.StubOutWithMock(rpc, 'call') + rpc.call(dummy_req.context, self.topic, + {'namespace': None, + 'method': 'create_stack', + 'args': {'stack_name': stack_name, + 'template': template, + 'params': engine_parms, + 'files': {}, + 'args': engine_args}, + 'version': self.api_version}, None).AndReturn(engine_resp) + + self.m.ReplayAll() + + response = self.controller.create(dummy_req) + + expected = { + 'CreateStackResponse': { + 'CreateStackResult': { + u'StackId': u'arn:openstack:heat::t:stacks/wordpress/1' + } + } + } + + self.assertEqual(response, expected) + self.m.VerifyAll() + + def test_create_onfailure_err(self): + # Format a dummy request + stack_name = "wordpress" + template = {u'Foo': u'bar'} + json_template = json.dumps(template) + params = {'Action': 'CreateStack', 'StackName': stack_name, + 'TemplateBody': '%s' % json_template, + 'TimeoutInMinutes': 30, + 'DisableRollback': 'true', + 'OnFailure': 'DO_NOTHING', + 'Parameters.member.1.ParameterKey': 'InstanceType', + 'Parameters.member.1.ParameterValue': 'm1.xlarge'} + engine_parms = {u'InstanceType': u'm1.xlarge'} + engine_args = {'timeout_mins': u'30', 'disable_rollback': 'false'} + dummy_req = self._dummy_GET_request(params) + + self.assertRaises(exception.HeatInvalidParameterCombinationError, + self.controller.create, dummy_req) + def test_create_err_no_template(self): # Format a dummy request with a missing template field stack_name = "wordpress"