Support 'termination protection' for cloudformation stacks (#31675)
* Support 'termination protection' for cloudformation stacks - Pass in the stack_name and desired termination protection state to update_termination_protection * Fix for failing cloudformation unit test * Check if cfn has update_termination_protection attr * Use hasattr to test if cfn supports update_termination_protection * termination_protection shouldn't prevent update_stack call for existing stacks
This commit is contained in:
parent
a8bc6f69d9
commit
b9e15d0df1
1 changed files with 48 additions and 2 deletions
|
@ -118,6 +118,10 @@ options:
|
|||
required: false
|
||||
default: null
|
||||
version_added: "2.3"
|
||||
termination_protection:
|
||||
description:
|
||||
- enable or disable termination protection on the stack. Only works with botocore >= 1.7.18.
|
||||
version_added: "2.5"
|
||||
|
||||
author: "James S. Martin (@jsmartin)"
|
||||
extends_documentation_fragment:
|
||||
|
@ -173,6 +177,16 @@ EXAMPLES = '''
|
|||
ClusterSize: 3
|
||||
tags:
|
||||
Stack: ansible-cloudformation
|
||||
|
||||
# Enable termination protection on a stack.
|
||||
# If the stack already exists, this will update its termination protection
|
||||
- name: enable termination protection during stack creation
|
||||
cloudformation:
|
||||
stack_name: my_stack
|
||||
state: present
|
||||
template_url: https://s3.amazonaws.com/my-bucket/cloudformation.template
|
||||
termination_protection: yes
|
||||
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
|
@ -256,8 +270,14 @@ def create_stack(module, stack_params, cfn):
|
|||
if 'TemplateBody' not in stack_params and 'TemplateURL' not in stack_params:
|
||||
module.fail_json(msg="Either 'template' or 'template_url' is required when the stack does not exist.")
|
||||
|
||||
# 'disablerollback' only applies on creation, not update.
|
||||
# 'disablerollback' and 'EnableTerminationProtection' only
|
||||
# apply on creation, not update.
|
||||
stack_params['DisableRollback'] = module.params['disable_rollback']
|
||||
if module.params.get('termination_protection') is not None:
|
||||
if boto_supports_termination_protection(cfn):
|
||||
stack_params['EnableTerminationProtection'] = bool(module.params.get('termination_protection'))
|
||||
else:
|
||||
module.fail_json(msg="termination_protection parameter requires botocore >= 1.7.18")
|
||||
|
||||
try:
|
||||
cfn.create_stack(**stack_params)
|
||||
|
@ -328,6 +348,26 @@ def update_stack(module, stack_params, cfn):
|
|||
return result
|
||||
|
||||
|
||||
def update_termination_protection(module, cfn, stack_name, desired_termination_protection_state):
|
||||
'''updates termination protection of a stack'''
|
||||
if not boto_supports_termination_protection(cfn):
|
||||
module.fail_json(msg="termination_protection parameter requires botocore >= 1.7.18")
|
||||
stack = get_stack_facts(cfn, stack_name)
|
||||
if stack:
|
||||
if stack['EnableTerminationProtection'] is not desired_termination_protection_state:
|
||||
try:
|
||||
cfn.update_termination_protection(
|
||||
EnableTerminationProtection=desired_termination_protection_state,
|
||||
StackName=stack_name)
|
||||
except botocore.exceptions.ClientError as e:
|
||||
module.fail_json(msg=boto_exception(e), exception=traceback.format_exc())
|
||||
|
||||
|
||||
def boto_supports_termination_protection(cfn):
|
||||
'''termination protection was added in botocore 1.7.18'''
|
||||
return hasattr(cfn, "update_termination_protection")
|
||||
|
||||
|
||||
def stack_operation(cfn, stack_name, operation):
|
||||
'''gets the status of a stack while it is created/updated/deleted'''
|
||||
existed = []
|
||||
|
@ -450,7 +490,8 @@ def main():
|
|||
create_changeset=dict(default=False, type='bool'),
|
||||
changeset_name=dict(default=None, required=False),
|
||||
role_arn=dict(default=None, required=False),
|
||||
tags=dict(default=None, type='dict')
|
||||
tags=dict(default=None, type='dict'),
|
||||
termination_protection=dict(default=None, type='bool')
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -511,6 +552,8 @@ def main():
|
|||
cfn.describe_stacks = backoff_wrapper(cfn.describe_stacks)
|
||||
cfn.list_stack_resources = backoff_wrapper(cfn.list_stack_resources)
|
||||
cfn.delete_stack = backoff_wrapper(cfn.delete_stack)
|
||||
if boto_supports_termination_protection(cfn):
|
||||
cfn.update_termination_protection = backoff_wrapper(cfn.update_termination_protection)
|
||||
|
||||
stack_info = get_stack_facts(cfn, stack_params['StackName'])
|
||||
|
||||
|
@ -530,6 +573,9 @@ def main():
|
|||
elif module.params.get('create_changeset'):
|
||||
result = create_changeset(module, stack_params, cfn)
|
||||
else:
|
||||
if module.params.get('termination_protection') is not None:
|
||||
update_termination_protection(module, cfn, stack_params['StackName'],
|
||||
bool(module.params.get('termination_protection')))
|
||||
result = update_stack(module, stack_params, cfn)
|
||||
|
||||
# format the stack output
|
||||
|
|
Loading…
Reference in a new issue