diff --git a/lib/Actions.json b/lib/Actions.json index 76467f5f3..aed2c6d97 100644 --- a/lib/Actions.json +++ b/lib/Actions.json @@ -17,6 +17,7 @@ "./actions/EventDeployStreamLambda.js", "./actions/EventDeployS3Lambda.js", "./actions/EventDeploySNSLambda.js", + "./actions/EventDeployScheduledLambda.js", "./actions/DashDeploy.js", "./actions/DashSummary.js", "./actions/EndpointDeployApiGateway.js", diff --git a/lib/actions/EventDeploy.js b/lib/actions/EventDeploy.js index 146b66e09..89be46724 100644 --- a/lib/actions/EventDeploy.js +++ b/lib/actions/EventDeploy.js @@ -250,6 +250,8 @@ module.exports = function(SPlugin, serverlessPath) { subAction = 'eventDeployS3Lambda'; } else if (eventType === 'sns') { subAction = 'eventDeploySNSLambda'; + } else if (eventType === 'schedule') { + subAction = 'eventDeployScheduledLambda'; } diff --git a/lib/actions/EventDeployCloudWatchLogsLambda.js b/lib/actions/EventDeployCloudWatchLogsLambda.js deleted file mode 100644 index 58c84a80f..000000000 --- a/lib/actions/EventDeployCloudWatchLogsLambda.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict'; - -/** - */ - -module.exports = function(SPlugin, serverlessPath) { - - const path = require('path'), - SError = require(path.join(serverlessPath, 'ServerlessError')), - SUtils = require(path.join(serverlessPath, 'utils/index')), - BbPromise = require('bluebird'); - - - class EventDeployCloudWatchLogsLambda extends SPlugin { - - constructor(S, config) { - super(S, config); - } - - static getName() { - return 'serverless.core.' + EventDeployCloudWatchLogsLambda.name; - } - - registerActions() { - - this.S.addAction(this.eventDeployCloudWatchLogsLambda.bind(this), { - handler: 'eventDeployCloudWatchLogsLambda', - description: 'Deploy a CloudWatch Logs event source' - }); - - return BbPromise.resolve(); - } - - /** - * Code Package Lambda - */ - - eventDeployCloudWatchLogsLambda(evt) { - let _this = this; - _this.evt = evt; - - // Validate required properties - if (!_this.evt.options.stage || !_this.evt.options.region || !_this.evt.options.event || !_this.evt.options.event.config.lambdaArn || !_this.evt.options.event.config.filtername || !_this.evt.options.event.config.filterPattern || !_this.evt.options.event.config.logGroupName || !_this.evt.options.event.config.roleArn) { - return BbPromise.reject(new SError(`Missing stage, region or valid event.`)); - } - - let populatedEvent = _this.evt.options.event.getPopulated({stage: _this.evt.options.stage, region: _this.evt.options.region}); - - let awsConfig = { - region: _this.evt.options.region, - accessKeyId: _this.S.config.awsAdminKeyId, - secretAccessKey: _this.S.config.awsAdminSecretKey - }; - - _this.CloudWatchLogs = require('../CloudWatch')(awsConfig); - - // the AWS method creates or updates the subscription, so we don't need - // to check if we're updating or creating - let params = { - destinationArn: populatedEvent.config.lambdaArn, - filterName: populatedEvent.config.filterName, - filterPattern: populatedEvent.config.filterPattern, - logGroupName: populatedEvent.config.logGroupName, - roleArn: populatedEvent.config.roleArn - }; - - return _this.CloudWatchLogs.putSubscriptionFilterAsync(params) - .then(function(data) { - return BbPromise.resolve(data); - }) - } - } - - - return( EventDeployCloudWatchLogsLambda ); -}; diff --git a/lib/actions/EventDeployScheduledLambda.js b/lib/actions/EventDeployScheduledLambda.js new file mode 100644 index 000000000..2b2b2de90 --- /dev/null +++ b/lib/actions/EventDeployScheduledLambda.js @@ -0,0 +1,94 @@ +'use strict'; + +/** + * EventDeployScheduledLambda: + * Deploys a Schedule based event source. Allows for scheduling lambda functions. + * + * Options: + * - stage: stage to deploy event to + * - region: region to deploy event to + * - path: event path + */ + +module.exports = function (SPlugin, serverlessPath) { + + const path = require('path'), + SError = require(path.join(serverlessPath, 'ServerlessError')), + BbPromise = require('bluebird'); + + + class EventDeployScheduledLambda extends SPlugin { + + constructor(S, config) { + super(S, config); + } + + static getName() { + return 'serverless.core.' + EventDeployScheduledLambda.name; + } + + registerActions() { + + this.S.addAction(this.eventDeployScheduledLambda.bind(this), { + handler: 'eventDeployScheduledLambda', + description: 'Deploy a schedule based event source' + }); + + return BbPromise.resolve(); + } + + /** + * Event Deploy Scheduled Lambda + */ + + eventDeployScheduledLambda(evt) { + let _this = this; + _this.evt = evt; + + // Validate required properties + if (!_this.evt.options.stage || !_this.evt.options.region || !_this.evt.options.path) { + return BbPromise.reject(new SError(`Missing stage, region or path.`)); + } + let event = _this.S.state.getEvents({paths: [_this.evt.options.path]})[0], + populatedEvent = event.getPopulated({stage: _this.evt.options.stage, region: _this.evt.options.region}), + pathName = _this.evt.options.path.replace(/\//g, '-').replace('#', '-'), + awsAccountId = _this.S.state.meta.get().stages[_this.evt.options.stage].regions[_this.evt.options.region].variables.iamRoleArnLambda.split('::')[1].split(':')[0], + lambdaArn = "arn:aws:lambda:" + _this.evt.options.region + ":" + awsAccountId + ":function:" + _this.S.state.getProject().name + "-" + _this.evt.options.path.split('/')[0] + "-" + _this.evt.options.path.split('/')[1] + "-" + _this.evt.options.path.split('/')[2].split('#')[0]; + + populatedEvent.config.enabled = populatedEvent.config.enabled ? 'ENABLED' : 'DISABLED'; + + let awsConfig = { + region: _this.evt.options.region, + accessKeyId: _this.S.config.awsAdminKeyId, + secretAccessKey: _this.S.config.awsAdminSecretKey + }; + + _this.CloudWatchEvents = require('../utils/aws/CloudWatchEvents')(awsConfig); + + var params = { + Name: pathName, + ScheduleExpression: populatedEvent.config.schedule, + State: populatedEvent.config.enabled + }; + + return _this.CloudWatchEvents.putRuleAsync(params) + .then(function (data) { + let params = { + Rule: pathName, + Targets: [ + { + Arn: lambdaArn, + Id: pathName + } + ] + }; + return _this.CloudWatchEvents.putTargetsAsync(params); + }) + .then(function (data) { + return BbPromise.resolve(data); + }); + } + } + + return ( EventDeployScheduledLambda ); +}; \ No newline at end of file diff --git a/lib/utils/aws/CloudWatchEvents.js b/lib/utils/aws/CloudWatchEvents.js new file mode 100644 index 000000000..b813bc889 --- /dev/null +++ b/lib/utils/aws/CloudWatchEvents.js @@ -0,0 +1,19 @@ +'use strict'; + +/** + * Serverless Services: AWS: CloudWatchEvents + * - Prefix custom methods with "s" + */ + +let BbPromise = require('bluebird'), + AWS = require('aws-sdk'); + +module.exports = function(config) { + + // Promisify and configure instance + const CloudWatchEvents = BbPromise.promisifyAll(new AWS.CloudWatchEvents(config)); + + + // Return configured, customized instance + return CloudWatchEvents; +}; diff --git a/package.json b/package.json index a05cd8d0d..aed57bcfa 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "dependencies": { "async": "^0.9.0", - "aws-sdk": "^2.2.21", + "aws-sdk": "^2.2.33", "bluebird": "^2.9.34", "chalk": "^1.1.0", "cli-spinner": "^0.2.1", diff --git a/tests/test-prj/nodejscomponent/module1/function1/s-function.json b/tests/test-prj/nodejscomponent/module1/function1/s-function.json index f4ffc7196..f21aac660 100644 --- a/tests/test-prj/nodejscomponent/module1/function1/s-function.json +++ b/tests/test-prj/nodejscomponent/module1/function1/s-function.json @@ -29,6 +29,13 @@ "config": { "topicArn": "${topicArn}" } + }, + { + "name": "schedule", + "type": "schedule", + "config": { + "schedule": "rate(5 minutes)" + } } ], "endpoints": [ diff --git a/tests/tests/actions/EventDeploy.js b/tests/tests/actions/EventDeploy.js index bb7f82dd8..61fd50bdf 100644 --- a/tests/tests/actions/EventDeploy.js +++ b/tests/tests/actions/EventDeploy.js @@ -68,7 +68,6 @@ describe('Test Action: Event Deploy', function() { /** * Tests */ - describe('Event Deploy: DynamoDB', function() { it('should deploy DynamoDB stream event', function(done) { @@ -141,4 +140,28 @@ describe('Test Action: Event Deploy', function() { }); }); + describe('Event Deploy: Scheduled', function() { + it('should deploy schedule based event source', function(done) { + + this.timeout(0); + + let event = { + stage: config.stage, + region: config.region, + paths: [ + 'nodejscomponent/module1/function1#schedule' + ] + }; + + serverless.actions.eventDeploy(event) + .then(function(evt) { + validateEvent(evt); + done(); + }) + .catch(e => { + done(e); + }); + }); + }); + }); \ No newline at end of file