Skip to content

Commit

Permalink
fix(aws-events): ergonomics improvements to CloudWatch Events (#1570)
Browse files Browse the repository at this point in the history
Fixes the following things for CloudWatch events:

* Support newlines in CloudWatch Events textTemplate as intended, by making a newline-separated list of JSON strings. Fixes #1514.
*  `jsonTemplate` now accepts arbitrary objects. They will be JSONified automatically. Fixes #1198.
* Explicitly implement `IEventRuleTarget` on stepfunctions StateMachine so that Java/.NET users can trigger StateMachines using CloudWatch Events. Fixes part of #1275.
  • Loading branch information
rix0rrr authored and Sam Goodwin committed Jan 23, 2019
1 parent 206c577 commit 912d897
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 9 deletions.
3 changes: 3 additions & 0 deletions examples/cdk-examples-typescript/cloudwatch-events/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "node index"
}
25 changes: 25 additions & 0 deletions examples/cdk-examples-typescript/cloudwatch-events/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import events = require('@aws-cdk/aws-events');
import sns = require('@aws-cdk/aws-sns');
import cdk = require('@aws-cdk/cdk');

const app = new cdk.App();

class CloudWatchEventsExample extends cdk.Stack {
constructor(scope: cdk.App, id: string) {
super(scope, id);

const topic = new sns.Topic(this, 'TestTopic');

const event = new events.EventRule(this, 'Rule', {
scheduleExpression: 'rate(1 minute)'
});

event.addTarget(topic, {
textTemplate: 'one line\nsecond line'
});
}
}

new CloudWatchEventsExample(app, 'CWE-Example');

app.run();
1 change: 1 addition & 0 deletions examples/cdk-examples-typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@aws-cdk/aws-rds": "^0.22.0",
"@aws-cdk/aws-s3": "^0.22.0",
"@aws-cdk/aws-sns": "^0.22.0",
"@aws-cdk/aws-events": "^0.22.0",
"@aws-cdk/aws-sqs": "^0.22.0",
"@aws-cdk/cdk": "^0.22.0",
"@aws-cdk/runtime-values": "^0.22.0"
Expand Down
13 changes: 9 additions & 4 deletions packages/@aws-cdk/aws-events/lib/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export class EventRule extends Construct implements IEventRule {
*/
public addTarget(target?: IEventRuleTarget, inputOptions?: TargetInputTemplate) {
if (!target) { return; }
const self = this;

const targetProps = target.asEventRuleTarget(this.ruleArn, this.node.uniqueId);

Expand Down Expand Up @@ -145,11 +146,15 @@ export class EventRule extends Construct implements IEventRule {
let inputTemplate: any;

if (inputOptions.jsonTemplate) {
inputTemplate = inputOptions.jsonTemplate;
} else if (typeof(inputOptions.textTemplate) === 'string') {
inputTemplate = JSON.stringify(inputOptions.textTemplate);
inputTemplate = typeof inputOptions.jsonTemplate === 'string'
? inputOptions.jsonTemplate
: self.node.stringifyJson(inputOptions.jsonTemplate);
} else {
inputTemplate = `"${inputOptions.textTemplate}"`;
inputTemplate = typeof(inputOptions.textTemplate) === 'string'
// Newline separated list of JSON-encoded strings
? inputOptions.textTemplate.split('\n').map(x => self.node.stringifyJson(x)).join('\n')
// Some object, stringify it, then stringify the string for proper escaping
: self.node.stringifyJson(self.node.stringifyJson(inputOptions.textTemplate));
}

return {
Expand Down
121 changes: 119 additions & 2 deletions packages/@aws-cdk/aws-events/test/test.rule.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expect, haveResource } from '@aws-cdk/assert';
import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert';
import cdk = require('@aws-cdk/cdk');
import { Stack } from '@aws-cdk/cdk';
import { Test } from 'nodeunit';
Expand Down Expand Up @@ -351,5 +351,122 @@ export = {
test.deepEqual(importedRule.ruleArn, 'arn:of:rule');

test.done();
}
},

'json template': {
'can just be a JSON object'(test: Test) {
// GIVEN
const stack = new Stack();
const rule = new EventRule(stack, 'Rule', {
scheduleExpression: 'rate(1 minute)'
});

// WHEN
rule.addTarget(new SomeTarget(), {
jsonTemplate: { SomeObject: 'withAValue' },
});

// THEN
expect(stack).to(haveResourceLike('AWS::Events::Rule', {
Targets: [
{
InputTransformer: {
InputTemplate: "{\"SomeObject\":\"withAValue\"}"
},
}
]
}));
test.done();
},
},

'text templates': {
'strings with newlines are serialized to a newline-delimited list of JSON strings'(test: Test) {
// GIVEN
const stack = new Stack();
const rule = new EventRule(stack, 'Rule', {
scheduleExpression: 'rate(1 minute)'
});

// WHEN
rule.addTarget(new SomeTarget(), {
textTemplate: 'I have\nmultiple lines',
});

// THEN
expect(stack).to(haveResourceLike('AWS::Events::Rule', {
Targets: [
{
InputTransformer: {
InputTemplate: "\"I have\"\n\"multiple lines\""
},
}
]
}));

test.done();
},

'escaped newlines are not interpreted as newlines'(test: Test) {
// GIVEN
const stack = new Stack();
const rule = new EventRule(stack, 'Rule', {
scheduleExpression: 'rate(1 minute)'
});

// WHEN
rule.addTarget(new SomeTarget(), {
textTemplate: 'this is not\\na real newline',
});

// THEN
expect(stack).to(haveResourceLike('AWS::Events::Rule', {
Targets: [
{
InputTransformer: {
InputTemplate: "\"this is not\\\\na real newline\""
},
}
]
}));

test.done();
},

'can use Tokens in text templates'(test: Test) {
// GIVEN
const stack = new Stack();
const rule = new EventRule(stack, 'Rule', {
scheduleExpression: 'rate(1 minute)'
});

const world = new cdk.Token(() => 'world');

// WHEN
rule.addTarget(new SomeTarget(), {
textTemplate: `hello ${world}`,
});

// THEN
expect(stack).to(haveResourceLike('AWS::Events::Rule', {
Targets: [
{
InputTransformer: {
InputTemplate: "\"hello world\""
},
}
]
}));

test.done();
}
},
};

class SomeTarget implements IEventRuleTarget {
public asEventRuleTarget() {
return {
id: 'T1', arn: 'ARN1', kinesisParameters: { partitionKeyPath: 'partitionKeyPath' }
};
}
}
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export interface StateMachineProps {
/**
* Define a StepFunctions State Machine
*/
export class StateMachine extends cdk.Construct implements IStateMachine {
export class StateMachine extends cdk.Construct implements IStateMachine, events.IEventRuleTarget {
/**
* Import a state machine
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, haveResource } from '@aws-cdk/assert';
import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert';
import events = require('@aws-cdk/aws-events');
import iam = require('@aws-cdk/aws-iam');
import cdk = require('@aws-cdk/cdk');
import { Test } from 'nodeunit';
Expand Down Expand Up @@ -134,7 +135,36 @@ export = {
});

test.done();
}
},

'State machine can be used as Event Rule target'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const rule = new events.EventRule(stack, 'Rule', {
scheduleExpression: 'rate(1 minute)'
});
const stateMachine = new stepfunctions.StateMachine(stack, 'SM', {
definition: new stepfunctions.Wait(stack, 'Hello', { })
});

// WHEN
rule.addTarget(stateMachine, {
jsonTemplate: { SomeParam: 'SomeValue' },
});

// THEN
expect(stack).to(haveResourceLike('AWS::Events::Rule', {
Targets: [
{
InputTransformer: {
InputTemplate: "{\"SomeParam\":\"SomeValue\"}"
},
}
]
}));

test.done();
},
};

class FakeResource implements stepfunctions.IStepFunctionsTaskResource {
Expand Down

0 comments on commit 912d897

Please sign in to comment.