From 27bc1bde245700a11560692e10e75f783de9cc2d Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Wed, 10 Apr 2019 14:31:30 +0200 Subject: [PATCH] Add custom error message when X-Ray tracing deployments fail --- lib/plugins/aws/lib/getStackErrorMessage.js | 39 ++++++++++++ .../aws/lib/getStackErrorMessage.test.js | 59 +++++++++++++++++++ lib/plugins/aws/lib/monitorStack.js | 5 +- 3 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 lib/plugins/aws/lib/getStackErrorMessage.js create mode 100644 lib/plugins/aws/lib/getStackErrorMessage.test.js diff --git a/lib/plugins/aws/lib/getStackErrorMessage.js b/lib/plugins/aws/lib/getStackErrorMessage.js new file mode 100644 index 000000000..d4f0bdaba --- /dev/null +++ b/lib/plugins/aws/lib/getStackErrorMessage.js @@ -0,0 +1,39 @@ +function isStageUpdateError(stackLatestError, that) { + const logicalId = stackLatestError.LogicalResourceId; + + const deploymentLogicalId = that.provider.naming + .generateApiGatewayDeploymentLogicalId(that.serverless.instanceId); + const stageLogicalId = that.provider.naming.getStageLogicalId(); + + if (logicalId === deploymentLogicalId) { + return stackLatestError.ResourceStatusReason.match(/StageName/); + } + if (logicalId === stageLogicalId) { + return stackLatestError.ResourceStatusReason.match(/already exists/); + } + + return false; +} + +// TODO: we should use `bind` rather than passing `this` into the function +function getStackErrorMessage(stackLatestError, that) { + let errorMessage = 'An error occurred: '; + errorMessage += `${stackLatestError.LogicalResourceId} - `; + errorMessage += `${stackLatestError.ResourceStatusReason}.`; + + // custom error message for API Gateway stage deployment errors + if (isStageUpdateError(stackLatestError, that)) { + const msg = [ + '\n\n ', + 'NOTE: Enabling API Gateway X-Ray Tracing for existing ', + 'deployments requires a remove and re-deploy of your API Gateway. ', + '\n ', + 'Please refer to our documentation for more information.', + ].join(''); + errorMessage += msg; + } + + return errorMessage; +} + +module.exports = getStackErrorMessage; diff --git a/lib/plugins/aws/lib/getStackErrorMessage.test.js b/lib/plugins/aws/lib/getStackErrorMessage.test.js new file mode 100644 index 000000000..f070f7aa0 --- /dev/null +++ b/lib/plugins/aws/lib/getStackErrorMessage.test.js @@ -0,0 +1,59 @@ +'use strict'; + +const expect = require('chai').expect; +const Serverless = require('../../../Serverless'); +const AwsProvider = require('../provider/awsProvider'); +const CLI = require('../../../classes/CLI'); +const getStackErrorMessage = require('./getStackErrorMessage'); + +describe('#getStackErrorMessage()', () => { + let serverless; + let awsPlugin; + + beforeEach(() => { + serverless = new Serverless(); + awsPlugin = {}; + const options = { + stage: 'dev', + region: 'us-east-1', + }; + awsPlugin.serverless = serverless; + awsPlugin.provider = new AwsProvider(serverless, options); + awsPlugin.serverless.cli = new CLI(serverless); + awsPlugin.options = options; + }); + + it('should return a formatted error message', () => { + const stackLatestError = { + LogicalResourceId: 'SomeLogicalResourceId', + ResourceStatusReason: 'Some error message', + }; + const msg = getStackErrorMessage(stackLatestError, awsPlugin); + + expect(msg).to.equal('An error occurred: SomeLogicalResourceId - Some error message.'); + }); + + describe('when X-Ray Tracing deployments cause errors', () => { + it('should return a custom error message if Deployment resource causes an error', () => { + const stackLatestError = { + LogicalResourceId: awsPlugin.provider.naming + .generateApiGatewayDeploymentLogicalId(awsPlugin.serverless.instanceId), + ResourceStatusReason: 'StageName', + }; + const msg = getStackErrorMessage(stackLatestError, awsPlugin); + + expect(msg).to.match(/API Gateway X-Ray Tracing/); + }); + + it('should return a custom error message if Stage resource causes an error', () => { + const stackLatestError = { + LogicalResourceId: awsPlugin.provider.naming + .getStageLogicalId(), + ResourceStatusReason: 'already exists', + }; + const msg = getStackErrorMessage(stackLatestError, awsPlugin); + + expect(msg).to.match(/API Gateway X-Ray Tracing/); + }); + }); +}); diff --git a/lib/plugins/aws/lib/monitorStack.js b/lib/plugins/aws/lib/monitorStack.js index 5f7186d90..9123feae0 100644 --- a/lib/plugins/aws/lib/monitorStack.js +++ b/lib/plugins/aws/lib/monitorStack.js @@ -3,6 +3,7 @@ const BbPromise = require('bluebird'); const async = require('async'); const chalk = require('chalk'); +const getStackErrorMessage = require('./getStackErrorMessage'); module.exports = { monitorStack(action, cfData, frequency) { @@ -112,9 +113,7 @@ module.exports = { if (!this.options.verbose) this.serverless.cli.consoleLog(''); this.serverless.cli.log('Operation failed!'); this.serverless.cli.log(`View the full error output: ${stackUrl}`); - let errorMessage = 'An error occurred: '; - errorMessage += `${stackLatestError.LogicalResourceId} - `; - errorMessage += `${stackLatestError.ResourceStatusReason}.`; + const errorMessage = getStackErrorMessage(stackLatestError, this); return reject(new this.serverless.classes.Error(errorMessage)); } // Trigger next monitoring action