How to create a new version of a Lambda function using CloudFormation?

后端 未结 11 678
清歌不尽
清歌不尽 2020-12-08 03:44

I\'m trying to create a new version of a Lambda function using CloudFormation.

I want to have multiple versions of the same Lambda function so that I can (a) point a

11条回答
  •  没有蜡笔的小新
    2020-12-08 04:37

    Looking for a similar thing that works with Lambda functions deployed from S3.

    My use case was this:

    • You have a cloudformation template that creates a Lambda function from an S3 bucket location
    • You need to update this function so you make code changes locally and push the changes to S3
    • You now want to push these changes to Lambda so you try to update the stack and cloudformation says there are no changes to update so you have to resort to manually updating the code using the AWS Lambda console.

    Not happy with this I looked for an alternative and came across this question. None of the answers exactly worked for me so I have taken some ideas and adapted the answers here and made my own version written in Python.

    This code is adapted from the answer from @wjordan so credit to him for the idea and the original answer. The differences are:

    • This is written in Python
    • It works with Lambda code deployed from an S3 bucket
    • It updates the code and publishes a new version

    You need a nonce parameter. You change the value of this parameter when the code needs to be republished to Lambda. This is to ensure that cloudformation will update your custom resource. When the custom resource is updated, it will run the Python code that ultimately updates your Lambda code.

    Hope this helps someone.

    Description: Publish a new version of a Lambda function whenever the code is updated.
    Parameters:
      Nonce:
        Description: Change this string when code is updated.
        Type: String
        Default: "Test"
    Resources:
      MyCustomResource:
        Type: Custom::Resource
        Properties:
          ServiceToken: !GetAtt MyFunction.Arn
          Nonce: !Ref Nonce
      MyFunction:
        Type: AWS::Lambda::Function
        Properties:
          Handler: index.handler
          Role: !GetAtt LambdaExecutionRole.Arn
          Code:
            S3Bucket: BucketContainingYourLambdaFunction
            S3Key: KeyToYourLambdaFunction.zip
          Runtime: "python3.6"
      LambdaExecutionRole:
        Type: AWS::IAM::Role
        Properties:
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Principal: {Service: [lambda.amazonaws.com]}
              Action: ['sts:AssumeRole']
          Path: /
          ManagedPolicyArns:
          - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      LambdaDeployCustomResource:
        Type: Custom::LambdaVersion
        Properties:
          ServiceToken: !GetAtt LambdaDeployFunction.Arn
          FunctionName: !Ref MyFunction
          S3Bucket: BucketContainingYourLambdaFunction
          S3Key: KeyToYourLambdaFunction.zip
          Nonce: !Ref Nonce
      LambdaDeployFunction:
        Type: AWS::Lambda::Function
        DependsOn: LambdaDeployFunctionExecutionRole
        Properties:
          Handler: "index.handler"
          Role: !GetAtt LambdaDeployFunctionExecutionRole.Arn
          Code:
            ZipFile: !Sub |
              import boto3
              import json
              import logging
              import cfnresponse
              import time
              from botocore.exceptions import ClientError
    
              def handler(event, context):
                logger = logging.getLogger()
                logger.setLevel(logging.INFO)
                logger.info (f"Input parameters from cloud formation: {event}")
                responseData = {}
                if (event["RequestType"] == 'Delete'):
                  logger.info("Responding to delete event...")
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
    
                try:            
                  lambdaClient = boto3.client('lambda')
                  s3Bucket = event['ResourceProperties']['S3Bucket']
                  s3Key = event['ResourceProperties']['S3Key']
                  functionName = event['ResourceProperties']['FunctionName']
                  logger.info("Updating the function code for Lambda function '{}' to use the code stored in S3 bucket '{}' at key location '{}'".format(functionName, s3Bucket, s3Key))
                  logger.info("Sleeping for 5 seconds to allow IAM permisisons to take effect")
                  time.sleep(5)             
                  response = lambdaClient.update_function_code(
                    FunctionName=functionName,
                    S3Bucket='{}'.format(s3Bucket),
                    S3Key='{}'.format(s3Key),
                    Publish=True)
                  responseValue = "Function: {}, Version: {}, Last Modified: {}".format(response["FunctionName"],response["Version"],response["LastModified"])
                  responseData['Data'] = responseValue
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, response["FunctionArn"])
                except ClientError as e:
                  errorMessage = e.response['Error']['Message']
                  logger.error(errorMessage)
                  cfnresponse.send(event, context, cfnresponse.FAILED, responseData)
          Runtime: "python3.6"
          Timeout: "30"
      LambdaDeployFunctionExecutionRole:
        Type: AWS::IAM::Role
        Properties:
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Principal: 
                Service: lambda.amazonaws.com
              Action: 
                - sts:AssumeRole
          Path: /
          ManagedPolicyArns:
          - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
          Policies:
          - PolicyName: ReadS3BucketContainingLambdaCode
            PolicyDocument:
              Version: 2012-10-17
              Statement:
              - Effect: Allow
                Action: 
                  - s3:GetObject              
                Resource: ArnOfS3BucketContainingLambdaCode/*
          - PolicyName: UpdateCodeAndPublishVersion
            PolicyDocument:
              Version: 2012-10-17
              Statement:
              - Effect: Allow
                Action: 
                  - lambda:UpdateFunctionCode
                  - lambda:PublishVersion
                Resource: '*'
    Outputs:
      LambdaVersion:
        Value: !GetAtt LambdaDeploy.Version
      CustomResourceResult:
        Value: !GetAtt MyCustomResource.Result 
    

提交回复
热议问题