From 3e069e948df88e50fd38e633f67dac6f557b112a Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Sun, 5 Dec 2021 10:57:47 +0900 Subject: [PATCH 1/6] feat(iotevents): add IoT Events input L2 Construct --- packages/@aws-cdk/aws-iotevents/README.md | 39 ++++++++++++--- packages/@aws-cdk/aws-iotevents/lib/index.ts | 2 + packages/@aws-cdk/aws-iotevents/lib/input.ts | 50 +++++++++++++++++++ packages/@aws-cdk/aws-iotevents/package.json | 6 ++- .../@aws-cdk/aws-iotevents/test/input.test.ts | 34 +++++++++++++ .../test/integ.detector-model.expected.json | 17 +++++++ .../test/integ.detector-model.ts | 18 +++++++ .../aws-iotevents/test/iotevents.test.ts | 6 --- 8 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 packages/@aws-cdk/aws-iotevents/lib/input.ts create mode 100644 packages/@aws-cdk/aws-iotevents/test/input.test.ts create mode 100644 packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json create mode 100644 packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts delete mode 100644 packages/@aws-cdk/aws-iotevents/test/iotevents.test.ts diff --git a/packages/@aws-cdk/aws-iotevents/README.md b/packages/@aws-cdk/aws-iotevents/README.md index e9a17af332776..6dc6a681636cc 100644 --- a/packages/@aws-cdk/aws-iotevents/README.md +++ b/packages/@aws-cdk/aws-iotevents/README.md @@ -1,4 +1,5 @@ # AWS::IoTEvents Construct Library + --- @@ -9,23 +10,45 @@ > > [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. + --- -This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. +AWS IoT Events enables you to monitor your equipment or device fleets for +failures or changes in operation, and to trigger actions when such events +occur. + +## Installation + +Install the module: + +```console +$ npm i @aws-cdk/aws-iotevents +``` + +Import it into your code: ```ts nofixture import * as iotevents from '@aws-cdk/aws-iotevents'; ``` - - -There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. -However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. +## `Input` -For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::IoTEvents](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_IoTEvents.html). +Add an AWS IoT Events input to your stack: -(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md) if you are interested in contributing to this construct library.) +```ts +import * as iotevents from '@aws-cdk/aws-iotevents'; - +new iotevents.Input(this, 'MyInput', { + inputName: 'my_input', + attributeJsonPaths: ['payload.temperature'], +}); +``` diff --git a/packages/@aws-cdk/aws-iotevents/lib/index.ts b/packages/@aws-cdk/aws-iotevents/lib/index.ts index 6390f9ed0b0ee..3851e30984391 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/index.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/index.ts @@ -1,2 +1,4 @@ +export * from './input'; + // AWS::IoTEvents CloudFormation Resources: export * from './iotevents.generated'; diff --git a/packages/@aws-cdk/aws-iotevents/lib/input.ts b/packages/@aws-cdk/aws-iotevents/lib/input.ts new file mode 100644 index 0000000000000..9ee35152279c4 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/lib/input.ts @@ -0,0 +1,50 @@ +import { Resource } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnInput } from './iotevents.generated'; + +/** + * Properties for defining an AWS IoT Events input + */ +export interface InputProps { + /** + * The name of the input + * + * @default xxx + */ + readonly inputName?: string, + + /** + * An expression that specifies an attribute-value pair in a JSON structure. + * Use this to specify an attribute from the JSON payload that is made available + * by the input. Inputs are derived from messages sent to AWS IoT Events (BatchPutMessage). + * Each such message contains a JSON payload. The attribute (and its paired value) + * specified here are available for use in the condition expressions used by detectors. + */ + readonly attributeJsonPaths: string[]; +} + +/** + * Defines an AWS IoT Events input in this stack. + */ +export class Input extends Resource { + /** + * The name of the input + * @attribute + */ + public readonly inputName: string; + + constructor(scope: Construct, id: string, props: InputProps) { + super(scope, id, { + physicalName: props.inputName, + }); + + const resource = new CfnInput(this, 'Resource', { + inputName: this.physicalName, + inputDefinition: { + attributes: props.attributeJsonPaths.map(path => ({ jsonPath: path })), + }, + }); + + this.inputName = this.getResourceNameAttribute(resource.ref); + } +} diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 7c69ce3fe3da5..50ed464cf76d7 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -76,9 +76,11 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.0.3" + "@types/jest": "^27.0.3", + "jest": "^27.3.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", @@ -92,7 +94,7 @@ "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "cfn-only", + "maturity": "experimental", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-iotevents/test/input.test.ts b/packages/@aws-cdk/aws-iotevents/test/input.test.ts new file mode 100644 index 0000000000000..b599f125a766a --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/test/input.test.ts @@ -0,0 +1,34 @@ +import { Template } from '@aws-cdk/assertions'; +import * as cdk from '@aws-cdk/core'; +import * as iotevents from '../lib'; + +test('Default property', () => { + const stack = new cdk.Stack(); + + // WHEN + new iotevents.Input(stack, 'MyInput', { + attributeJsonPaths: ['payload.temperature'], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::Input', { + InputDefinition: { + Attributes: [{ JsonPath: 'payload.temperature' }], + }, + }); +}); + +test('can set physical name', () => { + const stack = new cdk.Stack(); + + // WHEN + new iotevents.Input(stack, 'MyInput', { + inputName: 'test_input', + attributeJsonPaths: ['payload.temperature'], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IoTEvents::Input', { + InputName: 'test_input', + }); +}); diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json new file mode 100644 index 0000000000000..1f5d452b5475d --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.expected.json @@ -0,0 +1,17 @@ +{ + "Resources": { + "MyInput08947B23": { + "Type": "AWS::IoTEvents::Input", + "Properties": { + "InputDefinition": { + "Attributes": [ + { + "JsonPath": "payload.temperature" + } + ] + }, + "InputName": "test_input" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts new file mode 100644 index 0000000000000..cb900c83a3f44 --- /dev/null +++ b/packages/@aws-cdk/aws-iotevents/test/integ.detector-model.ts @@ -0,0 +1,18 @@ +import * as cdk from '@aws-cdk/core'; +import * as iotevents from '../lib'; + +const app = new cdk.App(); + +class TestStack extends cdk.Stack { + constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + new iotevents.Input(this, 'MyInput', { + inputName: 'test_input', + attributeJsonPaths: ['payload.temperature'], + }); + } +} + +new TestStack(app, 'test-stack'); +app.synth(); diff --git a/packages/@aws-cdk/aws-iotevents/test/iotevents.test.ts b/packages/@aws-cdk/aws-iotevents/test/iotevents.test.ts deleted file mode 100644 index 465c7bdea0693..0000000000000 --- a/packages/@aws-cdk/aws-iotevents/test/iotevents.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@aws-cdk/assertions'; -import {} from '../lib'; - -test('No tests are specified for this package', () => { - expect(true).toBe(true); -}); From 4cda3472547944bffddb42303f5908bd13a5f30c Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Mon, 6 Dec 2021 19:55:03 +0900 Subject: [PATCH 2/6] add test for getting inputName --- .../@aws-cdk/aws-iotevents/test/input.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/@aws-cdk/aws-iotevents/test/input.test.ts b/packages/@aws-cdk/aws-iotevents/test/input.test.ts index b599f125a766a..6673584d8555c 100644 --- a/packages/@aws-cdk/aws-iotevents/test/input.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/input.test.ts @@ -18,6 +18,27 @@ test('Default property', () => { }); }); +test('can get input name', () => { + const stack = new cdk.Stack(); + // GIVEN + const input = new iotevents.Input(stack, 'MyInput', { + attributeJsonPaths: ['payload.temperature'], + }); + + // WHEN + new cdk.CfnResource(stack, 'Res', { + type: 'Test::Resource', + properties: { + InputName: input.inputName, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('Test::Resource', { + InputName: { Ref: 'MyInput08947B23' }, + }); +}); + test('can set physical name', () => { const stack = new cdk.Stack(); From 0f155029d9aa7ef9b373eef5c5156dcd92ff7f1c Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Wed, 8 Dec 2021 19:15:17 +0900 Subject: [PATCH 3/6] add IInput --- packages/@aws-cdk/aws-iotevents/lib/input.ts | 25 ++++++++++++++++--- .../@aws-cdk/aws-iotevents/test/input.test.ts | 13 ++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/input.ts b/packages/@aws-cdk/aws-iotevents/lib/input.ts index 9ee35152279c4..7041d76311b51 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/input.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/input.ts @@ -1,7 +1,18 @@ -import { Resource } from '@aws-cdk/core'; +import { Resource, IResource } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnInput } from './iotevents.generated'; +/** + * Represents an AWS IoT Events input + */ +export interface IInput extends IResource { + /** + * The name of the input + * @attribute + */ + readonly inputName: string; +} + /** * Properties for defining an AWS IoT Events input */ @@ -26,11 +37,17 @@ export interface InputProps { /** * Defines an AWS IoT Events input in this stack. */ -export class Input extends Resource { +export class Input extends Resource implements IInput { /** - * The name of the input - * @attribute + * Import an existing input */ + public static fromInputName(scope: Construct, id: string, inputName: string): IInput { + class Import extends Resource implements IInput { + public readonly inputName = inputName; + } + return new Import(scope, id); + } + public readonly inputName: string; constructor(scope: Construct, id: string, props: InputProps) { diff --git a/packages/@aws-cdk/aws-iotevents/test/input.test.ts b/packages/@aws-cdk/aws-iotevents/test/input.test.ts index 6673584d8555c..957c41f86d953 100644 --- a/packages/@aws-cdk/aws-iotevents/test/input.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/input.test.ts @@ -53,3 +53,16 @@ test('can set physical name', () => { InputName: 'test_input', }); }); + +test('can import a Input by inputName', () => { + const stack = new cdk.Stack(); + + // WHEN + const inputName = 'test-input-name'; + const topicRule = iotevents.Input.fromInputName(stack, 'InputFromInputName', inputName); + + // THEN + expect(topicRule).toMatchObject({ + inputName, + }); +}); From a9ddebbd0278ccdadfc00ea3e4e7c46be2135618 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Wed, 8 Dec 2021 19:17:27 +0900 Subject: [PATCH 4/6] add at-default comment --- packages/@aws-cdk/aws-iotevents/lib/input.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/input.ts b/packages/@aws-cdk/aws-iotevents/lib/input.ts index 7041d76311b51..f4d15781fabe9 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/input.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/input.ts @@ -20,7 +20,7 @@ export interface InputProps { /** * The name of the input * - * @default xxx + * @default None */ readonly inputName?: string, From d1adc501f4796fa469c660d5755695c6f22fd838 Mon Sep 17 00:00:00 2001 From: yamatatsu Date: Wed, 8 Dec 2021 19:29:05 +0900 Subject: [PATCH 5/6] add a validation for empty json path --- packages/@aws-cdk/aws-iotevents/lib/input.ts | 4 ++++ packages/@aws-cdk/aws-iotevents/test/input.test.ts | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/@aws-cdk/aws-iotevents/lib/input.ts b/packages/@aws-cdk/aws-iotevents/lib/input.ts index f4d15781fabe9..abf163adc5380 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/input.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/input.ts @@ -55,6 +55,10 @@ export class Input extends Resource implements IInput { physicalName: props.inputName, }); + if (props.attributeJsonPaths.length === 0) { + throw new Error('attributeJsonPaths property cannot be empty'); + } + const resource = new CfnInput(this, 'Resource', { inputName: this.physicalName, inputDefinition: { diff --git a/packages/@aws-cdk/aws-iotevents/test/input.test.ts b/packages/@aws-cdk/aws-iotevents/test/input.test.ts index 957c41f86d953..11b457bb0cf1b 100644 --- a/packages/@aws-cdk/aws-iotevents/test/input.test.ts +++ b/packages/@aws-cdk/aws-iotevents/test/input.test.ts @@ -66,3 +66,13 @@ test('can import a Input by inputName', () => { inputName, }); }); + +test('cannot be created with an empty array of attributeJsonPaths', () => { + const stack = new cdk.Stack(); + + expect(() => { + new iotevents.Input(stack, 'MyInput', { + attributeJsonPaths: [], + }); + }).toThrow('attributeJsonPaths property cannot be empty'); +}); From ed8089686f501f1e7e8eeb5acfd03362096634e0 Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Fri, 10 Dec 2021 14:06:31 -0800 Subject: [PATCH 6/6] Update docs of the inputName property --- packages/@aws-cdk/aws-iotevents/lib/input.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iotevents/lib/input.ts b/packages/@aws-cdk/aws-iotevents/lib/input.ts index abf163adc5380..e4bba5684b7a4 100644 --- a/packages/@aws-cdk/aws-iotevents/lib/input.ts +++ b/packages/@aws-cdk/aws-iotevents/lib/input.ts @@ -20,7 +20,7 @@ export interface InputProps { /** * The name of the input * - * @default None + * @default - CloudFormation will generate a unique name of the input */ readonly inputName?: string,