From 31f36808252918e009430ff8c0ff60733b4e2a61 Mon Sep 17 00:00:00 2001 From: Jay McConnell Date: Mon, 21 Jan 2019 11:47:07 -0800 Subject: [PATCH 1/2] add LambdaZips pattern --- patterns/LambdaZips/README.md | 37 ++++++++ patterns/LambdaZips/example.yaml | 144 +++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 patterns/LambdaZips/README.md create mode 100644 patterns/LambdaZips/example.yaml diff --git a/patterns/LambdaZips/README.md b/patterns/LambdaZips/README.md new file mode 100644 index 0000000..3514bce --- /dev/null +++ b/patterns/LambdaZips/README.md @@ -0,0 +1,37 @@ +# Lambda Zips + +This pattern enables templates that include Lambda functions to be deployed in any region without needing additional +regional buckets containing function zips. + +## Example implementation + +[Full example template including custom resource source code.](/patterns/LambdaZips/example.yaml) + +## Usage: +```yaml +Resources: + # Create a bucket in the local region + LambdaZipsBucket: + Type: AWS::S3::Bucket + # Copy zip files from source bucket + CopyZips: + Type: Custom::CopyZips + Properties: + ServiceToken: !GetAtt 'CopyZipsFunction.Arn' + DestBucket: !Ref 'LambdaZipsBucket' + SourceBucket: !Ref 'QSS3BucketName' + Prefix: !Ref 'QSS3KeyPrefix' + Objects: + - functions/packages/MyFunction/lambda.zip + # Your lambda function + MyFunction: + # DependsOn is required to ensure copy is complete before creating the function + DependsOn: CopyZips + Type: AWS::Lambda::Function + Properties: + Code: + # points to regional bucket + S3Bucket: !Ref 'LambdaZipsBucket' + S3Key: !Sub '${QSS3KeyPrefix}functions/packages/MyFunction/lambda.zip' + ... +``` \ No newline at end of file diff --git a/patterns/LambdaZips/example.yaml b/patterns/LambdaZips/example.yaml new file mode 100644 index 0000000..f6a172f --- /dev/null +++ b/patterns/LambdaZips/example.yaml @@ -0,0 +1,144 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Example Lambda zip copy' +Parameters: + QSS3BucketName: + AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ + Default: aws-quickstart + Type: String + QSS3KeyPrefix: + AllowedPattern: ^[0-9a-zA-Z-/]*$ + Default: quickstart-redhat-openshift/ + Type: String +Resources: + LambdaZipsBucket: + Type: AWS::S3::Bucket + CopyZips: + Type: Custom::CopyZips + Properties: + ServiceToken: !GetAtt 'CopyZipsFunction.Arn' + DestBucket: !Ref 'LambdaZipsBucket' + SourceBucket: !Ref 'QSS3BucketName' + Prefix: !Ref 'QSS3KeyPrefix' + Objects: + - functions/packages/CleanupPV/lambda.zip + CopyZipsRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Path: / + Policies: + - PolicyName: lambda-copier + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - s3:GetObject + Resource: + - !Sub 'arn:aws:s3:::${QSS3BucketName}/${QSS3KeyPrefix}*' + - Effect: Allow + Action: + - s3:PutObject + - s3:DeleteObject + Resource: + - !Sub 'arn:aws:s3:::${LambdaZipsBucket}/${QSS3KeyPrefix}*' + CopyZipsFunction: + Type: AWS::Lambda::Function + Properties: + Description: Copies objects from a source S3 bucket to a destination + Handler: index.handler + Runtime: python2.7 + Role: !GetAtt 'CopyZipsRole.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 + } + print('copy_source: %s' % copy_source) + print('dest_bucket = %s'%dest_bucket) + print('key = %s' %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) + + MyFunctionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + MyFunction: + DependsOn: CopyZips + Type: AWS::Lambda::Function + Properties: + Description: Example + Handler: lambda_function.handler + Runtime: python2.7 + Role: !GetAtt 'MyFunctionRole.Arn' + Timeout: 300 + Code: + S3Bucket: !Ref 'LambdaZipsBucket' + S3Key: !Sub '${QSS3KeyPrefix}functions/packages/CleanupPV/lambda.zip' From 1551d1184ba017602a52b4cc929e84c491211be0 Mon Sep 17 00:00:00 2001 From: Jay McConnell Date: Mon, 21 Jan 2019 12:20:44 -0800 Subject: [PATCH 2/2] more accurate wording --- patterns/LambdaZips/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patterns/LambdaZips/README.md b/patterns/LambdaZips/README.md index 3514bce..705f8b1 100644 --- a/patterns/LambdaZips/README.md +++ b/patterns/LambdaZips/README.md @@ -1,7 +1,7 @@ # Lambda Zips -This pattern enables templates that include Lambda functions to be deployed in any region without needing additional -regional buckets containing function zips. +This pattern enables templates that include Lambda functions to be deployed in any region without needing to manually +create and populate additional regional buckets containing function zips. ## Example implementation