-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
rule.ts
220 lines (188 loc) · 6.89 KB
/
rule.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import { Construct, FnConcat, Token } from '@aws-cdk/cdk';
import { EventPattern } from './event-pattern';
import { cloudformation, RuleArn } from './events.generated';
import { TargetInputTemplate } from './input-options';
import { EventRuleRef } from './rule-ref';
import { IEventRuleTarget } from './target';
import { mergeEventPattern } from './util';
export interface EventRuleProps {
/**
* A description of the rule's purpose.
*/
description?: string;
/**
* A name for the rule. If you don't specify a name, AWS CloudFormation
* generates a unique physical ID and uses that ID for the rule name. For
* more information, see Name Type.
*/
ruleName?: string;
/**
* Indicates whether the rule is enabled.
* @default Rule is enabled
*/
enabled?: boolean;
/**
* The schedule or rate (frequency) that determines when CloudWatch Events
* runs the rule. For more information, see Schedule Expression Syntax for
* Rules in the Amazon CloudWatch User Guide.
*
* @see http://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html
*
* You must specify this property, the `eventPattern` property, or both.
*/
scheduleExpression?: string;
/**
* Describes which events CloudWatch Events routes to the specified target.
* These routed events are matched events. For more information, see Events
* and Event Patterns in the Amazon CloudWatch User Guide.
*
* @see
* http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CloudWatchEventsandEventPatterns.html
*
* You must specify this property (either via props or via
* `addEventPattern`), the `scheduleExpression` property, or both. The
* method `addEventPattern` can be used to add filter values to the event
* pattern.
*/
eventPattern?: EventPattern;
/**
* Targets to invoke when this rule matches an event.
*
* Input will be the full matched event. If you wish to specify custom
* target input, use `addTarget(target[, inputOptions])`.
*/
targets?: IEventRuleTarget[];
}
/**
* Defines a CloudWatch Event Rule in this stack.
*/
export class EventRule extends EventRuleRef {
public readonly ruleArn: RuleArn;
private readonly targets = new Array<cloudformation.RuleResource.TargetProperty>();
private readonly eventPattern: EventPattern = { };
private scheduleExpression?: string;
constructor(parent: Construct, name: string, props: EventRuleProps = { }) {
super(parent, name);
const resource = new cloudformation.RuleResource(this, 'Resource', {
description: props.description,
state: props.enabled == null ? 'ENABLED' : (props.enabled ? 'ENABLED' : 'DISABLED'),
scheduleExpression: new Token(() => this.scheduleExpression),
eventPattern: new Token(() => this.renderEventPattern()),
targets: new Token(() => this.renderTargets())
});
this.ruleArn = resource.ruleArn;
this.addEventPattern(props.eventPattern);
this.scheduleExpression = props.scheduleExpression;
for (const target of props.targets || []) {
this.addTarget(target);
}
}
/**
* Adds a target to the rule. The abstract class RuleTarget can be extended to define new
* targets.
*
* No-op if target is undefined.
*/
public addTarget(target?: IEventRuleTarget, inputOptions?: TargetInputTemplate) {
if (!target) { return; }
const targetProps = target.asEventRuleTarget(this.ruleArn, this.uniqueId);
// check if a target with this ID already exists
if (this.targets.find(t => t.id === targetProps.id)) {
throw new Error('Duplicate event rule target with ID: ' + targetProps.id);
}
this.targets.push({
...targetProps,
inputTransformer: renderTransformer(),
});
function renderTransformer(): cloudformation.RuleResource.InputTransformerProperty | undefined {
if (!inputOptions) {
return undefined;
}
if (inputOptions.jsonTemplate && inputOptions.textTemplate) {
throw new Error('"jsonTemplate" and "textTemplate" are mutually exclusive');
}
if (!inputOptions.jsonTemplate && !inputOptions.textTemplate) {
throw new Error('One of "jsonTemplate" or "textTemplate" are required');
}
let inputTemplate: any;
if (inputOptions.jsonTemplate) {
inputTemplate = inputOptions.jsonTemplate;
} else if (typeof(inputOptions.textTemplate) === 'string') {
inputTemplate = JSON.stringify(inputOptions.textTemplate);
} else {
inputTemplate = new FnConcat('"', inputOptions.textTemplate, '"');
}
return {
inputPathsMap: inputOptions.pathsMap,
inputTemplate
};
}
}
/**
* Adds an event pattern filter to this rule. If a pattern was already specified,
* these values are merged into the existing pattern.
*
* For example, if the rule already contains the pattern:
*
* {
* "resources": [ "r1" ],
* "detail": {
* "hello": [ 1 ]
* }
* }
*
* And `addEventPattern` is called with the pattern:
*
* {
* "resources": [ "r2" ],
* "detail": {
* "foo": [ "bar" ]
* }
* }
*
* The resulting event pattern will be:
*
* {
* "resources": [ "r1", "r2" ],
* "detail": {
* "hello": [ 1 ],
* "foo": [ "bar" ]
* }
* }
*
*/
public addEventPattern(eventPattern?: EventPattern) {
if (!eventPattern) {
return;
}
mergeEventPattern(this.eventPattern, eventPattern);
}
public validate() {
if (Object.keys(this.eventPattern).length === 0 && !this.scheduleExpression) {
return [ `Either 'eventPattern' or 'scheduleExpression' must be defined` ];
}
return [ ];
}
private renderTargets() {
if (this.targets.length === 0) {
return undefined;
}
return this.targets;
}
private renderEventPattern() {
const eventPattern = this.eventPattern;
if (Object.keys(eventPattern).length === 0) {
return undefined;
}
// rename 'detailType' to 'detail-type'
const out: any = {};
for (let key of Object.keys(eventPattern)) {
const value = (eventPattern as any)[key];
if (key === 'detailType') {
key = 'detail-type';
}
out[key] = value;
}
return out;
}
}