UNPKG

7.01 kBJavaScriptView Raw
1var AWS = require('aws-sdk');
2var utils = require('../lib/utils');
3var Response = require('../lib/response');
4
5module.exports = S3NotificationTopicConfig;
6
7/**
8* Represents an S3 Bucket Notification Configuration
9* @param {string} Id - an Id to identify the notification config
10* @param {string} snsTopicArn - the ARN for the SNS topic to get bucket notifications
11* @param {string} bucket - the S3 bucket to set notification configurations on
12* @param {string} bucketRegion - the region of the S3 bucket
13* @param {array} events - an array of events the topic will be notified on
14* @param {string} prefixFilter - string to filter prefixes on (optional) https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-filtering
15* @param {string} suffixFilter - string to filter suffixes on (optional) https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-filtering
16*/
17function S3NotificationTopicConfig(Id, snsTopicArn, bucket, bucketRegion, eventTypes, prefixFilter, suffixFilter, oldResources){
18 if(!Id)
19 throw new Error('Missing Parameter Id');
20 if(!snsTopicArn)
21 throw new Error('Missing Parameter SnsTopicArn');
22 if(!bucket)
23 throw new Error('Missing Parameter Bucket');
24 if(!bucketRegion)
25 throw new Error('Missing Parameter BucketRegion');
26 if(!eventTypes)
27 throw new Error('Missing Parameter Events');
28 if(!Array.isArray(eventTypes))
29 throw new Error('Events must be an Array');
30
31 this.id = Id;
32 this.snsTopicArn = snsTopicArn;
33 this.bucket = bucket;
34 this.bucketRegion = bucketRegion;
35 this.prefixFilter = (prefixFilter) ? prefixFilter : undefined;
36 this.suffixFilter = (suffixFilter) ? suffixFilter: undefined;
37 this.events = eventTypes;
38 if (oldResources) this.oldId = oldResources.Id;
39 if (oldResources) this.oldBucket = oldResources.Bucket;
40 if (oldResources) this.oldBucketRegion = oldResources.BucketRegion;
41
42 this.s3 = new AWS.S3({
43 params: { Bucket: bucket },
44 region: bucketRegion
45 });
46
47 this.olds3 = (oldResources) ? new AWS.S3({
48 params: { Bucket: oldResources.Bucket },
49 region: oldResources.BucketRegion
50 }) : undefined;
51}
52
53/**
54 * A Lambda function to manage an S3 Bucket Notification Topic Configuration in response to a CloudFormation event.
55 * @static
56 * @param {object} event - a Lambda invocation event sent from a custom CloudFormation resource
57 * @param {object} context - the Lambda invocation context
58 * @example
59 * // a custom CloudFormation resource that is backed by this Lambda function must
60 * // provide the ARN for this Lambda function, the ARN for an SNS topic, an
61 * // S3 bucket name, the S3 bucket's region, an array of filters to filter which notifications
62 * // the SNS topic will receive, and an array of events that the topic will be notified on.
63 * {
64 * "Type": "Custom::S3NotificationTopicConfig",
65 * "Properties": {
66 * "Id": "name of subscription"
67 * "ServiceToken": "arn:aws:lambda:us-east-1:123456789012:function/s3-bucket-notification-config",
68 * "SnsTopicArn": "arn:aws:sns:us-east-1:123456789012:my-s3-bucket-notification-config",
69 * "S3BucketName": "bucket",
70 * "S3BucketRegion": "us-east-1",
71 * "PrefixFilter": "prefix",
72 * "SuffixFilter": "jpg",
73 * "Events": [ 's3:ObjectCreated:*']
74 * }
75 * }
76 */
77
78 S3NotificationTopicConfig.manage = function(event, context) {
79 if (!utils.validCloudFormationEvent(event))
80 return context.done(null, 'ERROR: Invalid CloudFormation event');
81 var response = new Response(event, context);
82
83 var requestType = event.RequestType.toLowerCase();
84 var topicConfig;
85
86 try {
87 topicConfig = new S3NotificationTopicConfig(
88 event.ResourceProperties.Id,
89 event.ResourceProperties.SnsTopicArn,
90 event.ResourceProperties.Bucket,
91 event.ResourceProperties.BucketRegion,
92 event.ResourceProperties.EventTypes,
93 event.ResourceProperties.PrefixFilter,
94 event.ResourceProperties.SuffixFilter,
95 event.OldResourceProperties ? event.OldResourceProperties : undefined
96 );
97 } catch (err) {
98 return response.send(err);
99 }
100
101 topicConfig[requestType](function(err) {
102 response.send(err);
103 });
104 }
105
106 /**
107 * Create the notification configuration
108 * @param {function} callback - a function to handle the response
109 */
110S3NotificationTopicConfig.prototype.create = function(callback) {
111 var s3 = this.s3;
112 var topicArn = this.snsTopicArn;
113 var events = this.events;
114 var prefixFilter = this.prefixFilter;
115 var suffixFilter = this.suffixFilter;
116 var id = this.id;
117
118
119 s3.getBucketNotificationConfiguration(function(err, data) {
120 if (err) return callback(err);
121 var config = {
122 TopicArn: topicArn,
123 Events: events,
124 Id: id
125 };
126
127 if(prefixFilter || suffixFilter) {
128 config.Filter= { Key: { FilterRules: [] } };
129 if(prefixFilter) config.Filter.Key.FilterRules.push({ Name: 'Prefix', Value: prefixFilter });
130 if(suffixFilter) config.Filter.Key.FilterRules.push({ Name: 'Suffix', Value: suffixFilter });
131 }
132
133 var existingConfig;
134 if (data && data.TopicConfigurations) {
135 for(var idx = 0; idx < data.TopicConfigurations.length; idx++) {
136 if(id === data.TopicConfigurations[idx].Id) {
137 existingConfig = idx;
138 break;
139 }
140 }
141 }
142 else {
143 if(!data) data = {};
144 data.TopicConfigurations = [];
145 }
146
147 if(existingConfig > -1) {
148 data.TopicConfigurations.splice(existingConfig, 1, config);
149 }
150 else {
151 data.TopicConfigurations.push(config);
152 }
153 s3.putBucketNotificationConfiguration({ NotificationConfiguration: data }, (err) => {
154 if (err) return callback(err);
155 callback();
156 });
157 });
158}
159
160/**
161 * Update the notification configuration by removing it from the configuration and then creating it again
162 * @param {function} callback - a function to handle the response
163 */
164S3NotificationTopicConfig.prototype.update = function(callback) {
165 var remove = this.delete.bind(this);
166 var create = this.create.bind(this);
167
168 remove(function(err) {
169 if (err) return callback(err);
170 create(callback);
171 });
172}
173
174/**
175 * Delete the topic notification configuration
176 * @param {function} callback - a function to handle the response
177 */
178S3NotificationTopicConfig.prototype.delete = function(callback) {
179 var s3 = this.olds3 || this.s3;
180 var toDeleteId = this.oldId || this.id;
181
182 s3.getBucketNotificationConfiguration(function(err, data) {
183 if(err) return callback(err);
184 if(!data.TopicConfigurations) return callback();
185
186 var existingConfigIdx;
187 for(var idx = 0; idx < data.TopicConfigurations.length; idx++) {
188 if(this.id === data.TopicConfigurations[idx].Id) {
189 existingConfigIdx = idx;
190 break;
191 }
192 }
193
194 if(existingConfigIdx <= 0) return callback();
195 data.TopicConfigurations.splice(existingConfigIdx, 1);
196 s3.putBucketNotificationConfiguration( { NotificationConfiguration: data}, (err) => {
197 if (err) return callback(err);
198 callback();
199 });
200 });
201}
\No newline at end of file