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): Use Alias ARN directly #2091

Merged
merged 7 commits into from
Mar 28, 2019
Merged

fix(lambda): Use Alias ARN directly #2091

merged 7 commits into from
Mar 28, 2019

Conversation

RomainMuller
Copy link
Contributor

Use the Alias resource's ARN instead of building one using Fn::Join, so
that referencing the ARN implies a dependency on the alias.

Additionally, forward the underlying function's role to the Alias' role
property.

Fixes #2084

Use the Alias resource's ARN instead of building one using Fn::Join, so
that referencing the ARN implies a dependency on the alias.

Additionally, forward the underlying function's role to the Alias' role
property.
@RomainMuller RomainMuller requested a review from a team as a code owner March 26, 2019 08:21
Copy link
Contributor

@eladb eladb left a comment

Choose a reason for hiding this comment

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

Test please?

@@ -95,8 +89,14 @@ export class Alias extends FunctionBase {

// Not actually the name, but an ARN can be used in all places
// where the name is expected, and an ARN can refer to an Alias.
this.functionName = `${props.version.lambda.functionArn}:${props.aliasName}`;
this.functionArn = `${props.version.lambda.functionArn}:${props.aliasName}`;
this.functionName = this.functionArn = alias.aliasArn;
Copy link
Contributor

Choose a reason for hiding this comment

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

functionName is a horrible name here. It always was, of course, but can we please fix this before we 1.0 this accidentally?

Can you do me a favour and extend the scope of this PR slightly to add invokeArn: string to IFunction ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd actually want to keep the actual Function Name (and make the Alias' one actually a name - like ${this. underlyingLambda.functionName}:${props.aliasName}, or parsing it out the Alias' functionArn even).

Having the name can be useful if you want to include it in a Dashboard or something... And functionArn is your invokeArn.

Copy link
Contributor

@sam-goodwin sam-goodwin Mar 26, 2019

Choose a reason for hiding this comment

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

Is the following configuration appropriate?

on lambda.Function:

  • functionName is the actual function name
  • functionArn is the function ARN
  • invokeArn is also the functionArn

on lambda.Alias:

  • functionName is the underlying function name
  • functionArn is the underlying function ARN
  • invokeArn is the alias's ARN
  • aliasArn (not on IFunction) is another reference to invokeArn

Copy link
Contributor

Choose a reason for hiding this comment

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

Diving deeper into this, I agree with @RomainMuller that invokeArn doesn't make sense.

Looking at the documentation for FunctionName on AWS::Lambda::Permission

The name (physical ID), Amazon Resource Name (ARN), or alias ARN of the Lambda function that you want to associate with this statement. Lambda adds this statement to the function's access policy.

This suggests we shouldn't forward the addPermission call to the underlying lambda function - we should use the aliasArn for the functionName when constructing the AWS::Lambda::Permission:

https://github.com/awslabs/aws-cdk/blob/4e105a3904c6bd91f66d60e2d77ab42afe36549b/packages/%40aws-cdk/aws-lambda/lib/function-base.ts#L175-L182

The documentation for Versioning, Aliases, and Permissions suggests that we should include the aliasName in the Alias's functionName:

Assuming that you grant permission, the next question is, "can an event source invoke a function version using any of the associated ARNs?" The answer is, it depends on how you identified function in your add permissions request (see AddPermission). The key to understanding this is that the permission you grant apply only to the ARN used in the add permission request:

Specifically,

If you use an alias name (such as helloworld:BETA), the permission is valid only for invoking the helloworld function using the BETA alias ARN (using any other ARNs results in a permission error, including the function version ARN to which the alias points).

I suggest the following:

lambda.Function:

  • functionName is the actual function name (Ref).
  • functionArn is the function ARN

lambda.Alias:

  • functionName is ${underlyingFunction.functionName}:${aliasName}
  • functionArn is the alias ARN
  • No specialized behavior for addPermission - don't forward to underlying lambda.
  • Specialized behavior for metric so the alias's ARN is included in the dimensions:
{
  FunctionName: this.underlyingLambda.functionName,
  Resource: this.functionArn // alias ARN
}

as opposed to (see lambda-augmented.generated.ts):

dimensions: { FunctionName: this.functionName },

lambda.FunctionBase:

  • Use this.functionArn as the functionName when creating permissions

Copy link
Contributor

Choose a reason for hiding this comment

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

And functionArn is your invokeArn.

Yes, except all Lambda APIs where you pass in what Lambda to invoke, call the argument functionName (because it accepts both name and ARN, but they named the field after the trivial case).

So this means that everywhere you want to invoke a Lambda you now need to do:

new ConstructThatCallsLambda(this, {
  functionName: myFunctionLike.functionArn  // <-- Resist typing functionName here, which looks correct but is wrong!
});

Maybe then we call it functionInvokeName or something.

Copy link
Contributor

Choose a reason for hiding this comment

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

  • functionName is ${underlyingFunction.functionName}:${aliasName}

This needs a mechanism to add a dependency from the consumer to the alias then, probably hooking into Token in some way. Maybe Elad was right about references needing a generic callback, we could have used that :).

  • Specialized behavior for metric so the alias's ARN is included in the dimensions:

Looking at the metrics in beta right now, I don't see Alias names in the metrics, just plain function names. Where did you get that the Alias name is used in the metrics?

packages/@aws-cdk/aws-lambda/lib/alias.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-lambda/lib/alias.ts Outdated Show resolved Hide resolved
@sam-goodwin sam-goodwin self-assigned this Mar 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SQS Event Source on Alias has race condition
5 participants