Repository: serverless/serverless (JavaScript)
Date: 2016-10-28 15:47:28+00:00
Task type: Feature

Issue:
Support Input and inputPath options in AWS::Events::Rule for schedule events
# This is a Feature Proposal
## Description

At the moment there is no way to pass a predefined input (or an input path) to a schedule event (`AWS::Events::Rule`).

For this purposes Amazon Cloud Formation offers the options `Input` and `InputPath` as documented [here](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html)

e.g.

``` json
{
  "Arn" : "some string",
  "Id" : "some string",
  "Input" : "some string",
  "InputPath" : "some string"
}
```
## Sample use cases
- When you run a lambda with a cron and you want to provide specific custom data to the event (environment dependent variables, configuration attributes, etc.)
## Expected resolution
- Add the support for `Input` and `InputPath` options in `serverless.yml` and then use these options in [plugins/aws/deploy/compile/events/schedule](https://github.com/serverless/serverless/blob/master/lib/plugins/aws/deploy/compile/events/schedule/index.js) to properly populate the [cloud formation template](https://github.com/serverless/serverless/blob/master/lib/plugins/aws/deploy/compile/events/schedule/index.js#L57-L69).

Support Input and inputPath options in AWS::Events::Rule for schedule events
# This is a Feature Proposal
## Description

At the moment there is no way to pass a predefined input (or an input path) to a schedule event (`AWS::Events::Rule`).

For this purposes Amazon Cloud Formation offers the options `Input` and `InputPath` as documented [here](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html)

e.g.

``` json
{
  "Arn" : "some string",
  "Id" : "some string",
  "Input" : "some string",
  "InputPath" : "some string"
}
```
## Sample use cases
- When you run a lambda with a cron and you want to provide specific custom data to the event (environment dependent variables, configuration attributes, etc.)
## Expected resolution
- Add the support for `Input` and `InputPath` options in `serverless.yml` and then use these options in [plugins/aws/deploy/compile/events/schedule](https://github.com/serverless/serverless/blob/master/lib/plugins/aws/deploy/compile/events/schedule/index.js) to properly populate the [cloud formation template](https://github.com/serverless/serverless/blob/master/lib/plugins/aws/deploy/compile/events/schedule/index.js#L57-L69).



Issue discussion:

Solution patch:
diff --git a/docs/providers/aws/events/schedule.md b/docs/providers/aws/events/schedule.md
index 6c7a1704c65..4dc7e6d0303 100644
--- a/docs/providers/aws/events/schedule.md
+++ b/docs/providers/aws/events/schedule.md
@@ -36,7 +36,13 @@ functions:
       - schedule:
           rate: rate(10 minutes)
           enabled: false
+          input:
+            key1: value1
+            key2: value2
+            stageParams:
+              stage: dev
       - schedule:
           rate: cron(0 12 * * ? *)
           enabled: false
+          inputPath: '$.stageVariables'
 ```
diff --git a/lib/plugins/aws/deploy/compile/events/schedule/index.js b/lib/plugins/aws/deploy/compile/events/schedule/index.js
index b5f72782bcd..97677a219c3 100644
--- a/lib/plugins/aws/deploy/compile/events/schedule/index.js
+++ b/lib/plugins/aws/deploy/compile/events/schedule/index.js
@@ -23,6 +23,8 @@ class AwsCompileScheduledEvents {
             scheduleNumberInFunction++;
             let ScheduleExpression;
             let State;
+            let Input;
+            let InputPath;
 
             // TODO validate rate syntax
             if (typeof event.schedule === 'object') {
@@ -38,6 +40,26 @@ class AwsCompileScheduledEvents {
               }
               ScheduleExpression = event.schedule.rate;
               State = event.schedule.enabled ? 'ENABLED' : 'DISABLED';
+              Input = event.schedule.input;
+              InputPath = event.schedule.inputPath;
+
+              if (Input && InputPath) {
+                const errorMessage = [
+                  'You can\'t set both input & inputPath properties at the',
+                  'same time for schedule events.',
+                  'Please check the AWS docs for more info',
+                ].join('');
+                throw new this.serverless.classes
+                  .Error(errorMessage);
+              }
+
+              if (Input && typeof Input === 'object') {
+                Input = JSON.stringify(Input);
+              }
+              if (Input && typeof Input === 'string') {
+                // escape quotes to favor JSON.parse
+                Input = Input.replace(/\"/g, '\\"'); // eslint-disable-line
+              }
             } else if (typeof event.schedule === 'string') {
               ScheduleExpression = event.schedule;
               State = 'ENABLED';
@@ -61,6 +83,8 @@ class AwsCompileScheduledEvents {
                   "ScheduleExpression": "${ScheduleExpression}",
                   "State": "${State}",
                   "Targets": [{
+                    ${Input ? `"Input": "${Input}",` : ''}
+                    ${InputPath ? `"InputPath": "${InputPath}",` : ''}
                     "Arn": { "Fn::GetAtt": ["${normalizedFunctionName}LambdaFunction", "Arn"] },
                     "Id": "${functionName}Schedule"
                   }]


Test patch:
diff --git a/lib/plugins/aws/deploy/compile/events/schedule/tests/index.js b/lib/plugins/aws/deploy/compile/events/schedule/tests/index.js
index 63343565081..8bfd21a5da6 100644
--- a/lib/plugins/aws/deploy/compile/events/schedule/tests/index.js
+++ b/lib/plugins/aws/deploy/compile/events/schedule/tests/index.js
@@ -101,6 +101,98 @@ describe('AwsCompileScheduledEvents', () => {
       ).to.equal('AWS::Lambda::Permission');
     });
 
+    it('should respect inputPath variable', () => {
+      awsCompileScheduledEvents.serverless.service.functions = {
+        first: {
+          events: [
+            {
+              schedule: {
+                rate: 'rate(10 minutes)',
+                enabled: false,
+                inputPath: '$.stageVariables',
+              },
+            },
+          ],
+        },
+      };
+
+      awsCompileScheduledEvents.compileScheduledEvents();
+
+      expect(awsCompileScheduledEvents.serverless.service
+        .provider.compiledCloudFormationTemplate.Resources.FirstEventsRuleSchedule1
+        .Properties.Targets[0].InputPath
+      ).to.equal('$.stageVariables');
+    });
+
+    it('should respect input variable', () => {
+      awsCompileScheduledEvents.serverless.service.functions = {
+        first: {
+          events: [
+            {
+              schedule: {
+                rate: 'rate(10 minutes)',
+                enabled: false,
+                input: '{"key":"value"}',
+              },
+            },
+          ],
+        },
+      };
+
+      awsCompileScheduledEvents.compileScheduledEvents();
+
+      expect(awsCompileScheduledEvents.serverless.service
+        .provider.compiledCloudFormationTemplate.Resources.FirstEventsRuleSchedule1
+        .Properties.Targets[0].Input
+      ).to.equal('{"key":"value"}');
+    });
+
+    it('should respect input variable as an object', () => {
+      awsCompileScheduledEvents.serverless.service.functions = {
+        first: {
+          events: [
+            {
+              schedule: {
+                rate: 'rate(10 minutes)',
+                enabled: false,
+                input: {
+                  key: 'value',
+                },
+              },
+            },
+          ],
+        },
+      };
+
+      awsCompileScheduledEvents.compileScheduledEvents();
+
+      expect(awsCompileScheduledEvents.serverless.service
+        .provider.compiledCloudFormationTemplate.Resources.FirstEventsRuleSchedule1
+        .Properties.Targets[0].Input
+      ).to.equal('{"key":"value"}');
+    });
+
+    it('should throw an error when both Input and InputPath are set', () => {
+      awsCompileScheduledEvents.serverless.service.functions = {
+        first: {
+          events: [
+            {
+              schedule: {
+                rate: 'rate(10 minutes)',
+                enabled: false,
+                input: {
+                  key: 'value',
+                },
+                inputPath: '$.stageVariables',
+              },
+            },
+          ],
+        },
+      };
+
+      expect(() => awsCompileScheduledEvents.compileScheduledEvents()).to.throw(Error);
+    });
+
     it('should not create corresponding resources when scheduled events are not given', () => {
       awsCompileScheduledEvents.serverless.service.functions = {
         first: {