From e980625f586f55da4559b362a9dcd7275e9001bb Mon Sep 17 00:00:00 2001 From: devops hipster in training Date: Fri, 24 Jul 2020 17:51:10 +1000 Subject: [PATCH] fix: Recognize final DELETE_COMPLETE event with verbose flag (#7979) --- lib/plugins/aws/lib/monitorStack.js | 2 +- lib/plugins/aws/lib/monitorStack.test.js | 80 ++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/lib/plugins/aws/lib/monitorStack.js b/lib/plugins/aws/lib/monitorStack.js index 9ef2374de..6be0ad235 100644 --- a/lib/plugins/aws/lib/monitorStack.js +++ b/lib/plugins/aws/lib/monitorStack.js @@ -113,7 +113,7 @@ module.exports = { (!this.options.verbose || (stackStatus && (stackStatus.endsWith('ROLLBACK_COMPLETE') || - stackStatus === 'DELETE_FAILED'))) + ['DELETE_FAILED', 'DELETE_COMPLETE'].includes(stackStatus)))) ) { // empty console.log for a prettier output if (!this.options.verbose) this.serverless.cli.consoleLog(''); diff --git a/lib/plugins/aws/lib/monitorStack.test.js b/lib/plugins/aws/lib/monitorStack.test.js index c4302a1b9..d0a0ab232 100644 --- a/lib/plugins/aws/lib/monitorStack.test.js +++ b/lib/plugins/aws/lib/monitorStack.test.js @@ -761,6 +761,86 @@ describe('monitorStack', () => { } ); + it( + 'should throw an error if stack status is DELETE_COMPLETE and should output all ' + + 'stack events information with the --verbose option', + () => { + awsPlugin.options.verbose = true; + const describeStackEventsStub = sinon.stub(awsPlugin.provider, 'request'); + const cfDataMock = { + StackId: 'new-service-dev', + }; + const createStartEvent = { + StackEvents: [ + { + EventId: '1a2b3c4d', + StackName: 'new-service-dev', + LogicalResourceId: 'new-service-dev', + ResourceType: 'AWS::CloudFormation::Stack', + Timestamp: new Date(), + ResourceStatus: 'CREATE_IN_PROGRESS', + }, + ], + }; + const createItemFailedEvent = { + StackEvents: [ + { + EventId: '1e2f3g4h', + StackName: 'new-service-dev', + LogicalResourceId: 'myBucket', + ResourceType: 'AWS::S3::Bucket', + Timestamp: new Date(), + ResourceStatus: 'CREATE_FAILED', + ResourceStatusReason: 'Invalid Property for X', + }, + ], + }; + const createItemDeleteEvent = { + StackEvents: [ + { + EventId: '1i2j3k4l', + StackName: 'new-service-dev', + LogicalResourceId: 'myBucket', + ResourceType: 'AWS::S3::Bucket', + Timestamp: new Date(), + ResourceStatus: 'DELETE_IN_PROGRESS', + }, + ], + }; + const createFailedEvent = { + StackEvents: [ + { + EventId: '1m2n3o4p', + StackName: 'new-service-dev', + LogicalResourceId: 'new-service-dev', + ResourceType: 'AWS::CloudFormation::Stack', + Timestamp: new Date(), + ResourceStatus: 'DELETE_COMPLETE', + }, + ], + }; + + describeStackEventsStub.onCall(0).resolves(createStartEvent); + describeStackEventsStub.onCall(1).resolves(createItemFailedEvent); + describeStackEventsStub.onCall(2).resolves(createItemDeleteEvent); + describeStackEventsStub.onCall(3).resolves(createFailedEvent); + + return awsPlugin.monitorStack('create', cfDataMock, { frequency: 10 }).catch(e => { + let errorMessage = 'An error occurred: '; + errorMessage += 'myBucket - Invalid Property for X.'; + expect(e.name).to.be.equal('ServerlessError'); + expect(e.message).to.be.equal(errorMessage); + expect(describeStackEventsStub.callCount).to.be.equal(4); + expect( + describeStackEventsStub.calledWithExactly('CloudFormation', 'describeStackEvents', { + StackName: cfDataMock.StackId, + }) + ).to.be.equal(true); + awsPlugin.provider.request.restore(); + }); + } + ); + it('should record an error and fail if status is UPDATE_ROLLBACK_IN_PROGRESS', () => { const describeStackEventsStub = sinon.stub(awsPlugin.provider, 'request'); const cfDataMock = {