aws-cdk

Create log group for custom resource lambda in @aws-cdk/aws-s3-deployment


I am using the @aws-cdk/aws-s3-deployment module to upload files to s3 during deployment.

The module creates a CustomResource with a Lambda Function to move the files from the assets bucket to my bucket. When the Lambda function runs, it auto-creates a log group, which:

My normal solution is to just create the Log Group myself! But for that I need to name the lambda function (so that I can create the log group with the same name).

@aws-cdk/aws-s3-deployment uses SingletonFunction, which can be passed a function name. But @aws-cdk/aws-s3-deployment does not pass a function name.

Is there a way to set the name of the lambda function when using @aws-cdk/aws-s3-deployment?


Solution

  • The S3-Deployment will create CustomResources that behave like you described upon stack creation and deletion. To set the retention as well as tags of the log group, you have to create the resource yourself. The crux is to link it to the underlying lambda function of the custom resource and add the log group as dependency to that lambda. However, you cannot alter the SingletonFunction. I found a way to get the actual underlying lambda function, link it to a log group by its name, and set the dependencies. This will ensure that the whole stack including the log group will be deleted properly. I hope this will fix your problem!

    from aws_cdk import (
        aws_ec2 as ec2,
        aws_s3 as s3,
        aws_s3_deployment as s3deploy,
        aws_logs as logs,
        Aws, Stack,
    )
    from constructs import Construct
    
    class S3AssetDeployment(Construct):
        def __init__(
            self,
            scope: Construct,
            construct_id: str,
            vpc: ec2.Vpc,
            subnets: ec2.SubnetSelection,
        ):
    
            bucket = s3.Bucket(
                self,
                "AssetsBucket",
                bucket_name=f"fancy-project-assets-{Aws.ACCOUNT_ID}",
            )
    
            s3_deployment = s3deploy.BucketDeployment(
                self,
                "Assets",
                sources=[s3deploy.Source.asset(sync_directory)],
                destination_bucket=bucket,
                destination_key_prefix=sync_subdir,
                vpc=vpc,
                vpc_subnets=subnets,
            )
    
            # Find the underlying lambda function of the custom resource and overwrite its name
            all_stack_objects = Stack.of(s3_deployment).node.find_all()
            id_to_find = "Custom::CDKBucketDeployment"
            lambda_id = next(( item for item in [obj.node.id for obj in all_stack_objects] if id_to_find in item ), None)
    
            custom_resource_lambda = Stack.of(s3_deployment).node.find_child(lambda_id)
            custom_resource_lambda.node.default_child.add_property_override(
                "FunctionName", f"fancy-project-bucket-deployment"
            )
    
            # Create new log group with the same name and add the dependencies.
            deployment_log_group = logs.LogGroup(
                self,
                "BucketDeploymentLogGroup",
                log_group_name=f"/aws/lambda/fancy-project-bucket-deployment",
                removal_policy=RemovalPolicy.DESTROY,
                retention=logs.RetentionDays.TWO_WEEKS,
            )
    
            custom_resource_lambda.node.add_dependency(deployment_log_group)
            bucket.node.add_dependency(deployment_log_group)