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

fix(lambda-nodejs): NodejsFunction construct incompatible with lambda@edge #9562

Merged
merged 17 commits into from
Aug 19, 2020

Conversation

jogold
Copy link
Contributor

@jogold jogold commented Aug 10, 2020

Check version and function compatibility when a Lambda is used for
Lambda@Edge. Environment variables can be marked as "removable" when
used for Lambda@Edge.

Closes #9328
Closes #9453


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

jogold added 3 commits August 10, 2020 13:23
…at edge

Automatically remove environment variables of a Lambda function when
it's used at edge. A warning is also shown.

Works with singleton functions.

Closes aws#9328
Closes aws#9453
Comment on lines 56 to 58
if (edgeLambda.functionVersion.lambda.removeEnvironment()) {
edgeLambda.functionVersion.lambda.node.addWarning(`Removed environment variables from function ${edgeLambda.functionVersion.lambda.node.path} because Lambda@Edge does not support environment variables`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to surprise customers who are not aware of this limitation and expect their environment variables to show up.

How about removing environment variables that the CDK inserts, and throwing an error when the customer has environment variables configured?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also (FYI), the addWarning API was just deprecated yesterday (#9563) as part of prep work for CDK 2.0 (Design).

In the future, you'd use:

Suggested change
if (edgeLambda.functionVersion.lambda.removeEnvironment()) {
edgeLambda.functionVersion.lambda.node.addWarning(`Removed environment variables from function ${edgeLambda.functionVersion.lambda.node.path} because Lambda@Edge does not support environment variables`);
}
if (edgeLambda.functionVersion.lambda.removeEnvironment()) {
Annotations.of(edgeLambda.functionVersion.lambda).addWarning(`Removed environment variables from function ${edgeLambda.functionVersion.lambda.node.path} because Lambda@Edge does not support environment variables`);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nija-at
This means that we need to identify env vars inserted by CDK? You would like to add a special method (addCdkEnvironment()) and prop (cdkEnvironment) to identify those? Doesn't it require "developer discipline" inside the CDK?

Also consider the following use case outside the CDK: you have a construct that creates your special Lambda with a defined lists of env vars (whether used in the runtime code or not, like STAGE for example) and other good defaults. You want to use it both at edge and not.

@njlynch
saw #9563 but unfortunately Annotations has not been exported in core/lib/index.ts in this PR. Will be done when all node.addXxx() methods will be updated in the constructs library I presume.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair @jogold.

In your example, if I understand the lambda@edge limitation correctly, the special lambda function in the construct may not work at edge if it relies on certain env vars being present.

In this case, does it make sense instead to have a property allowInEdgeEnv or edgeEnvOptimized or something similar (false by default), that strips out env vars when used in edge environment, and errors out otherwise?

This can be used to encode similar behaviour for other lambda@edge limitations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nija-at how about the following?

  • add a get edgeArn() getter on IVersion: in there we can check that the version is "compatible" for Lambda@Edge and throw otherwise, let's start with env vars only in this PR (+ the check that it's not $LATEST)
  • call this get edgeArn() in aws-cloudfront instead of doing lambdaFunctionArn: edgeLambda.functionVersion.functionArn => lambdaFunctionArn: edgeLambda.functionVersion.edgeArn.
  • add a third parameter allowEdgeRemoval to addEnvironment() so that we can loop over the env vars in get edgeArn(), remove the env vars that we're allowed to and throw if anything remains (with a clear message saying that addEnvironment() can be used to overcome it). allowEdgeRemoval will be set to true in the call to addEnvironment() in aws-lambda-nodejs

Copy link
Contributor

@nija-at nija-at Aug 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach looks reasonable to me.

Minor tweaks - make the third parameter to addEnvironment() - EnvironmentOptions - which holds the property removeInEdge (or something like that).

@jogold jogold changed the title fix(cloudfront,lambda): remove env vars when Lambda function is used at edge fix(cloudfront,lambda): version and function compatibility with Lambda@Edge Aug 13, 2020
@mergify mergify bot dismissed nija-at’s stale review August 13, 2020 15:09

Pull request has been modified.

packages/@aws-cdk/aws-lambda/lib/function.ts Outdated Show resolved Hide resolved
Comment on lines 116 to 119
/**
* Checks whether this function is compatible for Lambda@Edge.
*/
checkEdgeCompatibility(): void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have you added this API to IFunction? Is there value in exposing this to users?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the underlying Lambda of a version is an IFunction. For the same reason, I had to make checkEdgeCompatibility() public. Do you see a workaround?

Copy link
Contributor

@nija-at nija-at Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I was not able to follow your response. Can you expand a bit more?

If we wanted it to be on a base class so that it's available on all implementations, we could make it a protected abstract method on FunctionBase and mark it as @internal?
At the calling point check on instanceof and call this internal method. We do that in a few places in the CDK, like here.

Copy link
Contributor Author

@jogold jogold Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK with instanceof I can move this method to Function but it will remain public since I need to call it from a Version on its underlying Lambda?

We don't need this method on FunctionBase because an imported Lambda will always be considered to be compatible?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's moved to FunctionBase and marked @internal, keeping it as public is fine.

Copy link
Contributor Author

@jogold jogold Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also do you prefer the Symbol implementation (vs instanceof Function)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's my preference but not strongly.
The value of the symbol based implementation will diminish over the next few months with our upcoming move to monolithic packaging.

Copy link
Contributor Author

@jogold jogold Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's my preference but not strongly.

Went for the instanceof implementation because FunctionBase has currently no constructor and didn't want to add one.

_checkEdgeCompatibility() is on FunctionBase to handle singleton functions.

packages/@aws-cdk/aws-lambda/lib/function.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-lambda/lib/function.ts Outdated Show resolved Hide resolved
@@ -760,27 +762,43 @@ export class Function extends FunctionBase {
return this._logGroup;
}

public checkEdgeCompatibility(): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this private instead?

packages/@aws-cdk/aws-lambda/lib/function.ts Outdated Show resolved Hide resolved
Co-authored-by: Niranjan Jayakar <nija@amazon.com>
@mergify mergify bot dismissed nija-at’s stale review August 17, 2020 13:52

Pull request has been modified.

@@ -426,8 +426,7 @@ nodeunitShim({
const stack = new cdk.Stack();
const sourceBucket = new s3.Bucket(stack, 'Bucket');

const lambdaFunction = new lambda.SingletonFunction(stack, 'Lambda', {
Copy link
Contributor Author

@jogold jogold Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to move from a SingletonFunction to Function because SingletonFunction has no addVersion() it's a FunctionBase. This test was actually incorrect because it associated a latest version with a CF distribution.

SingletonFunction now has a _checkEdgeCompatibility() but no addVersion() yet, for this PR?

@nija-at nija-at changed the title fix(cloudfront,lambda): version and function compatibility with Lambda@Edge fix(lambda-nodejs): NodejsFunction construct incompatible with lambda@edge Aug 19, 2020
Copy link
Contributor

@nija-at nija-at left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jogold - looks good. Just a couple of things below.

I've also reworded the commit title to focus on the NodejsFunction construct since that seems to be the primary benefit of this change.

};
})
? this.props.edgeLambdas.map(edgeLambda => ({
lambdaFunctionArn: Lazy.stringValue({ produce: () => edgeLambda.functionVersion.edgeArn }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edgeArn must always be lazily processed. Would be better to move the Lazy.stringValue() block into the getter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed better, 👍

@mergify mergify bot dismissed nija-at’s stale review August 19, 2020 13:43

Pull request has been modified.

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject6AEA49D1-qxepHUsryhcu
  • Commit ID: deed339
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify
Copy link
Contributor

mergify bot commented Aug 19, 2020

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@mergify mergify bot merged commit dfe2c5c into aws:master Aug 19, 2020
@jogold jogold deleted the lambda-edge-remove-env branch August 19, 2020 14:15
misterjoshua pushed a commit to misterjoshua/aws-cdk that referenced this pull request Aug 19, 2020
…@edge (aws#9562)

Check version and function compatibility when a Lambda is used for
Lambda@Edge. Environment variables can be marked as "removable" when
used for Lambda@Edge.

Closes aws#9328
Closes aws#9453


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
jogold added a commit to jogold/aws-cdk that referenced this pull request Aug 21, 2020
Add `currentVersion` for singleton functions. This makes it possible to
use them for Lambda@Edge.

Also remove deprecated calls to `addVersion()` introduced in aws#9562.
mergify bot pushed a commit that referenced this pull request Aug 26, 2020
Add `currentVersion` for singleton functions. This makes it possible to
use them for Lambda@Edge.

To achieve this, make `ensureLambda()` return a `Function` and not an `IFunction`
(which now allows to remove the default implementation of `_checkEdgeCompatibilty()`
in `FunctionBase`).

Also remove deprecated calls to `addVersion()` introduced in #9562.


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[lambda] Identify lambda@edge does not support environment variables
4 participants