Skip to content
This repository has been archived by the owner on Mar 10, 2023. It is now read-only.

Commit

Permalink
Supporting SNS events
Browse files Browse the repository at this point in the history
  • Loading branch information
karloscodes authored and davidgf committed Mar 13, 2018
1 parent ad75ec5 commit cf5dca8
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 47 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ The plugin relies on the [AWS Lambda traffic shifting feature](https://docs.aws.

## Limitations

For now, the plugin only works with Lambda functions invoked by API Gateway or Stream based events (such as the triggered by Kinesis or DynamoDB Streams). More events will be added soon.
For now, the plugin only works with Lambda functions invoked by API Gateway, Stream based (such as the triggered by Kinesis or DynamoDB Streams) and SNS based events. More events will be added soon.

## License

Expand Down
Binary file added example/.DS_Store
Binary file not shown.
6 changes: 3 additions & 3 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
"devDependencies": {
"serverless": "^1.26.1",
"serverless-plugin-aws-alerts": "^1.2.4",
"serverless-plugin-canary-deployments": "^0.1.0"
"serverless-plugin-canary-deployments": "^0.2.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"package": "npm un --no-save serverless-plugin-canary-deployments && npm pack ../ && npm i --no-save serverless-plugin-canary-deployments-0.1.0.tgz && sls package -s dev",
"deploy": "npm un --no-save serverless-plugin-canary-deployments && npm pack ../ && npm i --no-save serverless-plugin-canary-deployments-0.1.0.tgz && sls deploy -s dev",
"package": "npm un --no-save serverless-plugin-canary-deployments && npm pack ../ && npm i --no-save serverless-plugin-canary-deployments-0.2.0.tgz && sls package -s dev",
"deploy": "npm un --no-save serverless-plugin-canary-deployments && npm pack ../ && npm i --no-save serverless-plugin-canary-deployments-0.2.0.tgz && sls deploy -s dev",
"populate-table": "node ./scripts/populate-test-table"
},
"author": "",
Expand Down
1 change: 1 addition & 0 deletions example/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ functions:
Fn::GetAtt:
- StreamsTestTable
- StreamArn
- sns: snsTopic
alarms:
- name: foo
namespace: 'AWS/Lambda'
Expand Down
50 changes: 49 additions & 1 deletion fixtures/1.input.json
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,54 @@
}
}
},
"SNSTopicSnsTopic": {
"Type": "AWS::SNS::Topic",
"Properties": {
"TopicName": "snsTopic",
"DisplayName": "",
"Subscription": [
{
"Endpoint": {
"Fn::GetAtt": [
"HelloLambdaFunction",
"Arn"
]
},
"Protocol": "lambda"
}
]
}
},
"HelloLambdaPermissionSnsTopicSNS": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"HelloLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": "sns.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:aws:sns:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
"snsTopic"
]
]
}
}
},
"HelloEventSourceMappingDynamodbStreamsTestTable": {
"Type": "AWS::Lambda::EventSourceMapping",
"DependsOn": "IamRoleLambdaExecution",
Expand Down Expand Up @@ -464,4 +512,4 @@
}
}
}
}
}
94 changes: 68 additions & 26 deletions fixtures/1.output.json
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,48 @@
}
}
},
"SNSTopicSnsTopic": {
"Type": "AWS::SNS::Topic",
"Properties": {
"TopicName": "snsTopic",
"DisplayName": "",
"Subscription": [
{
"Endpoint": {
"Ref": "HelloLambdaFunctionAliasLive"
},
"Protocol": "lambda"
}
]
}
},
"HelloLambdaPermissionSnsTopicSNS": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Ref": "HelloLambdaFunctionAliasLive"
},
"Action": "lambda:InvokeFunction",
"Principal": "sns.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:aws:sns:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
"snsTopic"
]
]
}
}
},
"HelloEventSourceMappingDynamodbStreamsTestTable": {
"Type": "AWS::Lambda::EventSourceMapping",
"DependsOn": "IamRoleLambdaExecution",
Expand Down Expand Up @@ -376,6 +418,31 @@
"Statistic": "Minimum"
}
},
"StreamsTestTable": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"TableName": "StreamsTestTable",
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 1,
"WriteCapacityUnits": 1
},
"StreamSpecification": {
"StreamViewType": "NEW_AND_OLD_IMAGES"
}
}
},
"CanarydeploymentstestdevDeploymentApplication": {
"Type": "AWS::CodeDeploy::Application",
"Properties": {
Expand Down Expand Up @@ -481,31 +548,6 @@
}
}
}
},
"StreamsTestTable": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"TableName": "StreamsTestTable",
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 1,
"WriteCapacityUnits": 1
},
"StreamSpecification": {
"StreamViewType": "NEW_AND_OLD_IMAGES"
}
}
}
},
"Outputs": {
Expand Down Expand Up @@ -548,4 +590,4 @@
}
}
}
}
}
3 changes: 3 additions & 0 deletions fixtures/1.service.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
]
}
}
},
{
"sns": "snsTopic"
}
],
"deploymentSettings": {
Expand Down
Binary file added lib/.DS_Store
Binary file not shown.
23 changes: 23 additions & 0 deletions lib/CfTemplateGenerators/Sns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function replaceTopicSubscriptionFunctionWithAlias(snsTopic, functionAlias, functionName) {
const subscriptions = snsTopic.Properties.Subscription;

const isTargetSubscription = (subscription) => {
const endpoint = subscription.Endpoint || {};
const funcDetails = (endpoint['Fn::GetAtt'] || []);
const [funcName] = funcDetails;
return funcName ? funcName === functionName : false;
};

const restOfSubscriptions = subscriptions.filter(subscription => !isTargetSubscription(subscription));
const subscriptionWithAlias = { Endpoint: { Ref: functionAlias }, Protocol: 'lambda' };
const newSubscriptions = [...restOfSubscriptions, subscriptionWithAlias];

const newProperties = { ...snsTopic.Properties, Subscription: newSubscriptions };
return { ...snsTopic, Properties: newProperties };
}

const Sns = {
replaceTopicSubscriptionFunctionWithAlias
};

module.exports = Sns;
54 changes: 54 additions & 0 deletions lib/CfTemplateGenerators/Sns.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const { expect } = require('chai');
const Sns = require('./Sns');

describe('Sns', () => {
describe('.replaceTopicSubscriptionFunctionWithAlias', () => {
const functionName = 'HelloLambdaFunction';
const snsTopic = {
Type: 'AWS::SNS::Topic',
Properties: {
TopicName: 'snsTopic',
DisplayName: '',
Subscription: [
{
Endpoint: {
'Fn::GetAtt': [functionName, 'Arn']
},
Protocol: 'lambda'
},
{
Endpoint: {
'Fn::GetAtt': ['func', 'Arn']
},
Protocol: 'lambda'
}
]
}
};

it("replaces the topic subscription's function for an alias", () => {
const functionAlias = 'TheFunctionAlias';
const expected = {
Type: 'AWS::SNS::Topic',
Properties: {
TopicName: 'snsTopic',
DisplayName: '',
Subscription: [
{
Endpoint: {
'Fn::GetAtt': ['func', 'Arn']
},
Protocol: 'lambda'
},
{
Endpoint: { Ref: functionAlias },
Protocol: 'lambda'
}
]
}
};
const actual = Sns.replaceTopicSubscriptionFunctionWithAlias(snsTopic, functionAlias, functionName);
expect(actual).to.deep.equal(expected);
});
});
});
2 changes: 2 additions & 0 deletions lib/CfTemplateGenerators/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ const CodeDeploy = require('./CodeDeploy');
const Iam = require('./Iam');
const Lambda = require('./Lambda');
const ApiGateway = require('./ApiGateway');
const Sns = require('./Sns');

module.exports.codeDeploy = CodeDeploy;
module.exports.iam = Iam;
module.exports.lambda = Lambda;
module.exports.apiGateway = ApiGateway;
module.exports.sns = Sns;
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit cf5dca8

Please sign in to comment.