#!/usr/bin/env python3.9 # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 """Resource Name CloudFormation Custom Resource This is used generate a resource name prefix based on the parameters of the stack. It takes the following resource attributes: - BotId - BotLocaleId - StackName It retrieves the Bot Name using the DescribeBot API and returns a string like: <BotName>-<BotId>-<BotLocaleId>-<StackName> This is used to be able to generate resource names related to the bot but still keep them human readable. It also works around the `serverlessrepo` prefix that is added by the Serverless Application Repository (SAR) """ import logging from os import getenv import boto3 from botocore.config import Config as BotoCoreConfig from crhelper import CfnResource LOGGER = logging.getLogger(__name__) LOG_LEVEL = getenv("LOG_LEVEL", "DEBUG") HELPER = CfnResource( json_logging=True, log_level=LOG_LEVEL, ) SAR_STACK_PREFIX = "serverlessrepo-" # global init code goes here so that it can pass failure in case # of an exception try: # boto3 client CLIENT_CONFIG = BotoCoreConfig( retries={"mode": "adaptive", "max_attempts": 5}, ) CLIENT = boto3.client("lexv2-models", config=CLIENT_CONFIG) except Exception as init_exception: # pylint: disable=broad-except HELPER.init_failure(init_exception) @HELPER.create @HELPER.update def create_or_update_resource_name(event, _): """Create or Update Resource""" resource_type = event["ResourceType"] resource_properties = event["ResourceProperties"] if resource_type == "Custom::ResourceName": bot_id = resource_properties["BotId"] bot_locale_id = resource_properties["BotLocaleId"] stack_name = resource_properties["StackName"].removeprefix(SAR_STACK_PREFIX) try: response = CLIENT.describe_bot( botId=bot_id, ) bot_name = response["botName"] except Exception as exception: # pylint: disable=broad-except LOGGER.error("failed to call describe_bot - exception: %s", exception) raise return f"{bot_name}-{bot_id}-{bot_locale_id}-{stack_name}" raise ValueError(f"invalid resource type: {resource_type}") @HELPER.delete def delete_no_op(event, _): """Delete Resource""" LOGGER.info("delete event ignored: %s", event) def handler(event, context): """Lambda Handler""" HELPER(event, context)