UNPKG

4.63 kBJavaScriptView Raw
1var AWS = require('aws-sdk');
2var utils = require('../lib/utils');
3var Response = require('../lib/response');
4
5module.exports = SnsSubscription;
6
7/**
8 * Represents an SNS subscription
9 * @param {string} snsTopicArn - the ARN for the SNS topic to subscribe to
10 * @param {string} protocol - the subscription protocol
11 * @param {string} endpoint - the endpoint to subscribe to the SNS topic
12 * @param {string} [oldEndpoint] - the endpoint that was previously subscribed
13 */
14function SnsSubscription(snsTopicArn, protocol, endpoint, oldEndpoint) {
15 if (!snsTopicArn)
16 throw new Error('Missing Parameter SnsTopicArn');
17 if (!protocol)
18 throw new Error('Missing Parameter Protocol');
19 if (!endpoint)
20 throw new Error('Missing Parameter Endpoint');
21
22 this.snsTopicArn = snsTopicArn;
23 this.protocol = protocol;
24 this.endpoint = endpoint;
25 if (oldEndpoint) this.oldEndpoint = oldEndpoint;
26 this.sns = new AWS.SNS({ region: snsTopicArn.split(':')[3] });
27}
28
29/**
30 * A Lambda function to manage an SNS subscription in response to a CloudFormation event.
31 * @static
32 * @param {object} event - a Lambda invocation event sent from a custom CloudFormation resource
33 * @param {object} context - the Lambda invocation context
34 * @example
35 * // a custom CloudFormation resource that is backed by this Lambda function must
36 * // provide the ARN for this Lambda function, the ARN for an SNS topic, the
37 * // protocol and endpoint for the subscription.
38 * {
39 * "Type": "Custom::SnsSubscription",
40 * "Properties": {
41 * "ServiceToken": "arn:aws:lambda:us-east-1:123456789012:function/manage-sns-subscription",
42 * "SnsTopicArn": "arn:aws:sns:us-east-1:123456789012:my-sns-topic",
43 * "Protocol": "email",
44 * "Endpoint": "somebody@somewhere.com"
45 * }
46 * }
47 */
48SnsSubscription.manage = function(event, context) {
49 if (!utils.validCloudFormationEvent(event))
50 return context.done(null, 'ERROR: Invalid CloudFormation event');
51 var response = new Response(event, context);
52
53 var requestType = event.RequestType.toLowerCase();
54 var subscription;
55
56 try {
57 subscription = new SnsSubscription(
58 event.ResourceProperties.SnsTopicArn,
59 event.ResourceProperties.Protocol,
60 event.ResourceProperties.Endpoint,
61 event.OldResourceProperties ? event.OldResourceProperties.Endpoint : undefined
62 );
63 } catch (err) {
64 return response.send(err);
65 }
66 subscription[requestType](function(err) {
67 response.send(err);
68 });
69};
70
71/**
72 * Create the subscription
73 * @param {function} callback - a function to handle the response
74 */
75SnsSubscription.prototype.create = function(callback) {
76 var params = {
77 Protocol: this.protocol,
78 TopicArn: this.snsTopicArn,
79 Endpoint: this.endpoint
80 };
81 this.sns.subscribe(params, callback);
82};
83
84/**
85 * Update the subscription by unsubscribing an old endpoint and subscribing a new one
86 * @param {function} callback - a function to handle the response
87 */
88SnsSubscription.prototype.update = function(callback) {
89 var remove = this.delete.bind(this);
90 var create = this.create.bind(this);
91
92 remove(function(err) {
93 if (err) return callback(err);
94 create(callback);
95 });
96};
97
98/**
99 * Delete the subscription
100 * @param {function} callback - a function to handle the response
101 */
102SnsSubscription.prototype.delete = function(callback) {
103 var endpoint = this.oldEndpoint || this.endpoint;
104 var listParams = { TopicArn: this.snsTopicArn };
105 var snsSubscription = this;
106
107 console.log('Searching for subscription to delete: %s', endpoint);
108
109 (function listSubscriptions(next) {
110 if (next) listParams.NextToken = next;
111 snsSubscription.sns.listSubscriptionsByTopic(listParams, function(err, data) {
112 if (err && (err.code === 'NotFound' || err.code === 'InvalidParameter' || err.code === 'InvalidClientTokenId')) {
113 console.log('No topic %s found', listParams.TopicArn);
114 return callback();
115 }
116
117 if (err) return callback(err);
118
119 var arn = data.Subscriptions.filter(function(subscription) {
120 return subscription.Endpoint === endpoint;
121 }).map(function(subscription) {
122 return subscription.SubscriptionArn;
123 })[0];
124
125 var params = { SubscriptionArn: arn };
126
127 if (arn === 'PendingConfirmation') {
128 console.log('Found pending subscription');
129 return callback();
130 }
131
132 if (arn) {
133 console.log('Deleting subscription %s', arn);
134 return snsSubscription.sns.unsubscribe(params, callback);
135 }
136
137 if (data.NextToken) return listSubscriptions(data.NextToken);
138
139 console.log('No subscription found');
140 callback();
141 });
142 })();
143};