From 736b4d8e19e1e81e5b0cdb488e8c009fe36eac4a Mon Sep 17 00:00:00 2001 From: Allegra Chen Date: Thu, 29 Oct 2020 14:31:42 -0400 Subject: [PATCH 1/2] feat: Add multiple invalidations based on stages Before this commit, `cloudfrontInvalidation` was a single object under the `custom` section of serverless.yml file. There was no possible way to create invalidations for multiple CloudFront distributions. Therefore, the `cloudfrontInvalidation` object is turned into a list that can contain multiple distributions. index.js file is modified to realize this feature. The function body in `invalidate()` is moved into `...cloudfrontInvalidation.forEach()` Besides, an option of create invalidations based on deployment stages was also not available. Hence, an optional `stage` property is added for each distribution element. An if statement that checks for `stage` property declaration and its matching with the provider's stage is added into `invalidate()` in index.js file. The Setup example of `cloudfrontInvalidation` as a list and the Setup example of using the `stage` property of the elements of `cloudfrontInvalidation` is added to README.md file. Modified files: - index.js - README.md --- README.md | 16 ++++++++--- index.js | 81 ++++++++++++++++++++++++++++++------------------------- 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 43a6c1b..d8f09b3 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,18 @@ If the CDN is created as part of same serverless.yml then you can specify the `d ```yaml custom: cloudfrontInvalidate: - distributionId: "CLOUDFRONT_DIST_ID" #conditional, distributionId or distributionIdKey is required. - distributionIdKey: "CDNDistributionId" #conditional, distributionId or distributionIdKey is required. - items: # one or more paths required - - "/index.html" + - distributionId: "CLOUDFRONT_DIST_ID" #conditional, distributionId or distributionIdKey is required. + distributionIdKey: "CDNDistributionId" #conditional, distributionId or distributionIdKey is required. + items: # one or more paths required + - "/index.html" + stage: "dev" # conditional, the stage that this cloudfront invalidation should be created + # this should match the provider's stage you declared, e.g. "dev" but not "development" in this case + # an invalidation for this distribution will be created when executing `sls deploy --stage dev` + - distributionId: "CLOUDFRONT_DIST_ID" #conditional, distributionId or distributionIdKey is required. + distributionIdKey: "CDNDistributionId" #conditional, distributionId or distributionIdKey is required. + items: # one or more paths required + - "/index.html" + # `stage` is omitted, an invalidation will be created for this distribution at all stages resources: Resources: CDN: diff --git a/index.js b/index.js index e0cd031..368ae01 100644 --- a/index.js +++ b/index.js @@ -57,23 +57,23 @@ class CloudfrontInvalidate { } this.aws.sdk.config.update({ - httpOptions: { agent: new https.Agent({ ca: fs.readFileSync(caCert)}) } + httpOptions: { agent: new https.Agent({ ca: fs.readFileSync(caCert) }) } }); cli.consoleLog(`CloudfrontInvalidate: ${chalk.yellow('ca cert handling enabled')}`); } - createInvalidation(distributionId, reference) { + createInvalidation(distributionId, reference, cloudfrontInvalidate) { const cli = this.serverless.cli; - const cloudfrontInvalidateItems = this.serverless.service.custom.cloudfrontInvalidate.items; + const cloudfrontInvalidateItems = cloudfrontInvalidate.items; const params = { DistributionId: distributionId, /* required */ InvalidationBatch: { /* required */ CallerReference: reference, /* required */ Paths: { /* required */ - Quantity: cloudfrontInvalidateItems.length, /* required */ - Items: cloudfrontInvalidateItems + Quantity: cloudfrontInvalidateItems.length, /* required */ + Items: cloudfrontInvalidateItems } } }; @@ -91,40 +91,49 @@ class CloudfrontInvalidate { invalidate() { const cli = this.serverless.cli; - let cloudfrontInvalidate = this.serverless.service.custom.cloudfrontInvalidate; - let reference = randomstring.generate(16); - let distributionId = cloudfrontInvalidate.distributionId; - if (distributionId) { - cli.consoleLog(`DistributionId: ${chalk.yellow(distributionId)}`); - return this.createInvalidation(distributionId, reference); - } - - if (!cloudfrontInvalidate.distributionIdKey) { - cli.consoleLog('distributionId or distributionIdKey is required'); - return; - } - - cli.consoleLog(`DistributionIdKey: ${chalk.yellow(cloudfrontInvalidate.distributionIdKey)}`); + + this.serverless.service.custom.cloudfrontInvalidate.forEach(element => { + let cloudfrontInvalidate = element; + let reference = randomstring.generate(16); + let distributionId = cloudfrontInvalidate.distributionId; + let stage = cloudfrontInvalidate.stage; + + if (stage !== undefined && stage != `${this.serverless.service.provider.stage}`) { + return; + } - // get the id from the output of stack. - const stackName = this.serverless.getProvider('aws').naming.getStackName() + if (distributionId) { + cli.consoleLog(`DistributionId: ${chalk.yellow(distributionId)}`); + return this.createInvalidation(distributionId, reference, cloudfrontInvalidate); + } - return this.aws.request('CloudFormation', 'describeStacks',{ StackName: stackName }) - .then(result => { - if (result) { - const outputs = result.Stacks[0].Outputs; - outputs.forEach(output => { - if (output.OutputKey === cloudfrontInvalidate.distributionIdKey) { - distributionId = output.OutputValue; - } - }); - } - }) - .then(() => this.createInvalidation(distributionId, reference)) - .catch(error => { - cli.consoleLog('Failed to get DistributionId from stack output. Please check your serverless template.'); + if (!cloudfrontInvalidate.distributionIdKey) { + cli.consoleLog('distributionId or distributionIdKey is required'); return; - }); + } + + cli.consoleLog(`DistributionIdKey: ${chalk.yellow(cloudfrontInvalidate.distributionIdKey)}`); + + // get the id from the output of stack. + const stackName = this.serverless.getProvider('aws').naming.getStackName() + + return this.aws.request('CloudFormation', 'describeStacks', { StackName: stackName }) + .then(result => { + if (result) { + const outputs = result.Stacks[0].Outputs; + outputs.forEach(output => { + if (output.OutputKey === cloudfrontInvalidate.distributionIdKey) { + distributionId = output.OutputValue; + } + }); + } + }) + .then(() => this.createInvalidation(distributionId, reference, cloudfrontInvalidate)) + .catch(error => { + cli.consoleLog('Failed to get DistributionId from stack output. Please check your serverless template.'); + return; + }); + }); } } From 7282bb16a4045c8e6d2d95cf3609b31cc0c3efb9 Mon Sep 17 00:00:00 2001 From: Allegra Chen Date: Thu, 29 Oct 2020 15:45:53 -0400 Subject: [PATCH 2/2] docs: Change the comment about `stage` property to make it less confusing modified: README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d8f09b3..153afec 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ custom: items: # one or more paths required - "/index.html" stage: "dev" # conditional, the stage that this cloudfront invalidation should be created - # this should match the provider's stage you declared, e.g. "dev" but not "development" in this case + # this should match the provider's stage you declared, e.g. "dev" but not "prod" in this case # an invalidation for this distribution will be created when executing `sls deploy --stage dev` - distributionId: "CLOUDFRONT_DIST_ID" #conditional, distributionId or distributionIdKey is required. distributionIdKey: "CDNDistributionId" #conditional, distributionId or distributionIdKey is required.