diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 5e8cf4c825218..304c0ed6daf41 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -90,4 +90,4 @@ "node": ">= 8.10.0" }, "stability": "experimental" -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-cloudfront/test/test.basic.ts b/packages/@aws-cdk/aws-cloudfront/test/test.basic.ts index 77b7db5a890f7..76bff5d7d244d 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/test.basic.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/test.basic.ts @@ -1,8 +1,9 @@ -import { expect } from '@aws-cdk/assert'; +import { expect, haveResourceLike } from '@aws-cdk/assert'; +import * as lambda from '@aws-cdk/aws-lambda'; import s3 = require('@aws-cdk/aws-s3'); import cdk = require('@aws-cdk/core'); import { Test } from 'nodeunit'; -import { CloudFrontWebDistribution, ViewerProtocolPolicy } from '../lib'; +import { CloudFrontWebDistribution, LambdaEdgeEventType, ViewerProtocolPolicy } from '../lib'; // tslint:disable:object-literal-key-quotes @@ -321,4 +322,58 @@ 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.SingletonFunction(stack, 'Lambda', { + uuid: 'xxxx-xxxx-xxxx-xxxx', + code: lambda.Code.inline('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_8_10 + }); + + new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket + }, + behaviors: [ + { + isDefaultBehavior: true, + lambdaFunctionAssociations: [{ + eventType: LambdaEdgeEventType.ORIGIN_REQUEST, + lambdaFunction: lambdaFunction.latestVersion + }] + } + ] + } + ] + }); + + expect(stack).to(haveResourceLike('AWS::CloudFront::Distribution', { + "DistributionConfig": { + "DefaultCacheBehavior": { + "LambdaFunctionAssociations": [ + { + "EventType": "origin-request", + "LambdaFunctionARN": { + "Fn::Join": [ + "", + [ + { "Fn::GetAtt": [ "SingletonLambdaxxxxxxxxxxxxxxxx69D4268A", "Arn" ] }, + ":$LATEST" + ] + ] + } + } + ], + }, + } + })); + + test.done(); + }, + }; diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index 42e30270cf0f9..f0aee24953e5f 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -1,5 +1,6 @@ import cloudwatch = require('@aws-cdk/aws-cloudwatch'); -import { Construct } from '@aws-cdk/core'; +import { Construct, Fn } from '@aws-cdk/core'; +import { Function } from './function'; import { IFunction, QualifiedFunctionBase } from './function-base'; import { CfnVersion } from './lambda.generated'; @@ -72,6 +73,30 @@ export interface VersionAttributes { */ export class Version extends QualifiedFunctionBase implements IVersion { + /** + * Construct a Version object from a Version ARN. + * + * @param scope The cdk scope creating this resource + * @param id The cdk id of this resource + * @param versionArn The version ARN to create this version from + */ + public static fromVersionArn(scope: Construct, id: string, versionArn: string): IVersion { + const version = extractVersionFromArn(versionArn); + const lambda = Function.fromFunctionArn(scope, `${id}Function`, versionArn); + + class Import extends QualifiedFunctionBase implements IVersion { + public readonly version = version; + public readonly lambda = lambda; + public readonly functionName = `${lambda.functionName}:${version}`; + public readonly functionArn = versionArn; + public readonly grantPrincipal = lambda.grantPrincipal; + public readonly role = lambda.role; + + protected readonly canCreatePermissions = false; + } + return new Import(scope, id); + } + public static fromVersionAttributes(scope: Construct, id: string, attrs: VersionAttributes): IVersion { class Import extends QualifiedFunctionBase implements IVersion { public readonly version = attrs.version; @@ -131,3 +156,20 @@ export class Version extends QualifiedFunctionBase implements IVersion { }); } } + +/** + * Given an opaque (token) ARN, returns a CloudFormation expression that extracts the version + * name from the ARN. + * + * Version ARNs look like this: + * + * arn:aws:lambda:region:account-id:function:function-name:version + * + * ..which means that in order to extract the `version` component from the ARN, we can + * split the ARN using ":" and select the component in index 7. + * + * @returns `FnSelect(7, FnSplit(':', arn))` + */ +function extractVersionFromArn(arn: string) { + return Fn.select(7, Fn.split(':', arn)); +} diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts new file mode 100644 index 0000000000000..b373db4a7ddba --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts @@ -0,0 +1,33 @@ +import { expect } from '@aws-cdk/assert'; +import cdk = require('@aws-cdk/core'); +import { Test } from 'nodeunit'; +import lambda = require('../lib'); + +// tslint:disable:object-literal-key-quotes + +export = { + 'can import a Lambda version by ARN'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const version = lambda.Version.fromVersionArn(stack, 'Version', 'arn:aws:lambda:region:account-id:function:function-name:version'); + + new cdk.CfnOutput(stack, 'ARN', { value: version.functionArn }); + new cdk.CfnOutput(stack, 'Name', { value: version.functionName }); + + // THEN + expect(stack).toMatch({ + Outputs: { + ARN: { + Value: "arn:aws:lambda:region:account-id:function:function-name:version" + }, + Name: { + Value: "function-name:version" + } + } + }); + + test.done(); + }, +}; \ No newline at end of file