Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iotevents): support actions #18869

Merged
merged 32 commits into from
Mar 4, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
61a4bae
feat(iotevents): support actions
yamatatsu Feb 8, 2022
f3bdd56
fix code comments
yamatatsu Feb 8, 2022
940e1c7
remove redundant comments
yamatatsu Feb 8, 2022
5b86fa8
Update packages/@aws-cdk/aws-iotevents/README.md
yamatatsu Feb 9, 2022
7ad0532
Update packages/@aws-cdk/aws-iotevents/README.md
yamatatsu Feb 9, 2022
a021c79
Update packages/@aws-cdk/aws-iotevents/README.md
yamatatsu Feb 9, 2022
814e352
Update packages/@aws-cdk/aws-iotevents/README.md
yamatatsu Feb 9, 2022
2e9bca1
Update packages/@aws-cdk/aws-iotevents/README.md
yamatatsu Feb 9, 2022
a430030
address comments about README
yamatatsu Feb 9, 2022
31d3516
Update packages/@aws-cdk/aws-iotevents/lib/event.ts
yamatatsu Feb 9, 2022
7bd8f97
Update packages/@aws-cdk/aws-iotevents/lib/state.ts
yamatatsu Feb 9, 2022
ebfeeb2
Update packages/@aws-cdk/aws-iotevents/lib/state.ts
yamatatsu Feb 9, 2022
a123666
Update packages/@aws-cdk/aws-iotevents/lib/state.ts
yamatatsu Feb 9, 2022
20c47d2
Update packages/@aws-cdk/aws-iotevents/lib/state.ts
yamatatsu Feb 9, 2022
9e67025
Update packages/@aws-cdk/aws-iotevents/lib/state.ts
yamatatsu Feb 9, 2022
9a62326
Update packages/@aws-cdk/aws-iotevents/lib/state.ts
yamatatsu Feb 9, 2022
9cc9794
address comments
yamatatsu Feb 10, 2022
218b91e
address comments about tests
yamatatsu Feb 10, 2022
c7e142d
fix readme
yamatatsu Feb 12, 2022
9d7abc3
Merge branch 'master' into iotevents-actions
yamatatsu Feb 17, 2022
297e3b1
add sns action
yamatatsu Feb 21, 2022
8e4452b
lambda actions
yamatatsu Feb 28, 2022
6d80f69
write readme
yamatatsu Feb 28, 2022
011f1eb
add test for coverage
yamatatsu Feb 28, 2022
a8e6fd0
Merge branch 'master' into iotevents-actions
yamatatsu Feb 28, 2022
b686021
write readme
yamatatsu Mar 1, 2022
369562d
address comments
yamatatsu Mar 3, 2022
9f7ddf7
documentation
yamatatsu Mar 3, 2022
c0ccdf8
address commits
yamatatsu Mar 4, 2022
f9b8d8c
add link of actions to README
yamatatsu Mar 4, 2022
ea3059d
test behavior of action
yamatatsu Mar 4, 2022
de801e0
Merge branch 'master' into iotevents-actions
mergify[bot] Mar 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 171 additions & 25 deletions packages/@aws-cdk/aws-iotevents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,65 +40,211 @@ Import it into your code:
import * as iotevents from '@aws-cdk/aws-iotevents';
```

## `DetectorModel`
## Overview
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved

The following example creates an AWS IoT Events detector model to your stack.
The detector model need a reference to at least one AWS IoT Events input.
AWS IoT Events inputs enable the detector to get MQTT payload values from IoT Core rules.
The following example is a minimal set of an AWS IoT Events detector model.
It has no feature but it maybe help you to understand overview.

```ts
import * as iotevents from '@aws-cdk/aws-iotevents';

// First, define the input of the detector model
const input = new iotevents.Input(this, 'MyInput', {
inputName: 'my_input', // optional
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved
attributeJsonPaths: ['payload.deviceId', 'payload.temperature'],
});

const warmState = new iotevents.State({
// Second, define states of the detector model.
// You can define multiple states and its transitions.
const state = new iotevents.State({
stateName: 'warm',
onEnter: [{
eventName: 'test-event',
eventName: 'onEnter',
condition: iotevents.Expression.currentInput(input),
}],
});
const coldState = new iotevents.State({
stateName: 'cold',

// Finally, define the detector model.
new iotevents.DetectorModel(this, 'MyDetectorModel', {
initialState: state,
});
```

// transit to coldState when temperature is 10
warmState.transitionTo(coldState, {
Each part is explained in detail below.

## `Input`
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved

You can create `Input` as following. You can put messages to the Input with AWS IoT Core Topic Rule, AWS IoT Analytics and more.
For more information, see [the documentation](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-getting-started.html).

```ts
import * as iotevents from '@aws-cdk/aws-iotevents';

const input = new iotevents.Input(this, 'MyInput', {
inputName: 'my_input', // optional
attributeJsonPaths: ['payload.deviceId', 'payload.temperature'],
});
```

To grant permissions to put messages in the input,
you can use the `grantWrite()` method:

```ts
import * as iam from '@aws-cdk/aws-iam';
import * as iotevents from '@aws-cdk/aws-iotevents';

declare const grantable: iam.IGrantable;
const input = iotevents.Input.fromInputName(this, 'MyInput', 'my_input');
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved

input.grantWrite(grantable);
```

## `State`

You can create `State` as following.
In `onEnter` of a detector model's initial state, at least one reference of input via `condition` is needed.
And if the `condition` is evaluated to `TRUE`, the detector instance are created.
You can set the reference of input with `iotevents.Expression.currentInput()` or `iotevents.Expression.inputAttribute()` as following.
In other states, `onEnter` is optional.

```ts
import * as iotevents from '@aws-cdk/aws-iotevents';

declare const input: iotevents.IInput;

const initialState = new iotevents.State({
stateName: 'MyState',
onEnter: [{
eventName: 'onEnter',
condition: iotevents.Expression.currentInput(input),
}],
});
```

You can set actions to the `onEnter` event. It is caused if `condition` is evaluated to `TRUE`.
If you omit `condition`, actions is caused on every enter events of the state.
For more information, see [supported actions](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-supported-actions.html).

```ts
import * as iotevents from '@aws-cdk/aws-iotevents';

declare const input: iotevents.IInput;

const setTemperatureAction = {
bind: () => ({
configuration: {
setVariable: { variableName: 'temperature', value: temperatureAttr.evaluate() },
},
}),
};

const state = new iotevents.State({
stateName: 'MyState',
onEnter: [{ // optional
eventName: 'onEnter',
actions: [setTemperatureAction], // optional
condition: iotevents.Expression.eq(
iotevents.Expression.inputAttribute(input, 'payload.temperature'),
iotevents.Expression.fromString('10'),
), // optional
}],
});
```

Also you can use `onInput` and `onExit`. `onInput` is triggered when messages are put to the input
that is refered from the detector model. `onExit` is triggered when exiting this state.
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved

```ts
import * as iotevents from '@aws-cdk/aws-iotevents';

const state = new iotevents.State({
stateName: 'warm',
onEnter: [{ // optional
eventName: 'onEnter',
}],
onInput: [{ // optional
eventName: 'onInput',
}],
onExit: [{ // optional
eventName: 'onExit',
}],
});
```

You can set transitions of the states as following:

```ts
import * as iotevents from '@aws-cdk/aws-iotevents';

declare const input: iotevents.IInput;
declare const action: iotevents.IAction;
declare const stateA: iotevents.State;
declare const stateB: iotevents.State;

// transit from stateA to stateB when temperature is 10
stateA.transitionTo(stateB, {
eventName: 'to_coldState', // optional property, default by combining the names of the States
actions: [action], // optional,
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved
when: iotevents.Expression.eq(
iotevents.Expression.inputAttribute(input, 'payload.temperature'),
iotevents.Expression.fromString('10'),
),
});
// transit to warmState when temperature is 20
coldState.transitionTo(warmState, {
when: iotevents.Expression.eq(
iotevents.Expression.inputAttribute(input, 'payload.temperature'),
iotevents.Expression.fromString('20'),
),
});
```

## `DetectorModel`

You can create `DetectorModel` as following.
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved

```ts
import * as iotevents from '@aws-cdk/aws-iotevents';

declare const state: iotevents.State;

new iotevents.DetectorModel(this, 'MyDetectorModel', {
detectorModelName: 'test-detector-model', // optional
description: 'test-detector-model-description', // optional property, default is none
evaluationMethod: iotevents.EventEvaluation.SERIAL, // optional property, default is iotevents.EventEvaluation.BATCH
detectorKey: 'payload.deviceId', // optional property, default is none and single detector instance will be created and all inputs will be routed to it
initialState: warmState,
initialState: state,
});
```

To grant permissions to put messages in the input,
you can use the `grantWrite()` method:
## Examples

The following example creates an AWS IoT Events detector model to your stack.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's an idea. Instead of putting a big example here, how about we use the "literal snapshot test" feature the CDK offers? Basically, you put a reference to an integration test inside here, and the final rendered ReadMe will contain that test in it. Here's an example from the CodePipeline ReadMe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great! I was just thinking that I would like to post some of these examples as well.
I will move this example to aws-iotevents-actions because finally this example use actions😉.

The State of this detector model transits according to the temperature.

```ts
import * as iam from '@aws-cdk/aws-iam';
import * as iotevents from '@aws-cdk/aws-iotevents';

declare const grantable: iam.IGrantable;
const input = iotevents.Input.fromInputName(this, 'MyInput', 'my_input');
const input = new iotevents.Input(this, 'MyInput', {
attributeJsonPaths: ['payload.deviceId', 'payload.temperature'],
});

input.grantWrite(grantable);
const warmState = new iotevents.State({
stateName: 'warm',
onEnter: [{
eventName: 'onEnter',
condition: iotevents.Expression.currentInput(input),
}],
});
const coldState = new iotevents.State({
stateName: 'cold',
});

const temperatureEqual = (temperature: string) =>
iotevents.Expression.eq(
iotevents.Expression.inputAttribute(input, 'payload.temperature'),
iotevents.Expression.fromString('10'),
)

// transit to coldState when temperature is 10
warmState.transitionTo(coldState, { when: temperatureEqual('10') });
// transit to warmState when temperature is 20
coldState.transitionTo(warmState, { when: temperatureEqual('20') });

new iotevents.DetectorModel(this, 'MyDetectorModel', {
detectorKey: 'payload.deviceId',
initialState: warmState,
});
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved
```
24 changes: 24 additions & 0 deletions packages/@aws-cdk/aws-iotevents/lib/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { IDetectorModel } from './detector-model';
import { CfnDetectorModel } from './iotevents.generated';

/**
* An abstract action for DetectorModel.
*/
export interface IAction {
/**
* Returns the detector model action specification.
*
* @param detectorModel The DetectorModel that would trigger this action.
*/
bind(detectorModel: IDetectorModel): ActionConfig;
}

/**
* Properties for a detector model action
*/
export interface ActionConfig {
/**
* The configuration for this action.
*/
readonly configuration: CfnDetectorModel.ActionProperty;
}
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-iotevents/lib/detector-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class DetectorModel extends Resource implements IDetectorModel {
key: props.detectorKey,
detectorModelDefinition: {
initialStateName: props.initialState.stateName,
states: props.initialState._collectStateJsons(new Set<State>()),
states: props.initialState.bind(this),
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved
},
roleArn: role.roleArn,
});
Expand Down
8 changes: 8 additions & 0 deletions packages/@aws-cdk/aws-iotevents/lib/event.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IAction } from './action';
import { Expression } from './expression';

/**
Expand All @@ -15,4 +16,11 @@ export interface Event {
* @default - none (the actions are always executed)
*/
readonly condition?: Expression;

/**
* The actions to be performed.
*
* @default - none
yamatatsu marked this conversation as resolved.
Show resolved Hide resolved
*/
readonly actions?: IAction[];
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-iotevents/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './action';
export * from './detector-model';
export * from './event';
export * from './expression';
Expand Down
Loading