5

My goal here is that additional SAM deploy calls will result in the :staging alias reflecting the latest version and :live will get updated by outside means, but has to be initialized to the same version created at deploy-time.

I'm using SAM deploy and need aliases on my lambdas. Adding them in the initial template is tricky because you can't create an alias with an explicit version number and AWS CloudFormation forces retention on old lambda versions so you CAN NOT know the version without checking resources. This is the best approach I've found so far, but it's cumbersome and doesn't scale nicely (need the same logic for every stack).

This code also depends on cfn-response.js for custom-resource management.

How can I do this better?

template.yaml

GetLatestVersionOfLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
        FunctionName: GetLatestVersionOfLambdaFunction
        Description: Given an existing Lambda Function Name, return the most recent version number
        VersionDescription: !Sub ${deployVersionDescription}
        AutoPublishAlias: staging
        CodeUri: src/
        Handler: getLatestLambdaVersionByName.handler
        MemorySize: 128
        Runtime: nodejs12.x
        Timeout: 10
        Tracing: Active
        Role: !GetAtt GetLatestVersionOfLambdaRole.Arn
SampleLambdaGetMaxVersionFunction:
    Type: Custom::FunctionVersion
    Properties:
        ServiceToken: !GetAtt GetLatestVersionOfLambdaFunction.Arn
        FunctionName: !Ref SampleLambdaFunction
SampleLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
        FunctionName: SampleLambda
        AutoPublishAlias: staging
        CodeUri: src/
        Handler: SampleLambda.handler
        MemorySize: 512
        Runtime: nodejs12.x
        Role: !GetAtt SampleLambdaRole.Arn
SampleLambdaLiveAlias:
    Type: AWS::Lambda::Alias
    Properties:
        FunctionName: !Ref SampleLambdaFunction
        FunctionVersion: !GetAtt SampleLambdaGetMaxVersionFunction.version
        Name: live

src/getLatestLambdaVersionByName.js

const response = require('./cfn-response.js'),
    AWS = require('aws-sdk'),
    lambda = new AWS.Lambda({ apiVersion: '2015-03-31' });

exports.handler = function (event, context) {
    console.log({ GetLatestLambdaVersionBynameEvent: event });

    if (event.RequestType == 'Delete') {
        response.send(event, context, response.SUCCESS);  //, { Delete: true, event } 
        return;
    }

    try {
        let params = {
            FunctionName: event.ResourceProperties.FunctionName,
            MaxItems: 999
        };
        // Use list-versions-by-function then determine the greatest version # and return it
        lambda.listVersionsByFunction(params, function (err, data) {
            console.log({ params, err });
            if (err) {
                console.error(err, err.stack); // an error occurred
                response.send(event, context, response.FAILED);
                return; // JSON.stringify({ error: err });
            } else {
                console.log(JSON.stringify({ Versions: data.Versions }));

                let version = data.Versions[data.Versions.length - 1].Version;
                if (version == '$LATEST') version = 1;
                let res = { version };
                response.send(event, context, response.SUCCESS, res);
                return; // JSON.stringify(res);
            }
        });

    } catch (err) {
        let error = { err, stack: err.stack };
        response.send(event, context, response.FAILED);
        return; // JSON.stringify({ error });
    }
}
rainabba
  • 3,804
  • 35
  • 35

0 Answers0