Skip to content

Commit

Permalink
feat(cloudfront): define lambda@edge as resolvable resource
Browse files Browse the repository at this point in the history
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
  • Loading branch information
KnisterPeter committed Jun 13, 2019
1 parent 849b693 commit c11b70c
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 7 deletions.
27 changes: 21 additions & 6 deletions packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,9 @@ export interface LambdaFunctionAssociation {
readonly eventType: LambdaEdgeEventType;

/**
* A version of the lambda to associate
* A version of the lambda to associate or a resolvable resource
*/
readonly lambdaFunction: lambda.IVersion;
readonly lambdaFunction: lambda.IVersion | cdk.IResolvable;
}

export enum LambdaEdgeEventType {
Expand Down Expand Up @@ -719,6 +719,10 @@ export class CloudFrontWebDistribution extends cdk.Construct implements IDistrib
}

private toBehavior(input: BehaviorWithOrigin, protoPolicy?: ViewerProtocolPolicy) {
function isResolvable(resolvableOrVersion: cdk.IResolvable | lambda.IVersion): resolvableOrVersion is cdk.IResolvable {
return Boolean((resolvableOrVersion as cdk.IResolvable).resolve);
}

let toReturn = {
allowedMethods: this.METHOD_LOOKUP_MAP[input.allowedMethods || CloudFrontAllowedMethods.GET_HEAD],
cachedMethods: this.METHOD_LOOKUP_MAP[input.cachedMethods || CloudFrontAllowedCachedMethods.GET_HEAD],
Expand All @@ -737,10 +741,21 @@ export class CloudFrontWebDistribution extends cdk.Construct implements IDistrib
if (input.lambdaFunctionAssociations) {
toReturn = Object.assign(toReturn, {
lambdaFunctionAssociations: input.lambdaFunctionAssociations
.map(fna => ({
eventType: fna.eventType,
lambdaFunctionArn: fna.lambdaFunction && fna.lambdaFunction.versionArn,
}))
.map(fna => {
if (!fna.lambdaFunction) {
return undefined;
}
if (isResolvable(fna.lambdaFunction)) {
return {
eventType: fna.eventType,
lambdaFunctionArn: fna.lambdaFunction,
};
}
return {
eventType: fna.eventType,
lambdaFunctionArn: fna.lambdaFunction.versionArn,
};
})
});
}
return toReturn;
Expand Down
167 changes: 166 additions & 1 deletion packages/@aws-cdk/aws-cloudfront/test/test.basic.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { expect } from '@aws-cdk/assert';
import lambda = require('@aws-cdk/aws-lambda');
import s3 = require('@aws-cdk/aws-s3');
import cdk = require('@aws-cdk/cdk');
import { Test } from 'nodeunit';
import { CloudFrontWebDistribution, ViewerProtocolPolicy } from '../lib';
import { CloudFrontWebDistribution, LambdaEdgeEventType, ViewerProtocolPolicy } from '../lib';

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

Expand Down Expand Up @@ -322,4 +323,168 @@ export = {
test.done();
},

'distribution with resolvable lambda-association'(test: Test) {
const stack = new cdk.Stack();
const sourceBucket = new s3.Bucket(stack, 'Bucket');

const lambdaFunction = new lambda.Function(stack, 'Lambda', {
code: lambda.Code.inline('foo'),
handler: 'index.handler',
runtime: lambda.Runtime.Nodejs810
});

const lambdaVersion = new lambda.Version(stack, 'LambdaVersion', {
lambda: lambdaFunction
});

new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', {
originConfigs: [
{
s3OriginSource: {
s3BucketSource: sourceBucket
},
behaviors: [
{
isDefaultBehavior: true,
lambdaFunctionAssociations: [{
eventType: LambdaEdgeEventType.OriginRequest,
lambdaFunction: cdk.Token.asAny(lambdaVersion.versionArn)
}]
}
]
}
]
});

expect(stack).toMatch({
"Resources": {
"Bucket83908E77": {
"Type": "AWS::S3::Bucket",
"DeletionPolicy": "Retain",
},
"LambdaServiceRoleA8ED4D3B": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": {
"Fn::Join": [
"",
[
"lambda.",
{
"Ref": "AWS::URLSuffix"
}
]
]
}
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
]
}
]
}
},
"LambdaD247545B": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"ZipFile": "foo"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"LambdaServiceRoleA8ED4D3B",
"Arn"
]
},
"Runtime": "nodejs8.10"
},
"DependsOn": [
"LambdaServiceRoleA8ED4D3B"
]
},
"LambdaVersionFA49E61E": {
"Type": "AWS::Lambda::Version",
"Properties": {
"FunctionName": {
"Ref": "LambdaD247545B"
}
}
},
"AnAmazingWebsiteProbablyCFDistribution47E3983B": {
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"DefaultRootObject": "index.html",
"Origins": [
{
"DomainName": {
"Fn::GetAtt": [
"Bucket83908E77",
"RegionalDomainName"
]
},
"Id": "origin1",
"S3OriginConfig": {}
}
],
"ViewerCertificate": {
"CloudFrontDefaultCertificate": true
},
"PriceClass": "PriceClass_100",
"DefaultCacheBehavior": {
"AllowedMethods": [
"GET",
"HEAD"
],
"CachedMethods": [
"GET",
"HEAD"
],
"TargetOriginId": "origin1",
"ViewerProtocolPolicy": "redirect-to-https",
"ForwardedValues": {
"QueryString": false,
"Cookies": { "Forward": "none" }
},
"LambdaFunctionAssociations": [
{
"EventType": "origin-request",
"LambdaFunctionARN": {
"Ref": "LambdaVersionFA49E61E"
}
}
]
},
"Enabled": true,
"IPV6Enabled": true,
"HttpVersion": "http2",
"CacheBehaviors": []
}
}
}
}
});
test.done();
},

};

0 comments on commit c11b70c

Please sign in to comment.