Skip to content

Commit

Permalink
Transform SNS elements and move them to the alias stack.
Browse files Browse the repository at this point in the history
  • Loading branch information
Frank Schmid committed May 29, 2017
1 parent 36e8259 commit 9e2728f
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 0 deletions.
6 changes: 6 additions & 0 deletions lib/aliasRestructureStack.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const userResources = require('./stackops/userResources');
const lambdaRole = require('./stackops/lambdaRole');
const events = require('./stackops/events');
const cwEvents = require('./stackops/cwEvents');
const snsEvents = require('./stackops/snsEvents');

module.exports = {

Expand Down Expand Up @@ -50,6 +51,10 @@ module.exports = {
return cwEvents.call(this, currentTemplate, aliasStackTemplates, currentAliasStackTemplate);
},

aliasHandleSNSEvents(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) {
return snsEvents.call(this, currentTemplate, aliasStackTemplates, currentAliasStackTemplate);
},

aliasFinalize(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) {
const stageStack = this._serverless.service.provider.compiledCloudFormationTemplate;
const aliasStack = this._serverless.service.provider.compiledCloudFormationAliasTemplate;
Expand Down Expand Up @@ -84,6 +89,7 @@ module.exports = {
.spread(this.aliasHandleApiGateway)
.spread(this.aliasHandleEvents)
.spread(this.aliasHandleCWEvents)
.spread(this.aliasHandleSNSEvents)
.spread(this.aliasFinalize)
.then(() => BbPromise.resolve());
}
Expand Down
77 changes: 77 additions & 0 deletions lib/stackops/snsEvents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
'use strict';

/**
* Handle SNS Lambda subscriptions.
*/

const _ = require('lodash');
const BbPromise = require('bluebird');
const utils = require('../utils');

module.exports = function(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) {
const stageStack = this._serverless.service.provider.compiledCloudFormationTemplate;
const aliasStack = this._serverless.service.provider.compiledCloudFormationAliasTemplate;

this.options.verbose && this._serverless.cli.log('Processing SNS Lambda subscriptions');

const aliasResources = [];

const aliases = _.assign({}, _.pickBy(aliasStack.Resources, [ 'Type', 'AWS::Lambda::Alias' ]));
const versions = _.assign({}, _.pickBy(aliasStack.Resources, [ 'Type', 'AWS::Lambda::Version' ]));

// Add alias name to topics to disambiguate behavior
const snsTopics =
_.assign({},
_.pickBy(stageStack.Resources, [ 'Type', 'AWS::SNS::Topic' ]));

_.forOwn(snsTopics, (topic, name) => {
topic.DependsOn = topic.DependsOn || [];
// Remap lambda subscriptions
const lambdaSubscriptions = _.pickBy(topic.Properties.Subscription, ['Protocol', 'lambda']);
_.forOwn(lambdaSubscriptions, subscription => {
const functionNameRef = utils.findAllReferences(_.get(subscription, 'Endpoint'));
const functionName = _.replace(_.get(functionNameRef, '[0].ref', ''), /LambdaFunction$/, '');
const versionName = _.find(_.keys(versions), version => _.startsWith(version, functionName));
const aliasName = _.find(_.keys(aliases), alias => _.startsWith(alias, functionName));

subscription.Endpoint = { Ref: aliasName };

// Add dependency on function version
topic.DependsOn.push(versionName);
topic.DependsOn.push(aliasName);
});

topic.Properties.TopicName = `${topic.Properties.TopicName}-${this._alias}`;

delete stageStack.Resources[name];
});

// Fetch lambda permissions. These have to be updated later to allow the aliased functions.
const snsLambdaPermissions =
_.assign({},
_.pickBy(_.pickBy(stageStack.Resources, [ 'Type', 'AWS::Lambda::Permission' ]),
[ 'Properties.Principal', 'sns.amazonaws.com' ]));

// Adjust permission to reference the function aliases
_.forOwn(snsLambdaPermissions, (permission, name) => {
const functionName = _.replace(name, /LambdaPermission.*$/, '');
const versionName = _.find(_.keys(versions), version => _.startsWith(version, functionName));
const aliasName = _.find(_.keys(aliases), alias => _.startsWith(alias, functionName));

// Adjust references and alias permissions
permission.Properties.FunctionName = { Ref: aliasName };

// Add dependency on function version
permission.DependsOn = [ versionName, aliasName ];

delete stageStack.Resources[name];
});

// Add all alias stack owned resources
aliasResources.push(snsTopics);
aliasResources.push(snsLambdaPermissions);

_.forEach(aliasResources, resource => _.assign(aliasStack.Resources, resource));

return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]);
};

0 comments on commit 9e2728f

Please sign in to comment.