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
Looking for a similar thing that works with Lambda functions deployed from S3.
My use case was this:
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:
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