def lambda_handler()

in lambdas/custom_resources/CTE_CrossAccountCloudFormation/src/main.py [0:0]


def lambda_handler(event, context):
    print(json.dumps(event))
    response_data = dict()
    response = None
    description = ''
    config = event['ResourceProperties']['Parameters']['Configuration']
    base_stack_name = config['StackName']
    resources = config['Resources']
    outputs = dict()
    regions = list()
    count = 1

    # This will replace to all for local supported functions to ensure they will run as expected
    resources = ast.literal_eval(json.dumps(resources).replace("&Ref", "Ref").replace("&Fn", "Fn"))
    logger.debug(f"Resources Post Replace:{resources}")

    # Get tags from Cfn Configuration
    tags = config.get('Tags')

    # If regions are specified within the Cfn Configuration use that list, if non are provided use
    #  the region that executed the cfn stack
    if config.get('Regions'):
        regions = config['Regions']

    else:
        regions.append(event['ResponseURL'].split("%3A")[3])

    if config.get('Description'):
        description = config['Description'] + ' '

    # This will replace to all for local supported functions to ensure they will run as expected
    try:
        outputs = config.get('Outputs', {})
        outputs = ast.literal_eval(json.dumps(outputs).replace("&Ref", "Ref").replace("&Fn", "Fn"))
        logger.debug(f"Outputs Post Replace:{outputs}")

    except Exception as e:
        logger.warning(e)
        logger.warning(f"No Outputs found from template {config['StackName']}")

    # Get the number of regions it will deploy to to allow for proper Cfn Outputs
    num_of_regions = len(regions)

    for region in regions:
        logger.info(f"Running in Region:{region}")
        config['StackName'] = base_stack_name.replace('%_REGION_%', region)
        _resources = json.loads(json.dumps(resources).replace("%_REGION_%", region))

        try:
            credentials = assume_role_arn(role_arn=config['RoleArn'])
            session = boto3_session(region=region, credentials=credentials)

        except Exception as e:
            logger.error(f"Assume Role Error:{e}", exc_info=True)
            response_data['ERROR'] = str(e)
            cfnresponse.send(
                event=event,
                context=context,
                responseStatus=cfnresponse.FAILED,
                responseData=response_data
            )
            return

        if event['RequestType'] == "Delete":
            try:
                if config.get("OnFailure", "DELETE") == "DELETE":
                    disable_termination_protection(stack_name=config['StackName'], session=session)
                    response = delete_stack(stack_name=config['StackName'], session=session)

                    if response:
                        response_data['Data'] = response

                cfnresponse.send(
                    event=event,
                    context=context,
                    responseStatus=cfnresponse.SUCCESS,
                    responseData=response_data
                )
                return

            except Exception as e:
                logger.error(f"Deleting Stack Error:{e}", exc_info=True)
                response_data['ERROR'] = str(e)
                cfnresponse.send(
                    event=event,
                    context=context,
                    responseStatus=cfnresponse.FAILED,
                    responseData=response_data
                )
                return

        else:
            try:
                logger.debug(f"Deployed Resources:{_resources}")
                template = {
                    "AWSTemplateFormatVersion": "2010-09-09",
                    "Description": "{}(Lambda:CrossAccountCloudFormation)".format(description),
                    "Resources": _resources,
                    "Outputs": outputs
                }

                response = create_update_stack(
                    stack_name=config['StackName'],
                    template=template,
                    cfn_params=None,
                    capability=config['Capabilities'],
                    waiter=True,
                    tags=tags,
                    session=session
                )

                if response:
                    response_data['Data'] = response
                    try:
                        stack_info = describe_stack(stack_name=config['StackName'], session=session)
                        if stack_info["Stacks"][0].get("Outputs"):
                            for output in stack_info["Stacks"][0]["Outputs"]:
                                if num_of_regions > 1:
                                    response_data[output["OutputKey"] + f"_Region{count}"] = output["OutputValue"]
                                else:
                                    response_data[output["OutputKey"]] = output["OutputValue"]
                        else:
                            logger.info('Not Stack Outputs Found')

                    except Exception as e:
                        logger.error(f"Error getting Stack Details:{e}", exc_info=True)
                        raise

                if config.get('TerminationProtection') and (config['TerminationProtection'].lower() == 'true'):
                    enable_termination_protection(stack_name=config['StackName'], session=session)

                logger.debug(f"response_data:{response_data}")
                cfnresponse.send(
                    event=event,
                    context=context,
                    responseStatus=cfnresponse.SUCCESS,
                    responseData=response_data
                )

            except Exception as e:
                logger.error(f"Main Function Error:{e}", exc_info=True)
                if response:
                    response_data['ERROR'] = f"{response} - {str(e)}"

                else:
                    response_data['ERROR'] = str(e)

                cfnresponse.send(
                    event=event,
                    context=context,
                    responseStatus=cfnresponse.FAILED,
                    responseData=response_data
                )
        count += 1