Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[aws-lambda] Function.prototype.currentVersion does not work with Code.fromCfnParameters #11433

Open
marcogrcr opened this issue Nov 11, 2020 · 6 comments
Labels
@aws-cdk/aws-lambda Related to AWS Lambda bug This issue is a bug. effort/small Small work item – less than a day of effort p2

Comments

@marcogrcr
Copy link

Function.prototype.currentVersion does not work when the code of the Lambda function is created using Code.fromCfnParameters(). Given that the logical id of the version changes based on md5 of the function configuration, a new version does not get created when the parameters of the stack change (since this happens at CloudFormation update time).

Reproduction Steps

const stack = new Stack();

const func = new Function(stack, "MyFunction", {
  runtime: Runtime.NODEJS_12_X,
  handler: "index.handler",
  code: Code.fromCfnParameters({
    bucketNameParam: new CfnParameter(stack, "CodeBucket"),
    objectKeyParam: new CfnParameter(stack, "CodeKey")
  })
});

console.log(func.currentVersion.node.uniqueId);

This will always print MyFunctionCurrentVersion7FAFE164 because the function configuration is static:

{
  "Resources": {
    "MyFunction3BAA72D1": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Code": {
          "S3Bucket": { "Ref": "CodeBucket" },
          "S3Key": { "Ref": "CodeKey" }
        },
        "Handler": "index.handler",
        "Role": {
          "Fn::GetAtt": [
            "MyFunctionServiceRole3C357FF2",
            "Arn"
          ]
        },
        "Runtime": "nodejs12.x"
      }
    }
  }
}

export function calculateFunctionHash(fn: LambdaFunction) {
const stack = Stack.of(fn);
const functionResource = fn.node.defaultChild as CfnResource;
// render the cloudformation resource from this function
const config = stack.resolve((functionResource as any)._toCloudFormation());
const hash = crypto.createHash('md5');
hash.update(JSON.stringify(config));
return hash.digest('hex');
}

What did you expect to happen?

Changing the parameters causes a new version to be created.

What actually happened?

Changing the parameters causes the lambda function to be updated, but a new version is not created.

Environment

  • CDK CLI Version : 1.73.0
  • Framework Version: 1.73.0
  • Node.js Version: 12.13.0
  • OS: macOS 10.14.6
  • Language (Version): TypeScript 4.0.3

Other

The deprecation of Function.prototype.addVersion() makes this confusing since it suggests Function.prototype.currentVersion is the way to do Lambda versioning for all cases.

* @deprecated This method will create an AWS::Lambda::Version resource which
* snapshots the AWS Lambda function *at the time of its creation* and it
* won't get updated when the function changes. Instead, use
* `this.currentVersion` to obtain a reference to a version resource that gets
* automatically recreated when the function configuration (or code) changes.
*/
public addVersion(

However, it does not apply to all cases as shown in this bug. The non-deprecated workaround I found was to create an instance of Version directy:

new Version(func, "Version" + Date.now().toString(), {
  lambda: func
});

This change was introduced in #6771 in response to #6750 and #5334


This is 🐛 Bug Report

@marcogrcr marcogrcr added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Nov 11, 2020
@github-actions github-actions bot added the @aws-cdk/aws-lambda Related to AWS Lambda label Nov 11, 2020
@nija-at
Copy link
Contributor

nija-at commented Nov 17, 2020

The challenge here is that it's not possible for the CDK to know at synthesis time that your parameter values are changing. They are configured at the time of deployment.

For this reason we recommend not using CloudFormation parameters. Instead, specify the s3 bucket and object names directly in your CDK app.
This way every time the object name changes, the CDK can generate a new version.

@nija-at nija-at added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Nov 17, 2020
@marcogrcr
Copy link
Author

Thanks for the reply, can you provide advise on how to adapt the official docs CI/CD pipeline example so that it doesn't use Code.fromCfnParameters()?

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Nov 18, 2020
@nija-at
Copy link
Contributor

nija-at commented Nov 24, 2020

You are right. We do have conflicting recommendations in our docs.
In the coming months, we'll be updating the official docs for CI/CD with use of CDK pipelines - https://github.com/aws/aws-cdk/tree/master/packages/%40aws-cdk/pipelines - once we get our final versions of the APIs in place.

Unfortunately, I still don't have a good solution to automatically recompute a new lambda version when the cloudformation parameter values change.

@nija-at nija-at added effort/medium Medium work item – several days of effort p1 and removed needs-triage This issue or PR still needs to be triaged. labels Nov 24, 2020
@nija-at
Copy link
Contributor

nija-at commented Sep 23, 2021

I don't think there is a way to fix this issue in the current design of the CDK.

Since the value of the CfnParameter is determined at deploy time (after the CDK has synthesized), the best we can do here is throw an error when CfnParameter is used to indicate that currentVersion is incompatible with this use.

@comcalvi
Copy link
Contributor

comcalvi commented Apr 29, 2022

I'm dropping this here, as this issue is still open. This is relevant discussion from an internal ticket that may help external users. For @marcogrcr's issue, simply creating the version directly is likely the simplest way to achieve the desired behavior, but this still may help other users. Credit @rix0rrr for penning this.

CloudFormation will not perform an update to ANY resource unless any of its Properties have a different value during the deployment. Failing that, you can also change the LogicalID of the resource, which is a bit more drastic (and requires you to have enough information at template generation time to do so---which we do not if the filename comes in via a CFN Parameter)

Armed with that information:

To make CloudFormation publish a new version, you will need to trigger a change to the properties of AWS::Lambda::Version as well, which are:

{
  "Type" : "AWS::Lambda::Version",
  "Properties" : {
      "CodeSha256" : String,
      "Description" : String,
      "FunctionName" : String,
      "ProvisionedConcurrencyConfig" : ProvisionedConcurrencyConfiguration
    }
}

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-version.html

The only way to do that in a sensible way is to make sure to pass the SHA256 of the code into the CodeSha256 field: when the code updates, that field will update and a new Version will be published.

You will have to sequence a Custom Resource in between the Function and the Version, that does a GetFunction call, gets the CodeSha256 out and returns it, and pass that into the CodeSha256 of the Version object.

I recommend AwsCustomResource, it will make it convenient(-ish) to sequence arbitrary AWS calls into your CFN deployment: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.custom_resources.AwsCustomResource.html

Be sure to work a timestamp into either one of the properties of the AWS Custom Resource or its logical ID, to make sure it executes on every deployment (otherwise it will only execute once because of the rule I mentioned above).

Alternatively, you might try to work the S3 path into the Description of the Version: that might or might not work, depends on how CloudFormation implements the Version resource.

@madeline-k
Copy link
Contributor

Next steps for this issue would be to take Niranjan's suggestion:

the best we can do here is throw an error when CfnParameter is used to indicate that currentVersion is incompatible with this use.

Then convert to a discussion so that this information is available to folks. But it's not something we will be able to address by changing the Function or LayerVersion constructs.

@madeline-k madeline-k added effort/small Small work item – less than a day of effort and removed effort/medium Medium work item – several days of effort labels Jan 26, 2023
@colifran colifran added p1.5 and removed p1 labels May 15, 2023
@otaviomacedo otaviomacedo added p2 and removed p1.5 labels May 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-lambda Related to AWS Lambda bug This issue is a bug. effort/small Small work item – less than a day of effort p2
Projects
None yet
Development

No branches or pull requests

6 participants