diff --git a/changelogs/fragments/20230814-cloudformation-stack-set.yml b/changelogs/fragments/20230814-cloudformation-stack-set.yml new file mode 100644 index 00000000000..02b512f885e --- /dev/null +++ b/changelogs/fragments/20230814-cloudformation-stack-set.yml @@ -0,0 +1,2 @@ +minor_changes: + - cloudformation_stack_set - add new 'purge_stack_instances' module parameter to remove stack instances when accounts are not present in the list of accounts diff --git a/plugins/modules/cloudformation_stack_set.py b/plugins/modules/cloudformation_stack_set.py index 17e888b4f1b..dcc54295ac9 100644 --- a/plugins/modules/cloudformation_stack_set.py +++ b/plugins/modules/cloudformation_stack_set.py @@ -31,7 +31,7 @@ type: dict state: description: - - If I(state=present), stack will be created. If I(state=present) and if stack exists and template has changed, it will be updated. + - If I(state=present), stack will be created. If I(state=present) and if stack exists and template has changed, it will be updated. If I(state=absent), stack will be removed. default: present choices: [ present, absent ] @@ -66,67 +66,72 @@ type: str purge_stacks: description: - - Only applicable when I(state=absent). Sets whether, when deleting a stack set, the stack instances should also be deleted. - - By default, instances will be deleted. To keep stacks when stack set is deleted set I(purge_stacks=false). + - Only applicable when I(state=absent). Sets whether, when deleting a stack set, the stack instances should also be deleted. + - By default, instances will be deleted. To keep stacks when stack set is deleted set I(purge_stacks=false). type: bool default: true + purge_stack_instances: + description: + - When set to C(True), instructs the module to delete stack instances that are not defined via the I(accounts) parameter. + type: bool + default: false wait: description: - - Whether or not to wait for stack operation to complete. This includes waiting for stack instances to reach UPDATE_COMPLETE status. - - If you choose not to wait, this module will not notify when stack operations fail because it will not wait for them to finish. + - Whether or not to wait for stack operation to complete. This includes waiting for stack instances to reach UPDATE_COMPLETE status. + - If you choose not to wait, this module will not notify when stack operations fail because it will not wait for them to finish. type: bool default: false wait_timeout: description: - - How long to wait (in seconds) for stacks to complete create/update/delete operations. + - How long to wait (in seconds) for stacks to complete create/update/delete operations. default: 900 type: int capabilities: description: - - Capabilities allow stacks to create and modify IAM resources, which may include adding users or roles. - - Currently the only available values are 'CAPABILITY_IAM' and 'CAPABILITY_NAMED_IAM'. Either or both may be provided. - - > - The following resources require that one or both of these parameters is specified: AWS::IAM::AccessKey, - AWS::IAM::Group, AWS::IAM::InstanceProfile, AWS::IAM::Policy, AWS::IAM::Role, AWS::IAM::User, AWS::IAM::UserToGroupAddition + - Capabilities allow stacks to create and modify IAM resources, which may include adding users or roles. + - Currently the only available values are 'CAPABILITY_IAM' and 'CAPABILITY_NAMED_IAM'. Either or both may be provided. + - > + The following resources require that one or both of these parameters is specified: AWS::IAM::AccessKey, + AWS::IAM::Group, AWS::IAM::InstanceProfile, AWS::IAM::Policy, AWS::IAM::Role, AWS::IAM::User, AWS::IAM::UserToGroupAddition type: list elements: str choices: - - 'CAPABILITY_IAM' - - 'CAPABILITY_NAMED_IAM' + - 'CAPABILITY_IAM' + - 'CAPABILITY_NAMED_IAM' regions: description: - - A list of AWS regions to create instances of a stack in. The I(region) parameter chooses where the Stack Set is created, and I(regions) - specifies the region for stack instances. - - At least one region must be specified to create a stack set. On updates, if fewer regions are specified only the specified regions will - have their stack instances updated. + - A list of AWS regions to create instances of a stack in. The I(region) parameter chooses where the Stack Set is created, and I(regions) + specifies the region for stack instances. + - At least one region must be specified to create a stack set. On updates, if fewer regions are specified only the specified regions will + have their stack instances updated. type: list elements: str accounts: description: - - A list of AWS accounts in which to create instance of CloudFormation stacks. - - At least one region must be specified to create a stack set. On updates, if fewer regions are specified only the specified regions will - have their stack instances updated. + - A list of AWS accounts in which to create instance of CloudFormation stacks. + - At least one region must be specified to create a stack set. On updates, if fewer regions are specified only the specified regions will + have their stack instances updated. type: list elements: str administration_role_arn: description: - - ARN of the administration role, meaning the role that CloudFormation Stack Sets use to assume the roles in your child accounts. - - This defaults to C(arn:aws:iam::{{ account ID }}:role/AWSCloudFormationStackSetAdministrationRole) where C({{ account ID }}) is replaced with the - account number of the current IAM role/user/STS credentials. + - ARN of the administration role, meaning the role that CloudFormation Stack Sets use to assume the roles in your child accounts. + - This defaults to C(arn:aws:iam::{{ account ID }}:role/AWSCloudFormationStackSetAdministrationRole) where C({{ account ID }}) is replaced with the + account number of the current IAM role/user/STS credentials. aliases: - - admin_role_arn - - admin_role - - administration_role + - admin_role_arn + - admin_role + - administration_role type: str execution_role_name: description: - - ARN of the execution role, meaning the role that CloudFormation Stack Sets assumes in your child accounts. - - This MUST NOT be an ARN, and the roles must exist in each child account specified. - - The default name for the execution role is C(AWSCloudFormationStackSetExecutionRole) + - ARN of the execution role, meaning the role that CloudFormation Stack Sets assumes in your child accounts. + - This MUST NOT be an ARN, and the roles must exist in each child account specified. + - The default name for the execution role is C(AWSCloudFormationStackSetExecutionRole) aliases: - - exec_role_name - - exec_role - - execution_role + - exec_role_name + - exec_role + - execution_role type: str tags: description: @@ -135,40 +140,41 @@ type: dict failure_tolerance: description: - - Settings to change what is considered "failed" when running stack instance updates, and how many to do at a time. + - Settings to change what is considered "failed" when running stack instance updates, and how many to do at a time. type: dict default: {} suboptions: fail_count: description: - - The number of accounts, per region, for which this operation can fail before CloudFormation - stops the operation in that region. - - You must specify one of I(fail_count) and I(fail_percentage). + - The number of accounts, per region, for which this operation can fail before CloudFormation + stops the operation in that region. + - You must specify one of I(fail_count) and I(fail_percentage). type: int fail_percentage: type: int description: - - The percentage of accounts, per region, for which this stack operation can fail before CloudFormation - stops the operation in that region. - - You must specify one of I(fail_count) and I(fail_percentage). + - The percentage of accounts, per region, for which this stack operation can fail before CloudFormation + stops the operation in that region. + - You must specify one of I(fail_count) and I(fail_percentage). parallel_percentage: type: int description: - - The maximum percentage of accounts in which to perform this operation at one time. - - You must specify one of I(parallel_count) and I(parallel_percentage). - - Note that this setting lets you specify the maximum for operations. - For large deployments, under certain circumstances the actual percentage may be lower. + - The maximum percentage of accounts in which to perform this operation at one time. + - You must specify one of I(parallel_count) and I(parallel_percentage). + - Note that this setting lets you specify the maximum for operations. + For large deployments, under certain circumstances the actual percentage may be lower. parallel_count: type: int description: - - The maximum number of accounts in which to perform this operation at one time. - - I(parallel_count) may be at most one more than the I(fail_count). - - You must specify one of I(parallel_count) and I(parallel_percentage). - - Note that this setting lets you specify the maximum for operations. - For large deployments, under certain circumstances the actual count may be lower. + - The maximum number of accounts in which to perform this operation at one time. + - I(parallel_count) may be at most one more than the I(fail_count). + - You must specify one of I(parallel_count) and I(parallel_percentage). + - Note that this setting lets you specify the maximum for operations. + For large deployments, under certain circumstances the actual count may be lower. author: - "Ryan Scott Brown (@ryansb)" + - "Razique Mahroua (@razique)" extends_documentation_fragment: - amazon.aws.common.modules - amazon.aws.region.modules @@ -235,6 +241,23 @@ - 345678901234 regions: - us-east-1 + +- name: Delete untracked stack instances for an existing stack set. + community.aws.cloudformation_stack_set: + name: my-stack + state: present + purge_stack_instances: true + parameters: + InstanceName: my_restacked_instance + tags: + foo: bar + test: stack + accounts: + - 123456789012 + - 234567890123 + - 345678901234 + regions: + - us-east-1 """ RETURN = r""" @@ -459,10 +482,11 @@ def await_stack_instance_completion(module, cfn, stack_set_name, max_wait): pass time.sleep(15) - module.warn( - f"Timed out waiting for stack set {stack_set_name} instances {', '.join(s['StackId'] for s in to_await)} to" - f" complete after {max_wait} seconds. Returning unfinished operation" - ) + if to_await: + module.warn( + f"Timed out waiting for stack set {stack_set_name} instances {', '.join(s['StackId'] for s in to_await)} to" + f" complete after {max_wait} seconds. Returning unfinished operation" + ) def await_stack_set_exists(cfn, stack_set_name): @@ -539,6 +563,7 @@ def main(): wait_timeout=dict(type="int", default=900), state=dict(default="present", choices=["present", "absent"]), purge_stacks=dict(type="bool", default=True), + purge_stack_instances=dict(type="bool", default=False), parameters=dict(type="dict", default={}), template=dict(type="path"), template_url=dict(), @@ -705,10 +730,21 @@ def main(): changed = True cfn.create_stack_instances( StackSetName=module.params["name"], - Accounts=list(set(acct for acct, region in new_stack_instances)), - Regions=list(set(region for acct, region in new_stack_instances)), + Accounts=list(set(acct for acct, dummy in new_stack_instances)), + Regions=list(set(region for dummy, region in new_stack_instances)), + OperationPreferences=get_operation_preferences(module), + OperationId=operation_ids[-1], + ) + elif unspecified_stack_instances and module.params.get("purge_stack_instances"): + operation_ids.append(f"Ansible-StackInstance-RemoveInstance-{operation_uuid}") + changed = True + cfn.delete_stack_instances( + StackSetName=module.params["name"], + Accounts=list(set(acct for acct, dummy in unspecified_stack_instances)), + Regions=list(set(region for dummy, region in unspecified_stack_instances)), OperationPreferences=get_operation_preferences(module), OperationId=operation_ids[-1], + RetainStacks=not module.params.get("purge_stacks"), ) else: operation_ids.append(f"Ansible-StackInstance-Update-{operation_uuid}")