Skip to content

Commit e01654e

Browse files
authored
feat(iotevents): support actions (#18869)
This PR allow IoT Events detector model to perform actions as [this documentation](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-supported-actions.html). This PR is in roadmap of #17711. ![スクリーンショット 2022-02-08 22 43 33](https://user-images.githubusercontent.com/11013683/152999288-81721f15-fefb-4108-b34b-aab3f88a7ab8.png) With this fix, all the interfaces of the DetectorModel are now implemented! And next works is implementing expressions and actions. The exapmle in readme became not simple, so also this PR has sorted explanation of readme. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e7c0c75 commit e01654e

16 files changed

+608
-26
lines changed

packages/@aws-cdk/aws-iotevents-actions/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,33 @@
1818
This library contains integration classes to specify actions of state events of Detector Model in `@aws-cdk/aws-iotevents`.
1919
Instances of these classes should be passed to `State` defined in `@aws-cdk/aws-iotevents`
2020
You can define built-in actions to use a timer or set a variable, or send data to other AWS resources.
21+
22+
This library contains integration classes to use a timer or set a variable, or send data to other AWS resources.
23+
AWS IoT Events can trigger actions when it detects a specified event or transition event.
24+
25+
Currently supported are:
26+
27+
- Invoke a Lambda function
28+
29+
## Invoke a Lambda function
30+
31+
The code snippet below creates an Action that invoke a Lambda function
32+
when it is triggered.
33+
34+
```ts
35+
import * as iotevents from '@aws-cdk/aws-iotevents';
36+
import * as actions from '@aws-cdk/aws-iotevents-actions';
37+
import * as lambda from '@aws-cdk/aws-lambda';
38+
39+
declare const input: iotevents.IInput;
40+
declare const func: lambda.IFunction;
41+
42+
const state = new iotevents.State({
43+
stateName: 'MyState',
44+
onEnter: [{
45+
eventName: 'test-event',
46+
condition: iotevents.Expression.currentInput(input),
47+
actions: [new actions.LambdaInvokeAction(func)],
48+
}],
49+
});
50+
```
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
// this is placeholder for monocdk
2-
export const dummy = true;
1+
export * from './lambda-invoke-action';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as iotevents from '@aws-cdk/aws-iotevents';
2+
import * as lambda from '@aws-cdk/aws-lambda';
3+
import { Construct } from 'constructs';
4+
5+
/**
6+
* The action to write the data to an AWS Lambda function.
7+
*/
8+
export class LambdaInvokeAction implements iotevents.IAction {
9+
/**
10+
* @param func the AWS Lambda function to be invoked by this action
11+
*/
12+
constructor(private readonly func: lambda.IFunction) {
13+
}
14+
15+
bind(_scope: Construct, options: iotevents.ActionBindOptions): iotevents.ActionConfig {
16+
this.func.grantInvoke(options.role);
17+
return {
18+
configuration: {
19+
lambda: {
20+
functionArn: this.func.functionArn,
21+
},
22+
},
23+
};
24+
}
25+
}

packages/@aws-cdk/aws-iotevents-actions/package.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,19 @@
7878
"jest": "^27.5.1"
7979
},
8080
"dependencies": {
81-
"@aws-cdk/core": "0.0.0"
81+
"@aws-cdk/aws-iam": "0.0.0",
82+
"@aws-cdk/aws-iotevents": "0.0.0",
83+
"@aws-cdk/aws-lambda": "0.0.0",
84+
"@aws-cdk/core": "0.0.0",
85+
"constructs": "^3.3.69"
8286
},
8387
"homepage": "https://github.com/aws/aws-cdk",
8488
"peerDependencies": {
85-
"@aws-cdk/core": "0.0.0"
89+
"@aws-cdk/aws-iam": "0.0.0",
90+
"@aws-cdk/aws-iotevents": "0.0.0",
91+
"@aws-cdk/aws-lambda": "0.0.0",
92+
"@aws-cdk/core": "0.0.0",
93+
"constructs": "^3.3.69"
8694
},
8795
"engines": {
8896
"node": ">= 10.13.0 <13 || >=13.7.0"

packages/@aws-cdk/aws-iotevents-actions/test/iotevents-actions.test.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
{
2+
"Resources": {
3+
"MyInput08947B23": {
4+
"Type": "AWS::IoTEvents::Input",
5+
"Properties": {
6+
"InputDefinition": {
7+
"Attributes": [
8+
{
9+
"JsonPath": "payload.deviceId"
10+
}
11+
]
12+
},
13+
"InputName": "test_input"
14+
}
15+
},
16+
"MyFunctionServiceRole3C357FF2": {
17+
"Type": "AWS::IAM::Role",
18+
"Properties": {
19+
"AssumeRolePolicyDocument": {
20+
"Statement": [
21+
{
22+
"Action": "sts:AssumeRole",
23+
"Effect": "Allow",
24+
"Principal": {
25+
"Service": "lambda.amazonaws.com"
26+
}
27+
}
28+
],
29+
"Version": "2012-10-17"
30+
},
31+
"ManagedPolicyArns": [
32+
{
33+
"Fn::Join": [
34+
"",
35+
[
36+
"arn:",
37+
{
38+
"Ref": "AWS::Partition"
39+
},
40+
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
41+
]
42+
]
43+
}
44+
]
45+
}
46+
},
47+
"MyFunction3BAA72D1": {
48+
"Type": "AWS::Lambda::Function",
49+
"Properties": {
50+
"Code": {
51+
"ZipFile": "\n exports.handler = (event) => {\n console.log(\"It is test for lambda action of AWS IoT Rule.\", event);\n };"
52+
},
53+
"Role": {
54+
"Fn::GetAtt": [
55+
"MyFunctionServiceRole3C357FF2",
56+
"Arn"
57+
]
58+
},
59+
"Handler": "index.handler",
60+
"Runtime": "nodejs14.x"
61+
},
62+
"DependsOn": [
63+
"MyFunctionServiceRole3C357FF2"
64+
]
65+
},
66+
"MyDetectorModelDetectorModelRoleF2FB4D88": {
67+
"Type": "AWS::IAM::Role",
68+
"Properties": {
69+
"AssumeRolePolicyDocument": {
70+
"Statement": [
71+
{
72+
"Action": "sts:AssumeRole",
73+
"Effect": "Allow",
74+
"Principal": {
75+
"Service": "iotevents.amazonaws.com"
76+
}
77+
}
78+
],
79+
"Version": "2012-10-17"
80+
}
81+
}
82+
},
83+
"MyDetectorModelDetectorModelRoleDefaultPolicy82887422": {
84+
"Type": "AWS::IAM::Policy",
85+
"Properties": {
86+
"PolicyDocument": {
87+
"Statement": [
88+
{
89+
"Action": "lambda:InvokeFunction",
90+
"Effect": "Allow",
91+
"Resource": {
92+
"Fn::GetAtt": [
93+
"MyFunction3BAA72D1",
94+
"Arn"
95+
]
96+
}
97+
}
98+
],
99+
"Version": "2012-10-17"
100+
},
101+
"PolicyName": "MyDetectorModelDetectorModelRoleDefaultPolicy82887422",
102+
"Roles": [
103+
{
104+
"Ref": "MyDetectorModelDetectorModelRoleF2FB4D88"
105+
}
106+
]
107+
}
108+
},
109+
"MyDetectorModel559C0B0E": {
110+
"Type": "AWS::IoTEvents::DetectorModel",
111+
"Properties": {
112+
"DetectorModelDefinition": {
113+
"InitialStateName": "MyState",
114+
"States": [
115+
{
116+
"OnEnter": {
117+
"Events": [
118+
{
119+
"Actions": [
120+
{
121+
"Lambda": {
122+
"FunctionArn": {
123+
"Fn::GetAtt": [
124+
"MyFunction3BAA72D1",
125+
"Arn"
126+
]
127+
}
128+
}
129+
}
130+
],
131+
"Condition": {
132+
"Fn::Join": [
133+
"",
134+
[
135+
"currentInput(\"",
136+
{
137+
"Ref": "MyInput08947B23"
138+
},
139+
"\")"
140+
]
141+
]
142+
},
143+
"EventName": "test-event"
144+
}
145+
]
146+
},
147+
"OnInput": {},
148+
"StateName": "MyState"
149+
}
150+
]
151+
},
152+
"RoleArn": {
153+
"Fn::GetAtt": [
154+
"MyDetectorModelDetectorModelRoleF2FB4D88",
155+
"Arn"
156+
]
157+
},
158+
"Key": "payload.deviceId"
159+
}
160+
}
161+
}
162+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* Stack verification steps:
3+
* * put a message
4+
* * aws iotevents-data batch-put-message --messages=messageId=(date | md5),inputName=test_input,payload=(echo '{"payload":{"temperature":31.9,"deviceId":"000"}}' | base64)
5+
* * verify that the lambda logs be put
6+
*/
7+
import * as iotevents from '@aws-cdk/aws-iotevents';
8+
import * as lambda from '@aws-cdk/aws-lambda';
9+
import * as cdk from '@aws-cdk/core';
10+
import * as actions from '../../lib';
11+
12+
class TestStack extends cdk.Stack {
13+
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
14+
super(scope, id, props);
15+
16+
const input = new iotevents.Input(this, 'MyInput', {
17+
inputName: 'test_input',
18+
attributeJsonPaths: ['payload.deviceId'],
19+
});
20+
const func = new lambda.Function(this, 'MyFunction', {
21+
runtime: lambda.Runtime.NODEJS_14_X,
22+
handler: 'index.handler',
23+
code: lambda.Code.fromInline(`
24+
exports.handler = (event) => {
25+
console.log("It is test for lambda action of AWS IoT Rule.", event);
26+
};`,
27+
),
28+
});
29+
30+
const state = new iotevents.State({
31+
stateName: 'MyState',
32+
onEnter: [{
33+
eventName: 'test-event',
34+
condition: iotevents.Expression.currentInput(input),
35+
actions: [new actions.LambdaInvokeAction(func)],
36+
}],
37+
});
38+
39+
new iotevents.DetectorModel(this, 'MyDetectorModel', {
40+
detectorKey: 'payload.deviceId',
41+
initialState: state,
42+
});
43+
}
44+
}
45+
46+
const app = new cdk.App();
47+
new TestStack(app, 'lambda-invoke-action-test-stack');
48+
app.synth();
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { Template } from '@aws-cdk/assertions';
2+
import * as iotevents from '@aws-cdk/aws-iotevents';
3+
import * as lambda from '@aws-cdk/aws-lambda';
4+
import * as cdk from '@aws-cdk/core';
5+
import * as actions from '../../lib';
6+
7+
let stack: cdk.Stack;
8+
let input: iotevents.IInput;
9+
let func: lambda.IFunction;
10+
beforeEach(() => {
11+
stack = new cdk.Stack();
12+
input = iotevents.Input.fromInputName(stack, 'MyInput', 'test-input');
13+
func = lambda.Function.fromFunctionAttributes(stack, 'MyFunction', {
14+
functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn',
15+
sameEnvironment: true,
16+
});
17+
});
18+
19+
test('Default property', () => {
20+
// WHEN
21+
new iotevents.DetectorModel(stack, 'MyDetectorModel', {
22+
initialState: new iotevents.State({
23+
stateName: 'test-state',
24+
onEnter: [{
25+
eventName: 'test-eventName',
26+
condition: iotevents.Expression.currentInput(input),
27+
actions: [new actions.LambdaInvokeAction(func)],
28+
}],
29+
}),
30+
});
31+
32+
// THEN
33+
Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::DetectorModel', {
34+
DetectorModelDefinition: {
35+
States: [{
36+
OnEnter: {
37+
Events: [{
38+
Actions: [{
39+
Lambda: {
40+
FunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn',
41+
},
42+
}],
43+
}],
44+
},
45+
}],
46+
},
47+
RoleArn: {
48+
'Fn::GetAtt': ['MyDetectorModelDetectorModelRoleF2FB4D88', 'Arn'],
49+
},
50+
});
51+
52+
Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', {
53+
PolicyDocument: {
54+
Statement: [{
55+
Action: 'lambda:InvokeFunction',
56+
Effect: 'Allow',
57+
Resource: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn',
58+
}],
59+
},
60+
Roles: [{
61+
Ref: 'MyDetectorModelDetectorModelRoleF2FB4D88',
62+
}],
63+
});
64+
});

0 commit comments

Comments
 (0)