Skip to content

Commit

Permalink
feat(iot): support the TopicRule L2 construct
Browse files Browse the repository at this point in the history
1. add The TopicRule L2 construct
2. add unit tests
3. add integration test
4. update package.json
  • Loading branch information
yamatatsu committed Oct 6, 2021
1 parent ecb94d7 commit e6c26f5
Show file tree
Hide file tree
Showing 51 changed files with 4,853 additions and 2 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@
"@aws-cdk/aws-eks/yaml/**",
"@aws-cdk/aws-events-targets/aws-sdk",
"@aws-cdk/aws-events-targets/aws-sdk/**",
"@aws-cdk/aws-iot-alpha/case",
"@aws-cdk/aws-iot-alpha/case/**",
"@aws-cdk/aws-iot/case",
"@aws-cdk/aws-iot/case/**",
"@aws-cdk/aws-s3-deployment/case",
"@aws-cdk/aws-s3-deployment/case/**",
"@aws-cdk/cloud-assembly-schema/jsonschema",
Expand Down
30 changes: 30 additions & 0 deletions packages/@aws-cdk/aws-iot/NOTICE
Original file line number Diff line number Diff line change
@@ -1,2 +1,32 @@
AWS Cloud Development Kit (AWS CDK)
Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.

-------------------------------------------------------------------------------

The AWS CDK includes the following third-party software/licensing:

** case - https://www.npmjs.com/package/case
Copyright (c) 2013 Nathan Bubna

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

----------------
145 changes: 145 additions & 0 deletions packages/@aws-cdk/aws-iot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,153 @@
>
> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib
![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge)

> The APIs of higher level constructs in this module are experimental and under active development.
> They are subject to non-backward compatible changes or removal in any future version. These are
> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be
> announced in the release notes. This means that while you may use them, you may need to update
> your source code when upgrading to a newer version of this package.
---

<!--END STABILITY BANNER-->

This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.

## Rules

The `TopicRule` construct defined Rules that give your devices the ability to interact with AWS services.
Rules are analyzed and actions are performed based on the MQTT topic stream.
The `TopicRule` construct can use actions like these:

- Write data received from a device to an Amazon DynamoDB database.
- Save a file to Amazon S3.
- Send a push notification to all users using Amazon SNS.
- Publish data to an Amazon SQS queue.
- Invoke a Lambda function to extract data.
- Process messages from a large number of devices using Amazon Kinesis. (*To be developed*)
- Send data to the Amazon OpenSearch Service. (*To be developed*)
- Capture a CloudWatch metric.
- Change a CloudWatch alarm.
- Send message data to an AWS IoT Analytics channel. (*To be developed*)
- Start execution of a Step Functions state machine. (*To be developed*)
- Send message data to an AWS IoT Events input. (*To be developed*)
- Send message data an asset property in AWS IoT SiteWise. (*To be developed*)
- Send message data to a web application or service. (*To be developed*)

For example, to define a rule that triggers to invoke a lambda function and to put to a S3 bucket:

```ts
new TopicRule(stack, 'MyTopicRule', {
topicRuleName: 'MyRuleName', // optional property
topicRulePayload: {
description: 'Some description.', // optional property
sql: "SELECT topic(2) as device_id, temperature FROM 'device/+/data'",
acctions: [
new actions.LambdaAction(lambdaFn),
new actions.S3Action(bucket),
],
},
});
```

Or you can add action after constructing instance as following:

```ts
const topicRule = new TopicRule(stack, 'MyTopicRule', {
topicRulePayload: {
sql: "SELECT topic(2) as device_id, temperature FROM 'device/+/data'",
},
});
topicRule.addAction(new actions.LambdaAction(lambdaFn));
```

If a problem occurs when triggering actions, the rules engine triggers an error action, if one is specified for the rule:

```ts
new TopicRule(stack, 'MyTopicRule', {
topicRulePayload: {
sql: "SELECT topic(2) as device_id, temperature FROM 'device/+/data'",
errorAction: new actions.CloudwatchLogsAction(logGroup),
},
});
```

### Add action to set state of an Amazon CloudWatch alarm

```ts
topicRule.addAction(
new iot.CloudwatchAlarmAction(
cloudwatchAlarm,
cloudwatch.AlarmState.ALARM,
),
);
```

### Add action to send data to Amazon CloudWatch Logs

```ts
topicRule.addAction(new iot.CloudwatchLogsAction(logGroup));
```

### Add action to capture an Amazon CloudWatch metric

```ts
topicRule.addAction(new iot.CloudwatchMetricAction({
metricName: '${topic(2)}',
metricNamespace: '${namespace}',
metricUnit: '${unit}',
metricValue: '${value}',
metricTimestamp: '${timestamp}',
}));
```

### Add action to write all or part of an MQTT message to an Amazon DynamoDB table

```ts
topicRule.addAction(new iot.DynamoDBAction({
table,
partitionKeyValue: '${topic(2)}',
sortKeyValue: '${timestamp()}',
payloadField: 'custom-payload-field',
}));
```

Or you can define more easily with dynamodb v2 action:

```ts
topicRule.addAction(new iot.DynamoDBv2Action(table));
```

Dynamodb v2 action is easy to use, but only v1 action supports [substitution templates](https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html).

### Add action to invoke an AWS Lambda function, passing in an MQTT message

```ts
topicRule.addAction(new actions.LambdaAction(lambdaFn));
```

### Add action to republish an MQTT message to another MQTT topic

```ts
topicRule.addAction(new iot.RepublishAction('test-topic'));
```

### Add action to write the data from an MQTT message to an Amazon S3 bucket

```ts
topicRule.addAction(new iot.S3Action(bucket));
```

### Add action to send the data from an MQTT message as an Amazon SNS push notification

```ts
topicRule.addAction(new iot.SnsAction(topic));
```

### Add action to send data from an MQTT message to an Amazon SQS queue

```ts
topicRule.addAction(new iot.SqsAction(queue));
```
120 changes: 120 additions & 0 deletions packages/@aws-cdk/aws-iot/lib/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { CfnTopicRule } from './iot.generated';
import { ITopicRule } from './topic-rule-ref';

/**
* An abstract action for TopicRule.
*/
export interface IAction {
/**
* Returns the topic rule action specification.
*
* @param rule The TopicRule that would trigger this action.
*/
bind(rule: ITopicRule): ActionConfig;
}

/**
* Properties for an topic rule action
*/
export interface ActionConfig {
/**
* An action to set state of an Amazon CloudWatch alarm.
* @default None
*/
readonly cloudwatchAlarm?: CfnTopicRule.CloudwatchAlarmActionProperty;
/**
* An action to send data to Amazon CloudWatch Logs.
* @default None
*/
readonly cloudwatchLogs?: CfnTopicRule.CloudwatchLogsActionProperty;
/**
* An action to capture an Amazon CloudWatch metric.
* @default None
*/
readonly cloudwatchMetric?: CfnTopicRule.CloudwatchMetricActionProperty;
/**
* An action to write all or part of an MQTT message to an Amazon DynamoDB table.
* @default None
*/
readonly dynamoDb?: CfnTopicRule.DynamoDBActionProperty;
/**
* An action to write all or part of an MQTT message to an Amazon DynamoDB table.
* @default None
*/
readonly dynamoDBv2?: CfnTopicRule.DynamoDBv2ActionProperty;
/**
* An action to write data from MQTT messages to an Amazon OpenSearch Service domain.
* @default None
*/
readonly elasticsearch?: CfnTopicRule.ElasticsearchActionProperty;
/**
* An action to send data from an MQTT message to an Amazon Kinesis Data Firehose stream.
* @default None
*/
readonly firehose?: CfnTopicRule.FirehoseActionProperty;
/**
* An action to send data from an MQTT message to a web application or service.
* @default None
*/
readonly http?: CfnTopicRule.HttpActionProperty;
/**
* An action to send data from an MQTT message to an AWS IoT Analytics channel.
* @default None
*/
readonly iotAnalytics?: CfnTopicRule.IotAnalyticsActionProperty;
/**
* An action to send data from an MQTT message to an AWS IoT Events input.
* @default None
*/
readonly iotEvents?: CfnTopicRule.IotEventsActionProperty;
/**
* An action to send data from an MQTT message to asset properties in AWS IoT SiteWise.
* @default None
*/
readonly iotSiteWise?: CfnTopicRule.IotSiteWiseActionProperty;
/**
* An action to sends messages directly to your Amazon MSK or self-managed Apache Kafka clusters for data analysis and visualization.
* @default None
*/
readonly kafka?: CfnTopicRule.KafkaActionProperty;
/**
* An action to write data from an MQTT message to Amazon Kinesis Data Streams.
* @default None
*/
readonly kinesis?: CfnTopicRule.KinesisActionProperty;
/**
* An action to invoke an AWS Lambda function, passing in an MQTT message.
* @default None
*/
readonly lambda?: CfnTopicRule.LambdaActionProperty;
/**
* An action to republish an MQTT message to another MQTT topic.
* @default None
*/
readonly republish?: CfnTopicRule.RepublishActionProperty;
/**
* An action to write the data from an MQTT message to an Amazon S3 bucket.
* @default None
*/
readonly s3?: CfnTopicRule.S3ActionProperty;
/**
* An action to send the data from an MQTT message as an Amazon SNS push notification.
* @default None
*/
readonly sns?: CfnTopicRule.SnsActionProperty;
/**
* An action to send data from an MQTT message to an Amazon SQS queue.
* @default None
*/
readonly sqs?: CfnTopicRule.SqsActionProperty;
/**
* An action to start an AWS Step Functions state machine.
* @default None
*/
readonly stepFunctions?: CfnTopicRule.StepFunctionsActionProperty;
/**
* An action to write attributes (measures) from an MQTT message into an Amazon Timestream table.
* @default None
*/
readonly timestream?: CfnTopicRule.TimestreamActionProperty;
}
72 changes: 72 additions & 0 deletions packages/@aws-cdk/aws-iot/lib/actions/cloudwatch-alarm-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
import * as iam from '@aws-cdk/aws-iam';
import { IAction, ActionConfig, ITopicRule } from '..';
import { singletonActionRole } from './util';

/**
* Configuration properties of an action for CloudWatch alarm.
*/
export interface CloudwatchAlarmActionProps {
/**
* Reason for the alarm change.
*
* Supports substitution templates.
* @see https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html
*
* @default 'This state was set by the rule of AWS IoT Core.' will be set
*/
readonly stateReason?: string;
/**
* The IAM role that allows access to the CloudWatch alarm.
*
* @default a new role will be created
*/
readonly role?: iam.IRole;
}

/**
* The action to change the state of an Amazon CloudWatch alarm.
*/
export class CloudwatchAlarmAction implements IAction {
private readonly stateReason?: string;
private readonly role?: iam.IRole;

/**
* `stateValue` supports substitution templates.
* @see https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html
*
* @param alarm The CloudWatch alarm that set state by the rule
* @param stateValue The value of the alarm state.
* Valid values: OK, ALARM, INSUFFICIENT_DATA or substitution templates.
* @param props Optional properties to not use default
*/
constructor(
private readonly alarm: cloudwatch.IAlarm,
private readonly stateValue: cloudwatch.AlarmState | string,
props: CloudwatchAlarmActionProps = {},
) {
this.stateReason = props.stateReason;
this.role = props.role;
}

bind(rule: ITopicRule): ActionConfig {
const role = this.role ?? singletonActionRole(rule);
role.addToPrincipalPolicy(this.putEventStatement(this.alarm));

return {
cloudwatchAlarm: {
alarmName: this.alarm.alarmName,
stateReason: this.stateReason ?? 'This state was set by the rule of AWS IoT Core.',
stateValue: this.stateValue,
roleArn: role.roleArn,
},
};
}

private putEventStatement(alarm: cloudwatch.IAlarm) {
return new iam.PolicyStatement({
actions: ['cloudwatch:SetAlarmState'],
resources: [alarm.alarmArn],
});
}
}
Loading

0 comments on commit e6c26f5

Please sign in to comment.