From eeee34fa5b7c0e1587fdb7883a7658d676469ca3 Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 12 Jul 2016 09:48:15 +0200 Subject: [PATCH] Make coreBucket name unique --- .../aws/deploy/compile/functions/index.js | 5 +--- .../deploy/compile/functions/tests/index.js | 4 +-- .../aws/deploy/lib/initializeResources.js | 6 ----- .../aws/deploy/lib/uploadDeploymentPackage.js | 23 ++++++++--------- .../deploy/tests/uploadDeploymentPackage.js | 16 ++++++++++++ lib/plugins/aws/index.js | 13 ++++++++++ lib/plugins/aws/remove/index.js | 8 +++--- lib/plugins/aws/remove/lib/bucket.js | 16 +++++++----- lib/plugins/aws/remove/tests/bucket.js | 16 ++++++++++++ lib/plugins/aws/tests/index.js | 25 +++++++++++++++++++ lib/templates/core-cf.json | 10 +++++--- 11 files changed, 104 insertions(+), 38 deletions(-) diff --git a/lib/plugins/aws/deploy/compile/functions/index.js b/lib/plugins/aws/deploy/compile/functions/index.js index 461bde008..f69731ba6 100644 --- a/lib/plugins/aws/deploy/compile/functions/index.js +++ b/lib/plugins/aws/deploy/compile/functions/index.js @@ -25,7 +25,7 @@ class AwsCompileFunctions { "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "S3Bucket": "S3Bucket", + "S3Bucket": { "Ref": "coreBucket" }, "S3Key": "S3Key" }, "FunctionName": "FunctionName", @@ -42,9 +42,6 @@ class AwsCompileFunctions { const newFunction = JSON.parse(functionTemplate); const functionObject = this.serverless.service.getFunction(functionName); - newFunction.Properties.Code - .S3Bucket = - `${this.serverless.service.service}-${this.options.stage}-${this.options.region}`; newFunction.Properties.Code .S3Key = this.serverless.service.package.artifact.split(path.sep).pop(); diff --git a/lib/plugins/aws/deploy/compile/functions/tests/index.js b/lib/plugins/aws/deploy/compile/functions/tests/index.js index 85750c852..cf62a8212 100644 --- a/lib/plugins/aws/deploy/compile/functions/tests/index.js +++ b/lib/plugins/aws/deploy/compile/functions/tests/index.js @@ -39,7 +39,7 @@ describe('AwsCompileFunctions', () => { Type: 'AWS::Lambda::Function', Properties: { Code: { - S3Bucket: 'new-service-dev-us-east-1', + S3Bucket: { Ref: 'coreBucket' }, S3Key: 'artifact.zip', }, FunctionName: 'new-service-dev-first', @@ -54,7 +54,7 @@ describe('AwsCompileFunctions', () => { Type: 'AWS::Lambda::Function', Properties: { Code: { - S3Bucket: 'new-service-dev-us-east-1', + S3Bucket: { Ref: 'coreBucket' }, S3Key: 'artifact.zip', }, FunctionName: 'new-service-dev-second', diff --git a/lib/plugins/aws/deploy/lib/initializeResources.js b/lib/plugins/aws/deploy/lib/initializeResources.js index 3a981c298..6b04980f1 100644 --- a/lib/plugins/aws/deploy/lib/initializeResources.js +++ b/lib/plugins/aws/deploy/lib/initializeResources.js @@ -12,12 +12,6 @@ module.exports = { ); // set the necessary variables before creating stack - coreCFTemplate - .Resources - .coreBucket - .Properties - .BucketName = - `${this.serverless.service.service}-${this.options.stage}-${this.options.region}`; coreCFTemplate .Resources .IamPolicyLambda diff --git a/lib/plugins/aws/deploy/lib/uploadDeploymentPackage.js b/lib/plugins/aws/deploy/lib/uploadDeploymentPackage.js index e797cca94..75265c03e 100644 --- a/lib/plugins/aws/deploy/lib/uploadDeploymentPackage.js +++ b/lib/plugins/aws/deploy/lib/uploadDeploymentPackage.js @@ -6,16 +6,20 @@ const BbPromise = require('bluebird'); const _ = require('lodash'); module.exports = { - getServiceObjectsFromS3Bucket() { - const bucketName = - `${this.serverless.service.service}-${this.options.stage}-${this.options.region}`; + setCoreBucketName() { + return this.sdk.getCoreBucketName(this.options.stage, this.options.region) + .then((bucketName) => { + this.bucketName = bucketName; + }); + }, + getServiceObjectsFromS3Bucket() { // 4 old ones + the one which will be uploaded after the cleanup = 5 const objectsToKeepCount = 4; return this.sdk.request('S3', 'listObjectsV2', - { Bucket: bucketName }, + { Bucket: this.bucketName }, this.options.stage, this.options.region) .then((result) => { @@ -45,13 +49,10 @@ module.exports = { if (objectsToRemove && objectsToRemove.length) { this.serverless.cli.log('Removing old service versions...'); - const bucketName = - `${this.serverless.service.service}-${this.options.stage}-${this.options.region}`; - return this.sdk.request('S3', 'deleteObjects', { - Bucket: bucketName, + Bucket: this.bucketName, Delete: { Objects: objectsToRemove }, }, this.options.stage, @@ -64,13 +65,10 @@ module.exports = { uploadZipFileToS3Bucket() { this.serverless.cli.log('Uploading .zip file to S3...'); - const bucketName = - `${this.serverless.service.service}-${this.options.stage}-${this.options.region}`; - const body = fs.readFileSync(this.serverless.service.package.artifact); const params = { - Bucket: bucketName, + Bucket: this.bucketName, Key: this.serverless.service.package.artifact.split(path.sep).pop(), Body: body, }; @@ -84,6 +82,7 @@ module.exports = { uploadDeploymentPackage() { return BbPromise.bind(this) + .then(this.setCoreBucketName) .then(this.getServiceObjectsFromS3Bucket) .then(this.cleanupS3Bucket) .then(this.uploadZipFileToS3Bucket); diff --git a/lib/plugins/aws/deploy/tests/uploadDeploymentPackage.js b/lib/plugins/aws/deploy/tests/uploadDeploymentPackage.js index b7e9f4fde..9d52ca068 100644 --- a/lib/plugins/aws/deploy/tests/uploadDeploymentPackage.js +++ b/lib/plugins/aws/deploy/tests/uploadDeploymentPackage.js @@ -22,6 +22,22 @@ describe('uploadDeploymentPackage', () => { awsDeploy.serverless.cli = new serverless.classes.CLI(); }); + describe('#setCoreBucketName()', () => { + it('should store the name of the core bucket in the "this" variable', () => { + const getCoreBucketNameStub = sinon + .stub(awsDeploy.sdk, 'getCoreBucketName') + .returns(BbPromise.resolve('new-service-dev-us-east-1-12345678')); + + return awsDeploy.setCoreBucketName().then(() => { + expect(awsDeploy.bucketName).to.equal('new-service-dev-us-east-1-12345678'); + expect(getCoreBucketNameStub.calledOnce).to.be.equal(true); + expect(getCoreBucketNameStub + .calledWith(awsDeploy.options.stage, awsDeploy.options.region)); + awsDeploy.sdk.getCoreBucketName.restore(); + }); + }); + }); + describe('#getServiceObjectsFromS3Bucket()', () => { it('should resolve if no service objects are found', () => { const serviceObjects = { diff --git a/lib/plugins/aws/index.js b/lib/plugins/aws/index.js index 2cc2e1ceb..1c5528913 100644 --- a/lib/plugins/aws/index.js +++ b/lib/plugins/aws/index.js @@ -4,6 +4,7 @@ const BbPromise = require('bluebird'); const HttpsProxyAgent = require('https-proxy-agent'); const url = require('url'); const AWS = require('aws-sdk'); +const _ = require('lodash'); class SDK { constructor(serverless) { @@ -86,6 +87,18 @@ class SDK { return credentials; } + + getCoreBucketName(stage, region) { + const stackName = `${this.serverless.service.service}-${stage}`; + + return this.request('CloudFormation', + 'describeStacks', + { StackName: stackName }, + stage, + region + ).then((result) => _.find(result.Stacks[0].Outputs, + { OutputKey: 'CoreBucketName' }).OutputValue); + } } module.exports = SDK; diff --git a/lib/plugins/aws/remove/index.js b/lib/plugins/aws/remove/index.js index 21ecf2532..22ff74b5c 100644 --- a/lib/plugins/aws/remove/index.js +++ b/lib/plugins/aws/remove/index.js @@ -17,10 +17,10 @@ class AwsRemove { this.hooks = { 'remove:remove': () => BbPromise.bind(this) - .then(this.validate) - .then(this.emptyS3Bucket) - .then(this.removeStack) - .then(() => this.serverless.cli.log('Resource removal successful!')), + .then(this.validate) + .then(this.emptyS3Bucket) + .then(this.removeStack) + .then(() => this.serverless.cli.log('Resource removal successful!')), }; } } diff --git a/lib/plugins/aws/remove/lib/bucket.js b/lib/plugins/aws/remove/lib/bucket.js index 85e271ce7..41b9f7c57 100644 --- a/lib/plugins/aws/remove/lib/bucket.js +++ b/lib/plugins/aws/remove/lib/bucket.js @@ -3,14 +3,19 @@ const BbPromise = require('bluebird'); module.exports = { + setCoreBucketName() { + return this.sdk.getCoreBucketName(this.options.stage, this.options.region) + .then((bucketName) => { + this.bucketName = bucketName; + }); + }, + listObjects() { this.objectsInBucket = []; - const bucketName = `${this.serverless.service.service}-${ - this.options.stage}-${this.options.region}`; this.serverless.cli.log('Getting all objects in S3 bucket...'); return this.sdk.request('S3', 'listObjectsV2', { - Bucket: bucketName, + Bucket: this.bucketName, }, this.options.stage, this.options.region).then((result) => { if (result) { result.Contents.forEach((object) => { @@ -24,12 +29,10 @@ module.exports = { }, deleteObjects() { - const bucketName = `${this.serverless.service.service}-${ - this.options.stage}-${this.options.region}`; this.serverless.cli.log('Removing objects in S3 bucket...'); if (this.objectsInBucket.length) { return this.sdk.request('S3', 'deleteObjects', { - Bucket: bucketName, + Bucket: this.bucketName, Delete: { Objects: this.objectsInBucket, }, @@ -41,6 +44,7 @@ module.exports = { emptyS3Bucket() { return BbPromise.bind(this) + .then(this.setCoreBucketName) .then(this.listObjects) .then(this.deleteObjects); }, diff --git a/lib/plugins/aws/remove/tests/bucket.js b/lib/plugins/aws/remove/tests/bucket.js index b09178126..34b01f089 100644 --- a/lib/plugins/aws/remove/tests/bucket.js +++ b/lib/plugins/aws/remove/tests/bucket.js @@ -20,6 +20,22 @@ describe('emptyS3Bucket', () => { awsRemove.serverless.cli = new serverless.classes.CLI(); }); + describe('#setCoreBucketName()', () => { + it('should store the name of the core bucket in the "this" variable', () => { + const getCoreBucketNameStub = sinon + .stub(awsRemove.sdk, 'getCoreBucketName') + .returns(BbPromise.resolve('new-service-dev-us-east-1-12345678')); + + return awsRemove.setCoreBucketName().then(() => { + expect(awsRemove.bucketName).to.equal('new-service-dev-us-east-1-12345678'); + expect(getCoreBucketNameStub.calledOnce).to.be.equal(true); + expect(getCoreBucketNameStub + .calledWith(awsRemove.options.stage, awsRemove.options.region)); + awsRemove.sdk.getCoreBucketName.restore(); + }); + }); + }); + describe('#listObjects()', () => { it('should list all objects in the S3 bucket', () => { const listObjectsStub = sinon.stub(awsRemove.sdk, 'request') diff --git a/lib/plugins/aws/tests/index.js b/lib/plugins/aws/tests/index.js index 1c14eaf40..7050d68c1 100644 --- a/lib/plugins/aws/tests/index.js +++ b/lib/plugins/aws/tests/index.js @@ -1,5 +1,7 @@ 'use strict'; +const sinon = require('sinon'); +const BbPromise = require('bluebird'); const expect = require('chai').expect; const Serverless = require('../../../Serverless'); const AwsSdk = require('../'); @@ -127,4 +129,27 @@ describe('AWS SDK', () => { expect(credentials.profile).to.deep.equal('default'); }); }); + + describe('#getCoreBucketName', () => { + it('should return the name of the core bucket', () => { + const serverless = new Serverless(); + const awsSdk = new AwsSdk(serverless); + const options = { + stage: 'dev', + region: 'us-east-1', + }; + + const getCoreBucketNameStub = sinon + .stub(awsSdk, 'getCoreBucketName') + .returns(BbPromise.resolve('new-service-dev-us-east-1-12345678')); + + return awsSdk.getCoreBucketName(options.stage, options.region).then((bucketName) => { + expect(bucketName).to.equal('new-service-dev-us-east-1-12345678'); + expect(getCoreBucketNameStub.calledOnce).to.be.equal(true); + expect(getCoreBucketNameStub + .calledWith(options.stage, options.region)); + awsSdk.getCoreBucketName.restore(); + }); + }); + }); }); diff --git a/lib/templates/core-cf.json b/lib/templates/core-cf.json index aa7b6ba9c..34c079993 100644 --- a/lib/templates/core-cf.json +++ b/lib/templates/core-cf.json @@ -3,10 +3,7 @@ "Description": "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway", "Resources": { "coreBucket": { - "Type" : "AWS::S3::Bucket", - "Properties": { - "BucketName": "" - } + "Type" : "AWS::S3::Bucket" }, "IamRoleLambda": { "Type": "AWS::IAM::Role", @@ -65,6 +62,11 @@ "Arn" ] } + }, + "CoreBucketName": { + "Value": { + "Ref": "coreBucket" + } } } }