AWSTemplateFormatVersion: 2010-09-09 Description: This CloudFormation Template invokes another template responsible for copying files to a local region S3 Bucket for AWS Lambda. (qs-1s1cul5ls) Metadata: cfn-lint: { config: { ignore_checks: [W9006, W9002, W9003] } } Parameters: QSS3BucketName: Description: The Template Bucket Name. Type: String QSS3KeyPrefix: Description: The Template Bucket Prefix. Type: String DestinationBucket: Type: String Description: "Bucket where Lambda artifacts will be copied to" Default: "" Conditions: UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] Resources: CopyRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: ConfigPolicy PolicyDocument: Version: 2012-10-17 Statement: - Sid: Logging Effect: Allow Action: - logs:AssociateKmsKey - logs:CancelExportTask - logs:CreateExportTask - logs:CreateLogDelivery - logs:CreateLogGroup - logs:CreateLogStream - logs:DeleteDestination - logs:DeleteLogDelivery - logs:DeleteLogGroup - logs:DeleteLogStream - logs:DeleteMetricFilter - logs:DeleteQueryDefinition - logs:DeleteResourcePolicy - logs:DeleteRetentionPolicy - logs:DeleteSubscriptionFilter - logs:DescribeDestinations - logs:DescribeExportTasks - logs:DescribeLogGroups - logs:DescribeLogStreams - logs:DescribeMetricFilters - logs:DescribeQueries - logs:DescribeQueryDefinitions - logs:DescribeResourcePolicies - logs:DescribeSubscriptionFilters - logs:DisassociateKmsKey - logs:FilterLogEvents - logs:GetLogDelivery - logs:GetLogEvents - logs:GetLogGroupFields - logs:GetLogRecord - logs:GetQueryResults - logs:ListLogDeliveries - logs:ListTagsLogGroup - logs:PutDestination - logs:PutDestinationPolicy - logs:PutLogEvents - logs:PutMetricFilter - logs:PutQueryDefinition - logs:PutResourcePolicy - logs:PutRetentionPolicy - logs:PutSubscriptionFilter - logs:StartQuery - logs:StopQuery - logs:TagLogGroup - logs:TestMetricFilter - logs:UntagLogGroup - logs:UpdateLogDelivery Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:* - Sid: S3Get Effect: Allow Action: - s3:GetObject Resource: - !Sub - arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}* - S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] - Sid: S3Put Effect: Allow Action: - s3:PutObject - s3:DeleteObject Resource: !Sub arn:${AWS::Partition}:s3:::${DestinationBucket}/* CopyZips: Type: AWS::CloudFormation::CustomResource DependsOn: - CopyRole Properties: ServiceToken: !GetAtt CopyZipsFunction.Arn DestRegion: !Ref AWS::Region DestBucket: !Ref DestinationBucket SourceBucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Prefix: !Ref QSS3KeyPrefix Objects: - "app/packages/dragen/dragen.zip" CopyZipsFunction: Type: AWS::Lambda::Function Properties: Description: Copies objects from a source S3 bucket to a destination Handler: index.handler Runtime: python3.7 Role: !GetAtt CopyRole.Arn Timeout: 240 Code: ZipFile: | import json import logging import threading import boto3 import cfnresponse def copy_objects(source_bucket, dest_bucket, prefix, objects): s3 = boto3.client('s3') for o in objects: key = prefix + o copy_source = { 'Bucket': source_bucket, 'Key': key } s3.copy_object(CopySource=copy_source, Bucket=dest_bucket, Key=key) def delete_objects(bucket, prefix, objects): s3 = boto3.client('s3') objects = {'Objects': [{'Key': prefix + o} for o in objects]} s3.delete_objects(Bucket=bucket, Delete=objects) def timeout(event, context): logging.error('Execution is about to time out, sending failure response to CloudFormation') cfnresponse.send(event, context, cfnresponse.FAILED, {}, None) def handler(event, context): # make sure we send a failure to CloudFormation if the function is going to timeout timer = threading.Timer((context.get_remaining_time_in_millis() / 1000.00) - 0.5, timeout, args=[event, context]) timer.start() print(('Received event: %s' % json.dumps(event))) status = cfnresponse.SUCCESS try: source_bucket = event['ResourceProperties']['SourceBucket'] dest_bucket = event['ResourceProperties']['DestBucket'] prefix = event['ResourceProperties']['Prefix'] objects = event['ResourceProperties']['Objects'] if event['RequestType'] == 'Delete': delete_objects(dest_bucket, prefix, objects) else: copy_objects(source_bucket, dest_bucket, prefix, objects) except Exception as e: logging.error('Exception: %s' % e, exc_info=True) status = cfnresponse.FAILED finally: timer.cancel() cfnresponse.send(event, context, status, {}, None)