From d5c9336a152133313d0b9fe29b6b72649451e74c Mon Sep 17 00:00:00 2001 From: Fabrizio Siciliano Date: Fri, 26 Aug 2022 17:13:50 +0200 Subject: [PATCH 1/4] feat(iot): TopicRule action for Step Functions --- packages/@aws-cdk/aws-iot-actions/README.md | 28 ++ .../@aws-cdk/aws-iot-actions/lib/index.ts | 1 + .../lib/step-functions-action.ts | 62 +++++ .../@aws-cdk/aws-iot-actions/package.json | 4 +- .../integ.stepfunctions-action.ts | 25 ++ ...aultTestDeployAssertDDDAF29A.template.json | 1 + .../cdk.out | 1 + .../integ.json | 11 + .../manifest.json | 58 +++++ .../test-stack.assets.json | 19 ++ .../test-stack.template.json | 205 +++++++++++++++ .../tree.json | 241 ++++++++++++++++++ .../stepfunctions-action.test.ts | 95 +++++++ 13 files changed, 750 insertions(+), 1 deletion(-) create mode 100644 packages/@aws-cdk/aws-iot-actions/lib/step-functions-action.ts create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/integ.stepfunctions-action.ts create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/IntegrationTestDefaultTestDeployAssertDDDAF29A.template.json create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/test-stack.assets.json create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/test-stack.template.json create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/tree.json create mode 100644 packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.test.ts diff --git a/packages/@aws-cdk/aws-iot-actions/README.md b/packages/@aws-cdk/aws-iot-actions/README.md index efc5240ffb3af..50d42e014ef1b 100644 --- a/packages/@aws-cdk/aws-iot-actions/README.md +++ b/packages/@aws-cdk/aws-iot-actions/README.md @@ -33,6 +33,7 @@ Currently supported are: - Publish messages on SNS topics - Write messages into columns of DynamoDB - Put messages IoT Events input +- Start the execution of a Step Functions state machine ## Republish a message to another MQTT topic @@ -328,3 +329,30 @@ const topicRule = new iot.TopicRule(this, 'TopicRule', { ], }); ``` + +## Start the execution of a Step Functions state machine + +The code snippet below creates an AWS IoT Rule that starts the execution of a Step Functions state machine: + +```ts +import * as iam from '@aws-cdk/aws-iam'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; + +declare const role: iam.Role; + +const stateMachine = new sfn.StateMachine(this, 'StateMachine', { + definition: new sfn.Pass(stack, 'StartPass'), +}); + +const topicRule = new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323( + "SELECT * FROM 'device/+/data", + ), + actions: [ + new actions.StepFunctionsAction(stateMachine, { + role: role, // optional property, defaults to a new role + executionNamePrefix: 'StateMachinePrefix', // optional property, defaults to nothing + }), + ], +}); +``` diff --git a/packages/@aws-cdk/aws-iot-actions/lib/index.ts b/packages/@aws-cdk/aws-iot-actions/lib/index.ts index 0a9d23398f59b..7552098c350c0 100644 --- a/packages/@aws-cdk/aws-iot-actions/lib/index.ts +++ b/packages/@aws-cdk/aws-iot-actions/lib/index.ts @@ -11,3 +11,4 @@ export * from './lambda-function-action'; export * from './s3-put-object-action'; export * from './sqs-queue-action'; export * from './sns-topic-action'; +export * from './step-functions-action'; diff --git a/packages/@aws-cdk/aws-iot-actions/lib/step-functions-action.ts b/packages/@aws-cdk/aws-iot-actions/lib/step-functions-action.ts new file mode 100644 index 0000000000000..49f660128811d --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/lib/step-functions-action.ts @@ -0,0 +1,62 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as iot from '@aws-cdk/aws-iot'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import { CommonActionProps } from './common-action-props'; +import { singletonActionRole } from './private/role'; + +/** + * Configuration properties of an action for Step Functions + */ +export interface StepFunctionsActionProps extends CommonActionProps { + /** + * Specifies which prefix to append to the state machine execution. + * + * @default - no prefix + */ + readonly executionNamePrefix?: string; +} + +/** + * The action to start the execution of a Step Functions state machine + */ +export class StepFunctionsAction implements iot.IAction { + private readonly role?: iam.IRole; + private readonly stateMachine: sfn.StateMachine; + private readonly executionNamePrefix?: string; + + /** + * @param stateMachine The Step Functions state machine whose execution will be started. + * @param props Optional properties to not use default + */ + constructor( + stateMachine: sfn.StateMachine, + props: StepFunctionsActionProps = {}, + ) { + this.stateMachine = stateMachine; + this.role = props.role; + this.executionNamePrefix = props.executionNamePrefix; + } + + /** + * @internal + */ + _bind(topicRule: iot.ITopicRule): iot.ActionConfig { + const role = this.role ?? singletonActionRole(topicRule); + role.addToPrincipalPolicy( + new iam.PolicyStatement({ + actions: ['states:StartExecution'], + resources: [this.stateMachine.stateMachineArn], + }), + ); + + return { + configuration: { + stepFunctions: { + roleArn: role.roleArn, + stateMachineName: this.stateMachine.stateMachineName, + executionNamePrefix: this.executionNamePrefix, + }, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-iot-actions/package.json b/packages/@aws-cdk/aws-iot-actions/package.json index bf4691581742c..79e107a96142d 100644 --- a/packages/@aws-cdk/aws-iot-actions/package.json +++ b/packages/@aws-cdk/aws-iot-actions/package.json @@ -100,6 +100,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "case": "1.6.3", "constructs": "^10.0.0" @@ -118,6 +119,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^10.0.0" }, @@ -136,4 +138,4 @@ "tag": "next" }, "private": true -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/integ.stepfunctions-action.ts b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/integ.stepfunctions-action.ts new file mode 100644 index 0000000000000..c0e9864fbf715 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/integ.stepfunctions-action.ts @@ -0,0 +1,25 @@ +import * as iot from '@aws-cdk/aws-iot'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as actions 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); + + const topicRule = new iot.TopicRule(this, 'TopicRule', { + sql: iot.IotSql.fromStringAsVer20160323("SELECT * FROM 'device/+/data'"), + }); + + const stateMachine = new sfn.StateMachine(this, 'StateMachine', { + definition: new sfn.Pass(this, 'StartPass'), + }); + + topicRule.addAction(new actions.StepFunctionsAction(stateMachine)); + } +} + +new TestStack(app, 'test-stack'); +app.synth(); diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/IntegrationTestDefaultTestDeployAssertDDDAF29A.template.json b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/IntegrationTestDefaultTestDeployAssertDDDAF29A.template.json new file mode 100644 index 0000000000000..9e26dfeeb6e64 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/IntegrationTestDefaultTestDeployAssertDDDAF29A.template.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..588d7b269d34f --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"20.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/integ.json b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/integ.json new file mode 100644 index 0000000000000..1c271f595efd9 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/integ.json @@ -0,0 +1,11 @@ +{ + "version": "20.0.0", + "testCases": { + "IntegrationTest/DefaultTest": { + "stacks": [ + "test-stack" + ], + "assertionStack": "IntegrationTest/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..dd416c8b8412d --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/manifest.json @@ -0,0 +1,58 @@ +{ + "version": "20.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "test-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-stack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/test-stack/TopicRule/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TopicRule40A4EA44" + } + ], + "/test-stack/TopicRule/TopicRuleActionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TopicRuleTopicRuleActionRole246C4F77" + } + ], + "/test-stack/TopicRule/TopicRuleActionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687" + } + ], + "/test-stack/StateMachine/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "StateMachineRoleB840431D" + } + ], + "/test-stack/StateMachine/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "StateMachine2E01A3A5" + } + ], + "/test-stack/Service-principalMap": [ + { + "type": "aws:cdk:logicalId", + "data": "ServiceprincipalMap" + } + ] + }, + "displayName": "test-stack" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/test-stack.assets.json b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/test-stack.assets.json new file mode 100644 index 0000000000000..86e1b5a3a395b --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/test-stack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "20.0.0", + "files": { + "33ea9644d18ddb62bc89360ac3bad439c89f0f9665650f0548bd2f3106d02783": { + "source": { + "path": "test-stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "33ea9644d18ddb62bc89360ac3bad439c89f0f9665650f0548bd2f3106d02783.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/test-stack.template.json b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/test-stack.template.json new file mode 100644 index 0000000000000..44d3099931640 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/test-stack.template.json @@ -0,0 +1,205 @@ +{ + "Resources": { + "TopicRule40A4EA44": { + "Type": "AWS::IoT::TopicRule", + "Properties": { + "TopicRulePayload": { + "Actions": [ + { + "StepFunctions": { + "RoleArn": { + "Fn::GetAtt": [ + "TopicRuleTopicRuleActionRole246C4F77", + "Arn" + ] + }, + "StateMachineName": { + "Fn::GetAtt": [ + "StateMachine2E01A3A5", + "Name" + ] + } + } + } + ], + "AwsIotSqlVersion": "2016-03-23", + "Sql": "SELECT * FROM 'device/+/data'" + } + } + }, + "TopicRuleTopicRuleActionRole246C4F77": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "iot.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "StateMachine2E01A3A5" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687", + "Roles": [ + { + "Ref": "TopicRuleTopicRuleActionRole246C4F77" + } + ] + } + }, + "StateMachineRoleB840431D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::FindInMap": [ + "ServiceprincipalMap", + { + "Ref": "AWS::Region" + }, + "states" + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, + "DefinitionString": "{\"StartAt\":\"StartPass\",\"States\":{\"StartPass\":{\"Type\":\"Pass\",\"End\":true}}}" + }, + "DependsOn": [ + "StateMachineRoleB840431D" + ] + } + }, + "Mappings": { + "ServiceprincipalMap": { + "af-south-1": { + "states": "states.af-south-1.amazonaws.com" + }, + "ap-east-1": { + "states": "states.ap-east-1.amazonaws.com" + }, + "ap-northeast-1": { + "states": "states.ap-northeast-1.amazonaws.com" + }, + "ap-northeast-2": { + "states": "states.ap-northeast-2.amazonaws.com" + }, + "ap-northeast-3": { + "states": "states.ap-northeast-3.amazonaws.com" + }, + "ap-south-1": { + "states": "states.ap-south-1.amazonaws.com" + }, + "ap-southeast-1": { + "states": "states.ap-southeast-1.amazonaws.com" + }, + "ap-southeast-2": { + "states": "states.ap-southeast-2.amazonaws.com" + }, + "ap-southeast-3": { + "states": "states.ap-southeast-3.amazonaws.com" + }, + "ca-central-1": { + "states": "states.ca-central-1.amazonaws.com" + }, + "cn-north-1": { + "states": "states.cn-north-1.amazonaws.com" + }, + "cn-northwest-1": { + "states": "states.cn-northwest-1.amazonaws.com" + }, + "eu-central-1": { + "states": "states.eu-central-1.amazonaws.com" + }, + "eu-north-1": { + "states": "states.eu-north-1.amazonaws.com" + }, + "eu-south-1": { + "states": "states.eu-south-1.amazonaws.com" + }, + "eu-south-2": { + "states": "states.eu-south-2.amazonaws.com" + }, + "eu-west-1": { + "states": "states.eu-west-1.amazonaws.com" + }, + "eu-west-2": { + "states": "states.eu-west-2.amazonaws.com" + }, + "eu-west-3": { + "states": "states.eu-west-3.amazonaws.com" + }, + "me-south-1": { + "states": "states.me-south-1.amazonaws.com" + }, + "sa-east-1": { + "states": "states.sa-east-1.amazonaws.com" + }, + "us-east-1": { + "states": "states.us-east-1.amazonaws.com" + }, + "us-east-2": { + "states": "states.us-east-2.amazonaws.com" + }, + "us-gov-east-1": { + "states": "states.us-gov-east-1.amazonaws.com" + }, + "us-gov-west-1": { + "states": "states.us-gov-west-1.amazonaws.com" + }, + "us-iso-east-1": { + "states": "states.amazonaws.com" + }, + "us-iso-west-1": { + "states": "states.amazonaws.com" + }, + "us-isob-east-1": { + "states": "states.amazonaws.com" + }, + "us-west-1": { + "states": "states.us-west-1.amazonaws.com" + }, + "us-west-2": { + "states": "states.us-west-2.amazonaws.com" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/tree.json b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/tree.json new file mode 100644 index 0000000000000..f6d31f473ef9b --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.integ.snapshot/tree.json @@ -0,0 +1,241 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.85" + } + }, + "test-stack": { + "id": "test-stack", + "path": "test-stack", + "children": { + "TopicRule": { + "id": "TopicRule", + "path": "test-stack/TopicRule", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/TopicRule/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IoT::TopicRule", + "aws:cdk:cloudformation:props": { + "topicRulePayload": { + "actions": [ + { + "stepFunctions": { + "roleArn": { + "Fn::GetAtt": [ + "TopicRuleTopicRuleActionRole246C4F77", + "Arn" + ] + }, + "stateMachineName": { + "Fn::GetAtt": [ + "StateMachine2E01A3A5", + "Name" + ] + } + } + } + ], + "awsIotSqlVersion": "2016-03-23", + "sql": "SELECT * FROM 'device/+/data'" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iot.CfnTopicRule", + "version": "0.0.0" + } + }, + "TopicRuleActionRole": { + "id": "TopicRuleActionRole", + "path": "test-stack/TopicRule/TopicRuleActionRole", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/TopicRule/TopicRuleActionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "iot.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "test-stack/TopicRule/TopicRuleActionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/TopicRule/TopicRuleActionRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "states:StartExecution", + "Effect": "Allow", + "Resource": { + "Ref": "StateMachine2E01A3A5" + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687", + "roles": [ + { + "Ref": "TopicRuleTopicRuleActionRole246C4F77" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iot.TopicRule", + "version": "0.0.0" + } + }, + "StartPass": { + "id": "StartPass", + "path": "test-stack/StartPass", + "constructInfo": { + "fqn": "@aws-cdk/aws-stepfunctions.Pass", + "version": "0.0.0" + } + }, + "StateMachine": { + "id": "StateMachine", + "path": "test-stack/StateMachine", + "children": { + "Role": { + "id": "Role", + "path": "test-stack/StateMachine/Role", + "children": { + "Resource": { + "id": "Resource", + "path": "test-stack/StateMachine/Role/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::FindInMap": [ + "ServiceprincipalMap", + { + "Ref": "AWS::Region" + }, + "states" + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-stack/StateMachine/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::StepFunctions::StateMachine", + "aws:cdk:cloudformation:props": { + "roleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + }, + "definitionString": "{\"StartAt\":\"StartPass\",\"States\":{\"StartPass\":{\"Type\":\"Pass\",\"End\":true}}}" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-stepfunctions.CfnStateMachine", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-stepfunctions.StateMachine", + "version": "0.0.0" + } + }, + "Service-principalMap": { + "id": "Service-principalMap", + "path": "test-stack/Service-principalMap", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnMapping", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.test.ts b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.test.ts new file mode 100644 index 0000000000000..e3b17e4e0c376 --- /dev/null +++ b/packages/@aws-cdk/aws-iot-actions/test/stepfunctions/stepfunctions-action.test.ts @@ -0,0 +1,95 @@ +import { Match, Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; +import * as iot from '@aws-cdk/aws-iot'; +import * as sfn from '@aws-cdk/aws-stepfunctions'; +import * as cdk from '@aws-cdk/core'; +import * as actions from '../../lib'; + +const TOPIC_RULE_ROLE_ID = 'MyTopicRuleTopicRuleActionRoleCE2D05DA'; + +let stack: cdk.Stack; +let topicRule: iot.TopicRule; +let stateMachine: sfn.StateMachine; +beforeEach(() => { + stack = new cdk.Stack(); + topicRule = new iot.TopicRule(stack, 'MyTopicRule', { + sql: iot.IotSql.fromStringAsVer20160323( + "SELECT * as device_id FROM 'device/+/data'", + ), + }); + stateMachine = new sfn.StateMachine(stack, 'TestStateMachine', { + definition: new sfn.Pass(stack, 'TestPass'), + }); +}); + +test('Default Step Functions action', () => { + topicRule.addAction(new actions.StepFunctionsAction(stateMachine)); + + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + { + StepFunctions: { + RoleArn: { + 'Fn::GetAtt': [TOPIC_RULE_ROLE_ID, 'Arn'], + }, + StateMachineName: { + 'Fn::GetAtt': [ + Match.stringLikeRegexp('TestStateMachine'), + 'Name', + ], + }, + }, + }, + ], + }, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'states:StartExecution', + Effect: 'Allow', + // Resource: Match.objectLike({ Ref: stateMachine.stateMachineName }), + }, + ], + }, + Roles: [{ Ref: TOPIC_RULE_ROLE_ID }], + }); +}); + +test('Can set role', () => { + const ROLE_ARN = 'arn:aws:iam::123456789012:role/testrole'; + const role = iam.Role.fromRoleArn(stack, 'TestRole', ROLE_ARN); + + topicRule.addAction( + new actions.StepFunctionsAction(stateMachine, { + role, + }), + ); + + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [Match.objectLike({ StepFunctions: { RoleArn: ROLE_ARN } })], + }, + }); +}); + +test('Can set execution name prefix', () => { + const PREFIX = 'test'; + + topicRule.addAction( + new actions.StepFunctionsAction(stateMachine, { + executionNamePrefix: PREFIX, + }), + ); + + Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { + TopicRulePayload: { + Actions: [ + Match.objectLike({ StepFunctions: { ExecutionNamePrefix: PREFIX } }), + ], + }, + }); +}); From 7a113bb25d1b09de04f32328422b59f93fb758c1 Mon Sep 17 00:00:00 2001 From: Fabrizio Siciliano Date: Fri, 26 Aug 2022 18:23:07 +0200 Subject: [PATCH 2/4] Fix build breaking stack declaration --- packages/@aws-cdk/aws-iot-actions/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@aws-cdk/aws-iot-actions/README.md b/packages/@aws-cdk/aws-iot-actions/README.md index 50d42e014ef1b..adebf61d28fa1 100644 --- a/packages/@aws-cdk/aws-iot-actions/README.md +++ b/packages/@aws-cdk/aws-iot-actions/README.md @@ -339,6 +339,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; declare const role: iam.Role; +declare const stack: cdk.Stack; const stateMachine = new sfn.StateMachine(this, 'StateMachine', { definition: new sfn.Pass(stack, 'StartPass'), From bc831e96bdfc33ed72c51080bb4262e5c11e07e1 Mon Sep 17 00:00:00 2001 From: Fabrizio Siciliano Date: Fri, 26 Aug 2022 18:23:07 +0200 Subject: [PATCH 3/4] Fix build breaking stack declaration --- packages/@aws-cdk/aws-iot-actions/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iot-actions/README.md b/packages/@aws-cdk/aws-iot-actions/README.md index 50d42e014ef1b..09d4b9d39e53c 100644 --- a/packages/@aws-cdk/aws-iot-actions/README.md +++ b/packages/@aws-cdk/aws-iot-actions/README.md @@ -341,7 +341,7 @@ import * as sfn from '@aws-cdk/aws-stepfunctions'; declare const role: iam.Role; const stateMachine = new sfn.StateMachine(this, 'StateMachine', { - definition: new sfn.Pass(stack, 'StartPass'), + definition: new sfn.Pass(this, 'StartPass'), }); const topicRule = new iot.TopicRule(this, 'TopicRule', { From 52e6dbc96852295ed4dee857d7b37d0805ae679e Mon Sep 17 00:00:00 2001 From: Fabrizio Siciliano Date: Mon, 29 Aug 2022 10:01:06 +0200 Subject: [PATCH 4/4] fix build breaking --- packages/@aws-cdk/aws-iot-actions/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iot-actions/README.md b/packages/@aws-cdk/aws-iot-actions/README.md index 60bc8195f612a..09d4b9d39e53c 100644 --- a/packages/@aws-cdk/aws-iot-actions/README.md +++ b/packages/@aws-cdk/aws-iot-actions/README.md @@ -339,7 +339,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; declare const role: iam.Role; -declare const stack: cdk.Stack; const stateMachine = new sfn.StateMachine(this, 'StateMachine', { definition: new sfn.Pass(this, 'StartPass'),