Skip to content

Commit

Permalink
Merge pull request #55 from HyperBrain/fix-superfluous-iam-roles
Browse files Browse the repository at this point in the history
Remove stale iam roles
  • Loading branch information
HyperBrain authored Jun 6, 2017
2 parents 899bb0b + 62d1c9e commit 6238e9e
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 20 deletions.
17 changes: 13 additions & 4 deletions lib/stackops/lambdaRole.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,22 @@ module.exports = function(currentTemplate, aliasStackTemplates, currentAliasStac
func.DependsOn[dependencyIndex] = roleName;
});

if (_.isEmpty(utils.findReferences(currentTemplate.Resources, 'IamRoleLambdaExecution')) && _.has(currentTemplate, 'Resources.IamRoleLambdaExecution')) {
if (_.has(currentTemplate, 'Resources.IamRoleLambdaExecution')) {
if (!_.isEmpty(utils.findReferences(currentTemplate.Resources, 'IamRoleLambdaExecution'))) {
stageStack.Resources.IamRoleLambdaExecution = currentTemplate.Resources.IamRoleLambdaExecution;
}
delete currentTemplate.Resources.IamRoleLambdaExecution;
}

// Import all defined roles from the current template (without overwriting)
const currentRoles = _.assign({}, _.pickBy(currentTemplate.Resources, (resource, name) => resource.Type === 'AWS::IAM::Role' && /^IamRoleLambdaExecution/.test(name)));
_.defaults(stageStack.Resources, currentRoles);
// Retain the roles of all currently deployed aliases
_.forEach(aliasStackTemplates, aliasTemplate => {
const alias = _.get(aliasTemplate, 'Outputs.ServerlessAliasName.Value');
const aliasRoleName = `IamRoleLambdaExecution${alias}`;
const aliasRole = _.get(currentTemplate, `Resources.${aliasRoleName}`);
if (alias && aliasRole) {
stageStack.Resources[aliasRoleName] = aliasRole;
}
});

return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]);
};
9 changes: 5 additions & 4 deletions test/aliasRestructureStack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

const getInstalledPath = require('get-installed-path');
const _ = require('lodash');
const BbPromise = require('bluebird');
const chai = require('chai');
const sinon = require('sinon');
Expand Down Expand Up @@ -36,14 +37,14 @@ describe('aliasRestructureStack', () => {
stage: 'myStage',
region: 'us-east-1',
};
serverless.setProvider('aws', new AwsProvider(serverless));
serverless.setProvider('aws', new AwsProvider(serverless, options));
serverless.cli = new serverless.classes.CLI(serverless);
serverless.service.service = 'testService';
serverless.service.provider.compiledCloudFormationAliasTemplate = {
Resources: {},
Outputs: {}
};
serverless.service.provider.compiledCloudFormationTemplate = require('./data/sls-stack-1.json');
serverless.service.provider.compiledCloudFormationTemplate = _.cloneDeep(require('./data/sls-stack-1.json'));
awsAlias = new AWSAlias(serverless, options);

// Disable logging
Expand Down Expand Up @@ -94,8 +95,8 @@ describe('aliasRestructureStack', () => {
const aliasHandleSNSEventsSpy = sandbox.spy(awsAlias, 'aliasHandleSNSEvents');
const aliasFinalizeSpy = sandbox.spy(awsAlias, 'aliasFinalize');

const currentTemplate = require('./data/sls-stack-2.json');
const aliasTemplate = require('./data/alias-stack-1.json');
const currentTemplate = _.cloneDeep(require('./data/sls-stack-2.json'));
const aliasTemplate = _.cloneDeep(require('./data/alias-stack-1.json'));
const currentAliasStackTemplate = {};

return expect(awsAlias.aliasRestructureStack(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate))
Expand Down
5 changes: 4 additions & 1 deletion test/configureAliasStack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

const getInstalledPath = require('get-installed-path');
const _ = require('lodash');
const BbPromise = require('bluebird');
const chai = require('chai');
const sinon = require('sinon');
Expand Down Expand Up @@ -53,14 +54,16 @@ describe('configureAliasStack', () => {

describe('#configureAliasStack()', () => {
let readFileSyncStub;
let stack1;

beforeEach(() => {
readFileSyncStub = sandbox.stub(serverless.utils, 'readFileSync');
stack1 = _.cloneDeep(require('./data/sls-stack-1.json'));
});

it('should set alias reference and properties to CF templates', () => {
readFileSyncStub.returns(require('../lib/alias-cloudformation-template.json'));
serverless.service.provider.compiledCloudFormationTemplate = require('./data/sls-stack-1.json');
serverless.service.provider.compiledCloudFormationTemplate = stack1;
const cfTemplate = serverless.service.provider.compiledCloudFormationTemplate;

return expect(awsAlias.validate()).to.be.fulfilled
Expand Down
5 changes: 3 additions & 2 deletions test/stackops/init.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

const getInstalledPath = require('get-installed-path');
const _ = require('lodash');
const BbPromise = require('bluebird');
const chai = require('chai');
const sinon = require('sinon');
Expand Down Expand Up @@ -53,8 +54,8 @@ describe('SNS Events', () => {

describe('#aliasInit()', () => {
it('should set alias flags', () => {
serverless.service.provider.compiledCloudFormationTemplate = require('../data/sls-stack-1.json');
const aliasStack = serverless.service.provider.compiledCloudFormationAliasTemplate = require('../data/alias-stack-1.json');
serverless.service.provider.compiledCloudFormationTemplate = _.cloneDeep(require('../data/sls-stack-1.json'));
const aliasStack = serverless.service.provider.compiledCloudFormationAliasTemplate = _.cloneDeep(require('../data/alias-stack-1.json'));
return expect(awsAlias.aliasInit({}, [], {})).to.be.fulfilled
.then(() => BbPromise.all([
expect(aliasStack).to.have.property('Outputs')
Expand Down
49 changes: 46 additions & 3 deletions test/stackops/lambdaRole.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

const getInstalledPath = require('get-installed-path');
const _ = require('lodash');
const chai = require('chai');
const sinon = require('sinon');
const AWSAlias = require('../../index');
Expand Down Expand Up @@ -34,8 +35,8 @@ describe('lambdaRole', () => {
stage: 'myStage',
region: 'us-east-1',
};
serverless = new Serverless(options);
serverless.setProvider('aws', new AwsProvider(serverless));
serverless = new Serverless();
serverless.setProvider('aws', new AwsProvider(serverless, options));
serverless.cli = new serverless.classes.CLI(serverless);
serverless.service.service = 'testService';
serverless.service.provider.compiledCloudFormationAliasTemplate = {};
Expand All @@ -44,17 +45,59 @@ describe('lambdaRole', () => {
// Disable logging
logStub = sandbox.stub(serverless.cli, 'log');
logStub.returns();

return awsAlias.validate();
});

afterEach(() => {
sandbox.restore();
});

describe('#aliasHandleLambdaRole()', () => {
let stack;

beforeEach(() => {
stack = _.cloneDeep(require('../data/sls-stack-1.json'));
});

it('should succeed with standard template', () => {
serverless.service.provider.compiledCloudFormationTemplate = require('../data/sls-stack-1.json');
serverless.service.provider.compiledCloudFormationTemplate = stack;
return expect(awsAlias.aliasHandleLambdaRole({}, [], {})).to.be.fulfilled;
});

it('should remove old global IAM role when there are no references', () => {
const currentTemplate = {
Resources: {
IamRoleLambdaExecution: {}
},
Outputs: {}
};
serverless.service.provider.compiledCloudFormationTemplate = stack;
return expect(awsAlias.aliasHandleLambdaRole(currentTemplate, [], {})).to.be.fulfilled
.then(() => expect(currentTemplate).to.not.have.a.property('IamRoleLambdaExecution'));
});

it('should retain existing alias roles', () => {
const aliasTemplates = [{
Resources: {},
Outputs: {
ServerlessAliasName: {
Description: 'The current alias',
Value: 'testAlias'
}
}
}];
const currentTemplate = {
Resources: {
IamRoleLambdaExecution: {},
IamRoleLambdaExecutiontestAlias: {}
},
Outputs: {}
};
const stackTemplate = serverless.service.provider.compiledCloudFormationTemplate = stack;
return expect(awsAlias.aliasHandleLambdaRole(currentTemplate, aliasTemplates, {})).to.be.fulfilled
.then(() => expect(stackTemplate).to.have.a.deep.property('Resources.IamRoleLambdaExecutiontestAlias'));
});

});
});
23 changes: 17 additions & 6 deletions test/stackops/snsEvents.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

const getInstalledPath = require('get-installed-path');
const _ = require('lodash');
const BbPromise = require('bluebird');
const chai = require('chai');
const sinon = require('sinon');
Expand Down Expand Up @@ -52,15 +53,25 @@ describe('SNS Events', () => {
});

describe('#aliasHandleSNSEvents()', () => {
let stack1;
let aliasStack1;
let snsStack1;

beforeEach(() => {
stack1 = _.cloneDeep(require('../data/sls-stack-1.json'));
aliasStack1 = _.cloneDeep(require('../data/alias-stack-1.json'));
snsStack1 = _.cloneDeep(require('../data/sns-stack.json'));
});

it('should succeed with standard template', () => {
serverless.service.provider.compiledCloudFormationTemplate = require('../data/sls-stack-1.json');
serverless.service.provider.compiledCloudFormationAliasTemplate = require('../data/alias-stack-1.json');
serverless.service.provider.compiledCloudFormationTemplate = stack1;
serverless.service.provider.compiledCloudFormationAliasTemplate = aliasStack1;
return expect(awsAlias.aliasHandleSNSEvents({}, [], {})).to.be.fulfilled;
});

it('should move resources to alias stack', () => {
const snsStack = serverless.service.provider.compiledCloudFormationTemplate = require('../data/sns-stack.json');
const aliasStack = serverless.service.provider.compiledCloudFormationAliasTemplate = require('../data/alias-stack-1.json');
const snsStack = serverless.service.provider.compiledCloudFormationTemplate = snsStack1;
const aliasStack = serverless.service.provider.compiledCloudFormationAliasTemplate = aliasStack1;
return expect(awsAlias.aliasHandleSNSEvents({}, [], {})).to.be.fulfilled
.then(() => BbPromise.all([
expect(snsStack).to.not.have.property('SNSTopicSlstestprojecttopic'),
Expand All @@ -71,8 +82,8 @@ describe('SNS Events', () => {
});

it('should replace function with alias reference', () => {
serverless.service.provider.compiledCloudFormationTemplate = require('../data/sns-stack.json');
const aliasStack = serverless.service.provider.compiledCloudFormationAliasTemplate = require('../data/alias-stack-1.json');
serverless.service.provider.compiledCloudFormationTemplate = snsStack1;
const aliasStack = serverless.service.provider.compiledCloudFormationAliasTemplate = aliasStack1;
return expect(awsAlias.aliasHandleSNSEvents({}, [], {})).to.be.fulfilled
.then(() => BbPromise.all([
expect(aliasStack).to.not.have.property('SNSTopicSlstestprojecttopic')
Expand Down

0 comments on commit 6238e9e

Please sign in to comment.