From 86b9182767c67b32627c3aeafc727ac582bebf21 Mon Sep 17 00:00:00 2001 From: Mandar Kulkarni Date: Thu, 19 Dec 2024 12:49:04 -0800 Subject: [PATCH] cloudformation: Fix bug when updating stack's termination_protection with create_changeset set (#2391) SUMMARY Fixes #2149 Fix bug where termination protection is not updated when create_changeset=true is used for stack updates ISSUE TYPE Bugfix Pull Request COMPONENT NAME cloudformation ADDITIONAL INFORMATION Reviewed-by: Helen Bailey Reviewed-by: Bikouo Aubin Reviewed-by: GomathiselviS --- ...on-update-stack-termination_protection.yml | 3 + plugins/modules/cloudformation.py | 14 +- .../targets/cloudformation/defaults/main.yml | 1 + .../targets/cloudformation/tasks/main.yml | 122 ++++++++-------- .../tasks/test_disable_rollback.yml | 34 ++--- .../test_update_termination_protection.yml | 130 ++++++++++++++++++ 6 files changed, 225 insertions(+), 79 deletions(-) create mode 100644 changelogs/fragments/2391-cloudformation-update-stack-termination_protection.yml create mode 100644 tests/integration/targets/cloudformation/tasks/test_update_termination_protection.yml diff --git a/changelogs/fragments/2391-cloudformation-update-stack-termination_protection.yml b/changelogs/fragments/2391-cloudformation-update-stack-termination_protection.yml new file mode 100644 index 00000000000..2deb55fb327 --- /dev/null +++ b/changelogs/fragments/2391-cloudformation-update-stack-termination_protection.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - cloudformation - Fix bug where termination protection is not updated when create_changeset=true is used for stack updates (https://github.com/ansible-collections/amazon.aws/pull/2391). diff --git a/plugins/modules/cloudformation.py b/plugins/modules/cloudformation.py index 20c24b5cf6b..143d983854c 100644 --- a/plugins/modules/cloudformation.py +++ b/plugins/modules/cloudformation.py @@ -514,6 +514,7 @@ def update_stack(module, stack_params, cfn, events_limit): def update_termination_protection(module, cfn, stack_name, desired_termination_protection_state): """updates termination protection of a stack""" + changed = False stack = get_stack_facts(module, cfn, stack_name) if stack: if stack["EnableTerminationProtection"] is not desired_termination_protection_state: @@ -523,8 +524,10 @@ def update_termination_protection(module, cfn, stack_name, desired_termination_p EnableTerminationProtection=desired_termination_protection_state, StackName=stack_name, ) + changed = True except botocore.exceptions.ClientError as e: module.fail_json_aws(e) + return changed def stack_operation(module, cfn, stack_name, operation, events_limit, op_token=None): @@ -779,14 +782,17 @@ def main(): if state == "present": if not stack_info: result = create_stack(module, stack_params, cfn, module.params.get("events_limit")) - elif module.params.get("create_changeset"): - result = create_changeset(module, stack_params, cfn, module.params.get("events_limit")) else: + changeset_updated = False + if module.params.get("create_changeset"): + result = create_changeset(module, stack_params, cfn, module.params.get("events_limit")) + changeset_updated = True if module.params.get("termination_protection") is not None: - update_termination_protection( + result["changed"] = update_termination_protection( module, cfn, stack_params["StackName"], bool(module.params.get("termination_protection")) ) - result = update_stack(module, stack_params, cfn, module.params.get("events_limit")) + if not changeset_updated: + result = update_stack(module, stack_params, cfn, module.params.get("events_limit")) # format the stack output diff --git a/tests/integration/targets/cloudformation/defaults/main.yml b/tests/integration/targets/cloudformation/defaults/main.yml index 9f5b6c6088e..b3d906d4042 100644 --- a/tests/integration/targets/cloudformation/defaults/main.yml +++ b/tests/integration/targets/cloudformation/defaults/main.yml @@ -2,6 +2,7 @@ stack_name: "{{ resource_prefix }}" stack_name_disable_rollback_true: "{{ resource_prefix }}-drb-true" stack_name_disable_rollback_false: "{{ resource_prefix }}-drb-false" +stack_name_update_termination_protection: "{{ resource_prefix }}-update-tp" availability_zone: "{{ ec2_availability_zone_names[0] }}" diff --git a/tests/integration/targets/cloudformation/tasks/main.yml b/tests/integration/targets/cloudformation/tasks/main.yml index e2305edd984..c75e821a5e7 100644 --- a/tests/integration/targets/cloudformation/tasks/main.yml +++ b/tests/integration/targets/cloudformation/tasks/main.yml @@ -1,5 +1,6 @@ --- -- module_defaults: +- name: Wrap up all tests and setup AWS credentials + module_defaults: group/aws: access_key: "{{ aws_access_key }}" secret_key: "{{ aws_secret_key }}" @@ -26,8 +27,13 @@ # ==== Cloudformation tests with disable_rollback ==================== - - ansible.builtin.import_tasks: test_disable_rollback.yml - - name: create a cloudformation stack (check mode) + - name: Run tests for testing update stack termination protection + ansible.builtin.import_tasks: test_update_termination_protection.yml + + - name: Run tests for testing stack disable rollback + ansible.builtin.import_tasks: test_disable_rollback.yml + + - name: Create a cloudformation stack (Check mode) amazon.aws.cloudformation: stack_name: "{{ stack_name }}" template_body: "{{ lookup('file','cf_template.json') }}" @@ -41,13 +47,13 @@ register: cf_stack check_mode: true - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - cf_stack.changed - "'msg' in cf_stack and 'New stack would be created' in cf_stack.msg" - - name: create a cloudformation stack + - name: Create a cloudformation stack amazon.aws.cloudformation: stack_name: "{{ stack_name }}" template_body: "{{ lookup('file','cf_template.json') }}" @@ -60,7 +66,7 @@ test: "{{ resource_prefix }}" register: cf_stack - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - cf_stack.changed @@ -69,7 +75,7 @@ - "'stack_outputs' in cf_stack and 'InstanceId' in cf_stack.stack_outputs" - "'stack_resources' in cf_stack" - - name: create a cloudformation stack (check mode) (idempotent) + - name: Create a cloudformation stack (Check mode) (idempotent) amazon.aws.cloudformation: stack_name: "{{ stack_name }}" template_body: "{{ lookup('file','cf_template.json') }}" @@ -83,12 +89,12 @@ register: cf_stack check_mode: true - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - not cf_stack.changed - - name: create a cloudformation stack (idempotent) + - name: Create a cloudformation stack (idempotent) amazon.aws.cloudformation: stack_name: "{{ stack_name }}" template_body: "{{ lookup('file','cf_template.json') }}" @@ -101,7 +107,7 @@ test: "{{ resource_prefix }}" register: cf_stack - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - not cf_stack.changed @@ -109,21 +115,21 @@ - "'stack_outputs' in cf_stack and 'InstanceId' in cf_stack.stack_outputs" - "'stack_resources' in cf_stack" - - name: get all stacks details + - name: Get all stacks details amazon.aws.cloudformation_info: register: all_stacks_info - - name: assert all stacks info + - name: Assert all stacks info ansible.builtin.assert: that: - all_stacks_info | length > 0 - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - "'cloudformation' in stack_info" @@ -135,13 +141,13 @@ - "'stack_tags' in stack_info.cloudformation[stack_name]" - stack_info.cloudformation[stack_name].stack_tags.Stack == stack_name - - name: get stack details (checkmode) + - name: Get stack details (checkmode) amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info check_mode: true - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - "'cloudformation' in stack_info" @@ -153,13 +159,13 @@ - "'stack_tags' in stack_info.cloudformation[stack_name]" - stack_info.cloudformation[stack_name].stack_tags.Stack == stack_name - - name: get stack details (all_facts) + - name: Get stack details (all_facts) amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" all_facts: true register: stack_info - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - "'stack_events' in stack_info.cloudformation[stack_name]" @@ -168,14 +174,14 @@ - "'stack_resources' in stack_info.cloudformation[stack_name]" - "'stack_template' in stack_info.cloudformation[stack_name]" - - name: get stack details (all_facts) (checkmode) + - name: Get stack details (all_facts) (checkmode) amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" all_facts: true register: stack_info check_mode: true - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - "'stack_events' in stack_info.cloudformation[stack_name]" @@ -184,10 +190,10 @@ - "'stack_resources' in stack_info.cloudformation[stack_name]" - "'stack_template' in stack_info.cloudformation[stack_name]" - # ==== Cloudformation tests (create changeset) ============================ + # ==== Cloudformation tests (Create changeset) ============================ - # try to create a changeset by changing instance type - - name: create a changeset + # try to Create a changeset by changing instance type + - name: Create a changeset amazon.aws.cloudformation: stack_name: "{{ stack_name }}" create_changeset: true @@ -202,38 +208,38 @@ test: "{{ resource_prefix }}" register: create_changeset_result - - name: assert changeset created + - name: Assert changeset created ansible.builtin.assert: that: - create_changeset_result.changed - "'change_set_id' in create_changeset_result" - "'Stack CREATE_CHANGESET complete' in create_changeset_result.output" - - name: get stack details with changesets + - name: Get stack details with changesets amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" stack_change_sets: true register: stack_info - - name: assert changesets in info + - name: Assert changesets in info ansible.builtin.assert: that: - "'stack_change_sets' in stack_info.cloudformation[stack_name]" - - name: get stack details with changesets (checkmode) + - name: Get stack details with changesets (checkmode) amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" stack_change_sets: true register: stack_info check_mode: true - - name: assert changesets in info + - name: Assert changesets in info ansible.builtin.assert: that: - "'stack_change_sets' in stack_info.cloudformation[stack_name]" - # try to create an empty changeset by passing in unchanged template - - name: create a changeset + # try to Create an empty changeset by passing in unchanged template + - name: Create a changeset amazon.aws.cloudformation: stack_name: "{{ stack_name }}" create_changeset: true @@ -247,7 +253,7 @@ test: "{{ resource_prefix }}" register: create_changeset_result - - name: assert changeset created + - name: Assert changeset created ansible.builtin.assert: that: - not create_changeset_result.changed @@ -255,7 +261,7 @@ # ==== Cloudformation tests (termination_protection) ====================== - - name: set termination protection to true + - name: Set termination protection to true amazon.aws.cloudformation: stack_name: "{{ stack_name }}" termination_protection: true @@ -275,28 +281,28 @@ # that: # - cf_stack.changed - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - stack_info.cloudformation[stack_name].stack_description.enable_termination_protection - - name: get stack details (checkmode) + - name: Get stack details (checkmode) amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info check_mode: true - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - stack_info.cloudformation[stack_name].stack_description.enable_termination_protection - - name: set termination protection to false + - name: Set termination protection to false amazon.aws.cloudformation: stack_name: "{{ stack_name }}" termination_protection: false @@ -316,30 +322,30 @@ # that: # - cf_stack.changed - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - not stack_info.cloudformation[stack_name].stack_description.enable_termination_protection - - name: get stack details (checkmode) + - name: Get stack details (checkmode) amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info check_mode: true - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - not stack_info.cloudformation[stack_name].stack_description.enable_termination_protection # ==== Cloudformation tests (update_policy) ====================== - - name: setting an stack policy with json body + - name: Setting an stack policy with json body amazon.aws.cloudformation: stack_name: "{{ stack_name }}" stack_policy_body: "{{ lookup('file','update_policy.json') }}" @@ -353,12 +359,12 @@ test: "{{ resource_prefix }}" register: cf_stack - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info - - name: setting an stack policy on update + - name: Setting an stack policy on update amazon.aws.cloudformation: stack_name: "{{ stack_name }}" stack_policy_on_update_body: "{{ lookup('file','update_policy.json') }}" @@ -372,46 +378,46 @@ test: "{{ resource_prefix }}" register: cf_stack - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info # ==== Cloudformation tests (delete stack tests) ========================== - - name: delete cloudformation stack (check mode) + - name: Delete cloudformation stack (Check mode) amazon.aws.cloudformation: stack_name: "{{ stack_name }}" state: absent check_mode: true register: cf_stack - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - cf_stack.changed - "'msg' in cf_stack and 'Stack would be deleted' in cf_stack.msg" - - name: delete cloudformation stack + - name: Delete cloudformation stack amazon.aws.cloudformation: stack_name: "{{ stack_name }}" state: absent register: cf_stack - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - cf_stack.changed - "'output' in cf_stack and 'Stack Deleted' in cf_stack.output" - - name: delete cloudformation stack (check mode) (idempotent) + - name: Delete cloudformation stack (Check mode) (idempotent) amazon.aws.cloudformation: stack_name: "{{ stack_name }}" state: absent check_mode: true register: cf_stack - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - not cf_stack.changed @@ -419,35 +425,35 @@ - >- "Stack doesn't exist" in cf_stack.msg - - name: delete cloudformation stack (idempotent) + - name: Delete cloudformation stack (idempotent) amazon.aws.cloudformation: stack_name: "{{ stack_name }}" state: absent register: cf_stack - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - not cf_stack.changed - "'output' in cf_stack and 'Stack not found.' in cf_stack.output" - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - not stack_info.cloudformation - - name: get stack details (checkmode) + - name: Get stack details (checkmode) amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info check_mode: true - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - not stack_info.cloudformation @@ -455,7 +461,7 @@ # ==== Cleanup ============================================================ always: - - name: delete stack + - name: Delete stack amazon.aws.cloudformation: stack_name: "{{ stack_name }}" state: absent diff --git a/tests/integration/targets/cloudformation/tasks/test_disable_rollback.yml b/tests/integration/targets/cloudformation/tasks/test_disable_rollback.yml index 69e4e3795e5..b4bcae645e9 100644 --- a/tests/integration/targets/cloudformation/tasks/test_disable_rollback.yml +++ b/tests/integration/targets/cloudformation/tasks/test_disable_rollback.yml @@ -2,7 +2,7 @@ - name: Run cloudformation tests for `disable_rollback` parameter block: # disable rollback to true - - name: create a cloudformation stack (disable_rollback=true) (check mode) + - name: Create a cloudformation stack (disable_rollback=true) (check mode) amazon.aws.cloudformation: stack_name: "{{ stack_name_disable_rollback_true }}" state: present @@ -15,13 +15,13 @@ register: cf_stack check_mode: true - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - cf_stack.changed - "'msg' in cf_stack and 'New stack would be created' in cf_stack.msg" - - name: create a cloudformation stack (disable_rollback=true) + - name: Create a cloudformation stack (disable_rollback=true) amazon.aws.cloudformation: stack_name: "{{ stack_name_disable_rollback_true }}" state: present @@ -33,12 +33,12 @@ SubnetId: "{{ testing_subnet.subnet.id }}" register: cf_stack - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name_disable_rollback_true }}" register: stack_info - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - "'cloudformation' in stack_info" @@ -46,7 +46,7 @@ - stack_info.cloudformation[stack_name_disable_rollback_true].stack_description.disable_rollback == true # disable rollback to false - - name: create a cloudformation stack (disable_rollback=false) (check mode) + - name: Create a cloudformation stack (disable_rollback=false) (check mode) amazon.aws.cloudformation: stack_name: "{{ stack_name_disable_rollback_false }}" state: present @@ -59,13 +59,13 @@ register: cf_stack check_mode: true - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - cf_stack.changed - "'msg' in cf_stack and 'New stack would be created' in cf_stack.msg" - - name: create a cloudformation stack (disable_rollback=false) + - name: Create a cloudformation stack (disable_rollback=false) amazon.aws.cloudformation: stack_name: "{{ stack_name_disable_rollback_false }}" state: present @@ -77,12 +77,12 @@ SubnetId: "{{ testing_subnet.subnet.id }}" register: cf_stack - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name_disable_rollback_false }}" register: stack_info - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - "'cloudformation' in stack_info" @@ -90,7 +90,7 @@ - stack_info.cloudformation[stack_name_disable_rollback_false].stack_description.disable_rollback == false # disable rollback not set - - name: create a cloudformation stack (disable_rollback not set) (check mode) + - name: Create a cloudformation stack (disable_rollback not set) (check mode) amazon.aws.cloudformation: stack_name: "{{ stack_name }}" state: present @@ -102,13 +102,13 @@ register: cf_stack check_mode: true - - name: check task return attributes + - name: Check task return attributes ansible.builtin.assert: that: - cf_stack.changed - "'msg' in cf_stack and 'New stack would be created' in cf_stack.msg" - - name: create a cloudformation stack (disable_rollback not set) + - name: Create a cloudformation stack (disable_rollback not set) amazon.aws.cloudformation: stack_name: "{{ stack_name }}" state: present @@ -119,12 +119,12 @@ SubnetId: "{{ testing_subnet.subnet.id }}" register: cf_stack - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}" register: stack_info - - name: assert stack info + - name: Assert stack info ansible.builtin.assert: that: - "'cloudformation' in stack_info" @@ -191,7 +191,7 @@ SubnetId: "{{ testing_subnet.subnet.id }}" register: cf_stack - - name: get stack details + - name: Get stack details amazon.aws.cloudformation_info: stack_name: "{{ stack_name }}-failtest" register: stack_info @@ -204,7 +204,7 @@ - stack_info.cloudformation[stack_name+"-failtest"].stack_description.stack_status == "UPDATE_COMPLETE" always: - - name: delete stack + - name: Delete stack amazon.aws.cloudformation: stack_name: "{{ item }}" state: absent diff --git a/tests/integration/targets/cloudformation/tasks/test_update_termination_protection.yml b/tests/integration/targets/cloudformation/tasks/test_update_termination_protection.yml new file mode 100644 index 00000000000..a0f329ac4f3 --- /dev/null +++ b/tests/integration/targets/cloudformation/tasks/test_update_termination_protection.yml @@ -0,0 +1,130 @@ +--- +- name: Run cloudformation tests for upating `termination_protection` parameter when `create_changeset=true` + block: + - name: Create a cloudformation stack (termination_protection=true and create_changeset=true) + amazon.aws.cloudformation: + stack_name: "{{ stack_name_update_termination_protection }}" + state: present + disable_rollback: true + template_body: "{{ lookup('file','cf_template.json') }}" + create_changeset: true + termination_protection: true + template_parameters: + InstanceType: t3.nano + ImageId: "{{ ec2_ami_id }}" + SubnetId: "{{ testing_subnet.subnet.id }}" + register: cf_stack + + - name: Get stack details + amazon.aws.cloudformation_info: + stack_name: "{{ stack_name_update_termination_protection }}" + all_facts: true + register: stack_info + + - name: Assert stack info + ansible.builtin.assert: + that: + - cf_stack is changed + - cf_stack is not failed + - "'cloudformation' in stack_info" + - stack_info.cloudformation | length == 1 + - stack_info.cloudformation[stack_name_update_termination_protection].stack_description.enable_termination_protection == true + - stack_info.cloudformation[stack_name_update_termination_protection].stack_change_sets is defined + + - name: Update cloudformation stack `termination_protection=false` (create_changeset=true) + amazon.aws.cloudformation: + stack_name: "{{ stack_name_update_termination_protection }}" + state: present + disable_rollback: true + template_body: "{{ lookup('file','cf_template.json') }}" + create_changeset: true + termination_protection: false + template_parameters: + InstanceType: t3.nano + ImageId: "{{ ec2_ami_id }}" + SubnetId: "{{ testing_subnet.subnet.id }}" + register: cf_stack + + - name: Get stack details + amazon.aws.cloudformation_info: + stack_name: "{{ stack_name_update_termination_protection }}" + all_facts: true + register: stack_info + + - name: Assert stack info + ansible.builtin.assert: + that: + - cf_stack is changed + - cf_stack is not failed + - "'cloudformation' in stack_info" + - stack_info.cloudformation | length == 1 + - stack_info.cloudformation[stack_name_update_termination_protection].stack_description.enable_termination_protection == false + - stack_info.cloudformation[stack_name_update_termination_protection].stack_change_sets is defined + + - name: Update cloudformation stack `termination_protection=true` (create_changeset=true) + amazon.aws.cloudformation: + stack_name: "{{ stack_name_update_termination_protection }}" + state: present + disable_rollback: true + template_body: "{{ lookup('file','cf_template.json') }}" + create_changeset: true + termination_protection: true + template_parameters: + InstanceType: t3.nano + ImageId: "{{ ec2_ami_id }}" + SubnetId: "{{ testing_subnet.subnet.id }}" + register: cf_stack + + - name: Get stack details + amazon.aws.cloudformation_info: + stack_name: "{{ stack_name_update_termination_protection }}" + all_facts: true + register: stack_info + + - name: Assert stack info + ansible.builtin.assert: + that: + - cf_stack is changed + - cf_stack is not failed + - "'cloudformation' in stack_info" + - stack_info.cloudformation | length == 1 + - stack_info.cloudformation[stack_name_update_termination_protection].stack_description.enable_termination_protection == true + - stack_info.cloudformation[stack_name_update_termination_protection].stack_change_sets is defined + + - name: Update cloudformation stack `termination_protection=fale` (create_changeset=true) # required to delete stack + amazon.aws.cloudformation: + stack_name: "{{ stack_name_update_termination_protection }}" + state: present + disable_rollback: true + template_body: "{{ lookup('file','cf_template.json') }}" + create_changeset: true + termination_protection: false + template_parameters: + InstanceType: t3.nano + ImageId: "{{ ec2_ami_id }}" + SubnetId: "{{ testing_subnet.subnet.id }}" + register: cf_stack + + - name: Get stack details + amazon.aws.cloudformation_info: + stack_name: "{{ stack_name_update_termination_protection }}" + all_facts: true + register: stack_info + + - name: Assert stack info + ansible.builtin.assert: + that: + - cf_stack is changed + - cf_stack is not failed + - "'cloudformation' in stack_info" + - stack_info.cloudformation | length == 1 + - stack_info.cloudformation[stack_name_update_termination_protection].stack_description.enable_termination_protection == false + - stack_info.cloudformation[stack_name_update_termination_protection].stack_change_sets is defined + always: + - name: Delete stack + amazon.aws.cloudformation: + stack_name: "{{ item }}" + state: absent + ignore_errors: true + with_items: + - "{{ stack_name_update_termination_protection }}"