cloud-red
Version:
Harnessing Serverless for your cloud integration needs
158 lines (139 loc) • 4.77 kB
JavaScript
module.exports = function(RED) {
'use strict';
const claudia = require('claudia');
const AWS = require('aws-sdk');
const path = require('path');
/**
* Constructs an s3trigger
* @param {Object} props - S3 trigger properties
* @param {string} props.name - node label to be used
* @param {string} props.bucketName - S3 Bucket name which will push notifications to Lambda
* @param {string} props.prefix - (optional) Prefix filter for S3 keys that will cause the event
* @param {string} props.suffix - (optional) Suffix filter for S3 keys that will cause the event
* @param {string} props.version - (optional) Bind to a particular version. Defaults to: `latest` version
* @param {string} props.events - (optional) Comma separated list of event types that trigger the function. Defaults to: `s3:ObjectCreated:*`
* @param {string} props.description - (optional) General Description about this trigger
*
*/
class S3Trigger {
constructor(props) {
RED.nodes.createNode(this, props);
this.name = props.name;
this.bucketName = props.bucketName;
this.prefix = props.prefix;
this.suffix = props.suffix;
this.version = props.version;
this.events = props.events;
this.description = props.description;
this.postEditorDeployment = this.postEditorDeployment.bind(this);
RED.events.on('editor:post-deployment', this.postEditorDeployment);
this.on('close', () => {
// this.log('Removing listener');
RED.events.removeListener(
'editor:post-deployment',
this.postEditorDeployment
);
});
}
async getBucketNotifications(s3EventOpts) {
// Make sure the following event is not registered in the bucket
let events = this.events
? this.events.split(',')
: ['s3:ObjectCreated:*'];
AWS.config.credentials = new AWS.SharedIniFileCredentials({
profile: 'personal'
});
try {
const s3 = new AWS.S3();
const config = await s3
.getBucketNotificationConfiguration({
Bucket: s3EventOpts.bucket
})
.promise();
const exist = this.checkIfEventsExist(
config.LambdaFunctionConfigurations,
events
);
if (exist) {
this.log('Removing existing S3 Event Notification ...');
const result = await s3
.putBucketNotificationConfiguration({
Bucket: s3EventOpts.bucket,
NotificationConfiguration: {}
})
.promise();
return result;
}
} catch (err) {
console.log(err);
throw err;
}
}
checkIfEventsExist(lambdaConfigs, eventsToMatch) {
if (!lambdaConfigs && lambdaConfigs.length === 0) {
return false;
}
let BreakException = {}; // hack as there is no built-in ability to break in forEach. Js, c'mon!!
let found = false;
try {
lambdaConfigs.forEach(configs => {
if (!configs.Events && configs.Events.length === 0) {
found = false;
} else {
configs.Events.forEach(event => {
if (eventsToMatch.indexOf(event) >= 0) {
// found it
found = true;
throw BreakException;
}
});
}
});
} catch (error) {
if (error !== BreakException) throw e;
return found;
}
return found;
}
async postEditorDeployment() {
//RED.settings.getUserSettings();
this.log('Attaching s3 event to lambda...');
const userDir = RED.settings.userDir;
let s3EventOpts = {
bucket: this.bucketName, // mandatory
source: userDir,
config: path.join(userDir, 'cloud-red-config.json')
};
if (this.prefix) {
s3EventOpts.prefix = this.prefix;
}
if (this.suffix) {
s3EventOpts.suffix = this.suffix;
}
if (this.events) {
s3EventOpts.events = this.events;
}
// Clean up bucket notification if exists
try {
await this.getBucketNotifications(s3EventOpts);
} catch (err) {
throw err;
}
AWS.config.credentials = new AWS.SharedIniFileCredentials({
profile: 'personal'
});
claudia
.addS3EventSource(s3EventOpts)
.then(() => {
this.log(
`Lambda configured to receive S3 Event notification from bucket: ${this.bucketName}`
);
})
.catch(err => {
this.error('Error while attaching an S3 event to lambda');
console.log(err);
});
}
}
RED.nodes.registerType('s3-trigger', S3Trigger);
};