in lambdas/custom_resources/CTE_CrossAccountCloudFormation/src/cfn_helper.py [0:0]
def create_update_stack(stack_name, template, cfn_params, capability, region='us-east-1', waiter=False, tags=None, session=None):
"""Creates or updates a cloudformation stack using the provided parameters and
optionally waits for it to be complete
Args:
stack_name (str): Name of the stack to create/update
template (str or dict): Path to the template file on disk to create stack with
cfn_params (list of dict, optional): List of parameter structures that specify input parameters for the stack
capability (str): The capability string noting if the stack contains IAM or custom named IAM resources
Options: 'CAPABILITY_IAM'|'CAPABILITY_NAMED_IAM'
region (str): AWS Region
waiter (bool): True/False if we should wait for the stack to complete or immediately return response
tags (list): tags set on CloudFormation stack
session (object, optional): boto3 session object
Returns:
dict: Standard AWS response dict
"""
# Setup default arguments for cfn
args = dict()
args['StackName'] = stack_name
args['Capabilities'] = list()
args['session'] = session
# Setup CloudFormation Path and/or Body
args['TemplateBody'] = json.dumps(template)
template_body = args['TemplateBody']
# Does CloudFormation Stack already Exists
stack_exists = describe_stack(
stack_name=stack_name,
session=session
)
# Setup Tags
if tags:
args['Tags'] = tags
if not tags and stack_exists:
args['Tags'] = stack_exists['Stacks'][0]['Tags']
# If CloudFormation stack is currently in progress pickup where it was left off
in_progress_status = [
"CREATE_IN_PROGRESS",
"UPDATE_IN_PROGRESS",
"DELETE_IN_PROGRESS",
"ROLLBACK_IN_PROGRESS",
"UPDATE_COMPLETE_CLEANUP_IN_PROGRESS",
"UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS",
"UPDATE_ROLLBACK_IN_PROGRESS"
]
if stack_exists and (stack_exists['Stacks'][0]['StackStatus'] in in_progress_status):
wait_all_stacks([{"Name": stack_name, "Session": session}])
return
# Setup capability to be a list so CloudFormation doesn't fail
if isinstance(capability, str):
args['Capabilities'] = [capability]
elif isinstance(capability, list):
args['Capabilities'] = capability
# Check to see if an Update or Create needs to occur
if stack_exists:
# if stack exists get integration existing / override parameters
if stack_exists['Stacks'][0].get('Parameters'):
logger.info(f"Parameters found in existing Cfn Stack ({stack_name})")
parameters = update_parameters(
override_parameters=cfn_params,
current_parameters=stack_exists['Stacks'][0]['Parameters']
)
else:
logger.info(f"No Parameters found in existing Cfn Stack ({stack_name})")
parameters = update_parameters(override_parameters=cfn_params)
args['Parameters'] = remove_unused_parameters(template=template_body, parameters=parameters)
response = update_stack(**args)
cfn_action = 'stack_update_complete'
else:
args['Parameters'] = update_parameters(override_parameters=cfn_params)
logger.info(f"Parameters:{args['Parameters']}")
response = create_stack(**args)
cfn_action = 'stack_create_complete'
# Check to see if a waiter is needed and a proper response was received
if response and waiter:
stack_id = response['StackId']
stack_url = f"https://console.aws.amazon.com/cloudformation/home?region={region}#/stack/detail?stackId={re.sub('/', '%2F', stack_id)}"
logger.info("Waiting for CloudFormation Stack to complete")
wait_for_stack_complete(stack_name=stack_name, stack_url=stack_url, cfn_action=cfn_action, session=session)
return response