From d3f54ea62f5c85545cdbfd2af80ce2eb3dc361f7 Mon Sep 17 00:00:00 2001 From: Eetu Tuomala Date: Thu, 1 Mar 2018 07:58:11 +0200 Subject: [PATCH] refactor origin and behavior indexing --- lib/plugins/aws/lib/naming.js | 7 ++ .../compile/events/cloudFront/index.js | 86 +++++++++++-------- 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js index 71e0f524d..b8e70c5a1 100644 --- a/lib/plugins/aws/lib/naming.js +++ b/lib/plugins/aws/lib/naming.js @@ -518,4 +518,11 @@ module.exports = { getLambdaAtEdgeInvokePermissionLogicalId(functionName) { return `${this.getLambdaLogicalId(functionName)}InvokePermission`; }, + getCloudFrontOriginId(functionName, path) { + let originId = this.getNormalizedFunctionName(functionName); + if (typeof path !== 'undefined') { + originId = `${originId}${path}`; + } + return originId; + }, }; diff --git a/lib/plugins/aws/package/compile/events/cloudFront/index.js b/lib/plugins/aws/package/compile/events/cloudFront/index.js index 339562637..19544d2c9 100644 --- a/lib/plugins/aws/package/compile/events/cloudFront/index.js +++ b/lib/plugins/aws/package/compile/events/cloudFront/index.js @@ -5,7 +5,7 @@ const { URL } = require('url'); const chalk = require('chalk'); // helper function for joining origins and behaviors -const extendDeep = (object, source) => { +const extendDeep = (object, source) => _.assignWith(object, source, (a, b) => { if (_.isArray(a)) { return _.uniq(a.concat(b)); @@ -15,7 +15,7 @@ const extendDeep = (object, source) => { } return a; }); -}; + class AwsCompileCloudFrontEvents { constructor(serverless) { this.serverless = serverless; @@ -44,12 +44,14 @@ class AwsCompileCloudFrontEvents { this.provider.naming.getCloudFrontDistributionDomainNameLogicalId(); const lambdaAtEdgeFunctions = []; + + const origins = []; + const behaviors = []; + const { Resources, Outputs } = this.serverless.service.provider.compiledCloudFormationTemplate; function createOrigin(functionName, origin, naming) { - const originObj = { - Id: naming.getNormalizedFunctionName(functionName), - }; + const originObj = {}; if (typeof origin === 'string') { const originUrl = new URL(origin); _.merge(originObj, { @@ -73,6 +75,9 @@ class AwsCompileCloudFrontEvents { _.merge(originObj, origin); } + _.merge(originObj, { + Id: naming.getCloudFrontOriginId(functionName, originObj.OriginPath), + }); return originObj; } @@ -95,9 +100,21 @@ class AwsCompileCloudFrontEvents { ? event.cloudFront.pathPattern : undefined; - const behavior = { + let origin = + createOrigin(functionName, event.cloudFront.origin, this.provider.naming); + + const existingOrigin = + _.find(origins, o => o.OriginPath === origin.OriginPath); + + if (typeof existingOrigin === 'undefined') { + origins.push(origin); + } else { + origin = extendDeep(existingOrigin, origin); + } + + let behavior = { ViewerProtocolPolicy: 'allow-all', - TargetOriginId: this.provider.naming.getNormalizedFunctionName(functionName), + TargetOriginId: origin.Id, ForwardedValues: { QueryString: false, }, @@ -109,21 +126,36 @@ class AwsCompileCloudFrontEvents { }], }; - if (typeof pathPattern !== undefined) { + if (typeof pathPattern !== 'undefined') { _.merge(behavior, { PathPattern: pathPattern }); } - const origin = - createOrigin(functionName, event.cloudFront.origin, this.provider.naming); + const existingBehaviour = + _.find(behaviors, o => + o.PathPattern === behavior.PathPattern + && o.TargetOriginId === behavior.TargetOriginId); - lambdaAtEdgeFunctions.push(_.merge({ - cloudFront: { origin, behavior } }, + if (typeof existingBehaviour === 'undefined') { + behaviors.push(behavior); + } else { + behavior = extendDeep(existingBehaviour, behavior); + } + + lambdaAtEdgeFunctions.push(_.merge({}, functionObj, { functionName, lambdaVersionLogicalId })); } }); } }); + // sort that first is without PathPattern if available + behaviors.sort((a, b) => { + if (b.PathPattern) { + return -1; + } + return 0; + }); + if (lambdaAtEdgeFunctions.length > 0) { if (this.provider.getRegion() !== 'us-east-1') { throw new @@ -205,17 +237,7 @@ class AwsCompileCloudFrontEvents { } const CacheBehaviors = - lambdaAtEdgeFunctions - .filter(({ cloudFront }) => !!cloudFront.behavior.PathPattern) - .map(({ cloudFront }) => cloudFront.behavior) - .reduce((result, behaviour) => { - const existingBehaviour = _.find(result, { PathPattern: behaviour.PathPattern }); - if (typeof existingBehaviour !== 'undefined') { - extendDeep(existingBehaviour, behaviour); - return result; - } - return result.concat(behaviour); - }, []); + behaviors.slice(1); const CloudFrontDistribution = { Type: 'AWS::CloudFront::Distribution', @@ -223,25 +245,13 @@ class AwsCompileCloudFrontEvents { DistributionConfig: { Comment: `${this.serverless.service.service} ${this.serverless.service.provider.stage}`, Enabled: true, - DefaultCacheBehavior: - lambdaAtEdgeFunctions - .filter(({ cloudFront }) => !cloudFront.behavior.PathPattern) - .map(({ cloudFront }) => cloudFront.behavior)[0], - Origins: lambdaAtEdgeFunctions - .map(({ cloudFront }) => cloudFront.origin) - .reduce((result, origin) => { - const existingOrigin = _.find(result, { OriginPath: origin.OriginPath }); - if (typeof existingOrigin !== 'undefined') { - extendDeep(existingOrigin, origin); - return result; - } - return result.concat(origin); - }, []), + DefaultCacheBehavior: behaviors[0], + Origins: origins, }, }, }; - if (typeof CacheBehaviors !== 'undefined') { + if (CacheBehaviors.length > 0) { _.merge(CloudFrontDistribution.Properties.DistributionConfig, { CacheBehaviors }); }