Skip to content

Commit c39d659

Browse files
KnisterPetermergify[bot]
authored andcommitted
feat(cloudfront): define lambda@edge as resolvable resource (#2861)
* feat(cloudfront): define lambda@edge as resolvable resource This declaration is required for deploying custom resources as lamdba association, which by itself is required to deploy a lambda@edge for a stack which is in a different region as 'us-east-1'. Relates to #1575 * test: simplified test case by just test resources required for the case * feat: allow to create a version from an arn This commit allows to reference a lambda from a different region and use that as function association. * refactor: resolve conflicts * refactor: update based on review * refactor: use version arn as function arn * Fixing package.json * Fix tests
1 parent c92e9a9 commit c39d659

File tree

4 files changed

+134
-4
lines changed

4 files changed

+134
-4
lines changed

packages/@aws-cdk/aws-cloudfront/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,4 @@
9090
"node": ">= 8.10.0"
9191
},
9292
"stability": "experimental"
93-
}
93+
}

packages/@aws-cdk/aws-cloudfront/test/test.basic.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { expect } from '@aws-cdk/assert';
1+
import { expect, haveResourceLike } from '@aws-cdk/assert';
2+
import * as lambda from '@aws-cdk/aws-lambda';
23
import s3 = require('@aws-cdk/aws-s3');
34
import cdk = require('@aws-cdk/core');
45
import { Test } from 'nodeunit';
5-
import { CloudFrontWebDistribution, ViewerProtocolPolicy } from '../lib';
6+
import { CloudFrontWebDistribution, LambdaEdgeEventType, ViewerProtocolPolicy } from '../lib';
67

78
// tslint:disable:object-literal-key-quotes
89

@@ -321,4 +322,58 @@ export = {
321322
test.done();
322323
},
323324

325+
'distribution with resolvable lambda-association'(test: Test) {
326+
const stack = new cdk.Stack();
327+
const sourceBucket = new s3.Bucket(stack, 'Bucket');
328+
329+
const lambdaFunction = new lambda.SingletonFunction(stack, 'Lambda', {
330+
uuid: 'xxxx-xxxx-xxxx-xxxx',
331+
code: lambda.Code.inline('foo'),
332+
handler: 'index.handler',
333+
runtime: lambda.Runtime.NODEJS_8_10
334+
});
335+
336+
new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', {
337+
originConfigs: [
338+
{
339+
s3OriginSource: {
340+
s3BucketSource: sourceBucket
341+
},
342+
behaviors: [
343+
{
344+
isDefaultBehavior: true,
345+
lambdaFunctionAssociations: [{
346+
eventType: LambdaEdgeEventType.ORIGIN_REQUEST,
347+
lambdaFunction: lambdaFunction.latestVersion
348+
}]
349+
}
350+
]
351+
}
352+
]
353+
});
354+
355+
expect(stack).to(haveResourceLike('AWS::CloudFront::Distribution', {
356+
"DistributionConfig": {
357+
"DefaultCacheBehavior": {
358+
"LambdaFunctionAssociations": [
359+
{
360+
"EventType": "origin-request",
361+
"LambdaFunctionARN": {
362+
"Fn::Join": [
363+
"",
364+
[
365+
{ "Fn::GetAtt": [ "SingletonLambdaxxxxxxxxxxxxxxxx69D4268A", "Arn" ] },
366+
":$LATEST"
367+
]
368+
]
369+
}
370+
}
371+
],
372+
},
373+
}
374+
}));
375+
376+
test.done();
377+
},
378+
324379
};

packages/@aws-cdk/aws-lambda/lib/lambda-version.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import cloudwatch = require('@aws-cdk/aws-cloudwatch');
2-
import { Construct } from '@aws-cdk/core';
2+
import { Construct, Fn } from '@aws-cdk/core';
3+
import { Function } from './function';
34
import { IFunction, QualifiedFunctionBase } from './function-base';
45
import { CfnVersion } from './lambda.generated';
56

@@ -72,6 +73,30 @@ export interface VersionAttributes {
7273
*/
7374
export class Version extends QualifiedFunctionBase implements IVersion {
7475

76+
/**
77+
* Construct a Version object from a Version ARN.
78+
*
79+
* @param scope The cdk scope creating this resource
80+
* @param id The cdk id of this resource
81+
* @param versionArn The version ARN to create this version from
82+
*/
83+
public static fromVersionArn(scope: Construct, id: string, versionArn: string): IVersion {
84+
const version = extractVersionFromArn(versionArn);
85+
const lambda = Function.fromFunctionArn(scope, `${id}Function`, versionArn);
86+
87+
class Import extends QualifiedFunctionBase implements IVersion {
88+
public readonly version = version;
89+
public readonly lambda = lambda;
90+
public readonly functionName = `${lambda.functionName}:${version}`;
91+
public readonly functionArn = versionArn;
92+
public readonly grantPrincipal = lambda.grantPrincipal;
93+
public readonly role = lambda.role;
94+
95+
protected readonly canCreatePermissions = false;
96+
}
97+
return new Import(scope, id);
98+
}
99+
75100
public static fromVersionAttributes(scope: Construct, id: string, attrs: VersionAttributes): IVersion {
76101
class Import extends QualifiedFunctionBase implements IVersion {
77102
public readonly version = attrs.version;
@@ -131,3 +156,20 @@ export class Version extends QualifiedFunctionBase implements IVersion {
131156
});
132157
}
133158
}
159+
160+
/**
161+
* Given an opaque (token) ARN, returns a CloudFormation expression that extracts the version
162+
* name from the ARN.
163+
*
164+
* Version ARNs look like this:
165+
*
166+
* arn:aws:lambda:region:account-id:function:function-name:version
167+
*
168+
* ..which means that in order to extract the `version` component from the ARN, we can
169+
* split the ARN using ":" and select the component in index 7.
170+
*
171+
* @returns `FnSelect(7, FnSplit(':', arn))`
172+
*/
173+
function extractVersionFromArn(arn: string) {
174+
return Fn.select(7, Fn.split(':', arn));
175+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { expect } from '@aws-cdk/assert';
2+
import cdk = require('@aws-cdk/core');
3+
import { Test } from 'nodeunit';
4+
import lambda = require('../lib');
5+
6+
// tslint:disable:object-literal-key-quotes
7+
8+
export = {
9+
'can import a Lambda version by ARN'(test: Test) {
10+
// GIVEN
11+
const stack = new cdk.Stack();
12+
13+
// WHEN
14+
const version = lambda.Version.fromVersionArn(stack, 'Version', 'arn:aws:lambda:region:account-id:function:function-name:version');
15+
16+
new cdk.CfnOutput(stack, 'ARN', { value: version.functionArn });
17+
new cdk.CfnOutput(stack, 'Name', { value: version.functionName });
18+
19+
// THEN
20+
expect(stack).toMatch({
21+
Outputs: {
22+
ARN: {
23+
Value: "arn:aws:lambda:region:account-id:function:function-name:version"
24+
},
25+
Name: {
26+
Value: "function-name:version"
27+
}
28+
}
29+
});
30+
31+
test.done();
32+
},
33+
};

0 commit comments

Comments
 (0)