forked from aws/aws-cdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(iot): add Action to set a CloudWatch alarm (aws#18021)
Adding IoT Rule action for CloudWatch alarm. Fixes aws#17705 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
- Loading branch information
1 parent
6bb75c3
commit aab7c27
Showing
6 changed files
with
356 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
packages/@aws-cdk/aws-iot-actions/lib/cloudwatch-set-alarm-state-action.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; | ||
import * as iam from '@aws-cdk/aws-iam'; | ||
import * as iot from '@aws-cdk/aws-iot'; | ||
import { CommonActionProps } from './common-action-props'; | ||
import { singletonActionRole } from './private/role'; | ||
|
||
/** | ||
* Configuration properties of an action for CloudWatch alarm. | ||
*/ | ||
export interface CloudWatchSetAlarmStateActionProps extends CommonActionProps { | ||
/** | ||
* The reason for the alarm change. | ||
* | ||
* @default None | ||
*/ | ||
readonly reason?: string; | ||
|
||
/** | ||
* The value of the alarm state to set. | ||
*/ | ||
readonly alarmStateToSet: cloudwatch.AlarmState; | ||
} | ||
|
||
/** | ||
* The action to change the state of an Amazon CloudWatch alarm. | ||
*/ | ||
export class CloudWatchSetAlarmStateAction implements iot.IAction { | ||
constructor( | ||
private readonly alarm: cloudwatch.IAlarm, | ||
private readonly props: CloudWatchSetAlarmStateActionProps, | ||
) { | ||
} | ||
|
||
bind(topicRule: iot.ITopicRule): iot.ActionConfig { | ||
const role = this.props.role ?? singletonActionRole(topicRule); | ||
role.addToPrincipalPolicy(new iam.PolicyStatement({ | ||
actions: ['cloudwatch:SetAlarmState'], | ||
resources: [this.alarm.alarmArn], | ||
})); | ||
|
||
return { | ||
configuration: { | ||
cloudwatchAlarm: { | ||
alarmName: this.alarm.alarmName, | ||
roleArn: role.roleArn, | ||
stateReason: this.props.reason ?? `Set state of '${this.alarm.alarmName}' to '${this.props.alarmStateToSet}'`, | ||
stateValue: this.props.alarmStateToSet, | ||
}, | ||
}, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
packages/@aws-cdk/aws-iot-actions/test/cloudwatch/cloudwatch-set-alarm-state-action.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { Template, Match } from '@aws-cdk/assertions'; | ||
import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; | ||
import * as iam from '@aws-cdk/aws-iam'; | ||
import * as iot from '@aws-cdk/aws-iot'; | ||
import * as cdk from '@aws-cdk/core'; | ||
import * as actions from '../../lib'; | ||
|
||
test('Default cloudwatch alarm action', () => { | ||
// Given | ||
const stack = new cdk.Stack(); | ||
const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { | ||
sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, stateReason, stateValue FROM 'device/+/data'"), | ||
}); | ||
const alarm = cloudwatch.Alarm.fromAlarmArn(stack, 'MyAlarm', 'arn:aws:cloudwatch:us-east-1:123456789012:alarm:MyAlarm'); | ||
|
||
// When | ||
topicRule.addAction(new actions.CloudWatchSetAlarmStateAction(alarm, { | ||
reason: 'Test reason', | ||
alarmStateToSet: cloudwatch.AlarmState.ALARM, | ||
})); | ||
|
||
// Then | ||
Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { | ||
TopicRulePayload: { | ||
Actions: [ | ||
{ | ||
CloudwatchAlarm: { | ||
AlarmName: 'MyAlarm', | ||
RoleArn: { | ||
'Fn::GetAtt': ['MyTopicRuleTopicRuleActionRoleCE2D05DA', 'Arn'], | ||
}, | ||
StateReason: 'Test reason', | ||
StateValue: cloudwatch.AlarmState.ALARM, | ||
}, | ||
}, | ||
], | ||
}, | ||
}); | ||
|
||
Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { | ||
AssumeRolePolicyDocument: { | ||
Statement: [ | ||
{ | ||
Action: 'sts:AssumeRole', | ||
Effect: 'Allow', | ||
Principal: { | ||
Service: 'iot.amazonaws.com', | ||
}, | ||
}, | ||
], | ||
Version: '2012-10-17', | ||
}, | ||
}); | ||
|
||
Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { | ||
PolicyDocument: { | ||
Statement: [ | ||
{ | ||
Action: 'cloudwatch:SetAlarmState', | ||
Effect: 'Allow', | ||
Resource: alarm.alarmArn, | ||
}, | ||
], | ||
Version: '2012-10-17', | ||
}, | ||
PolicyName: 'MyTopicRuleTopicRuleActionRoleDefaultPolicy54A701F7', | ||
Roles: [{ Ref: 'MyTopicRuleTopicRuleActionRoleCE2D05DA' }], | ||
}); | ||
}); | ||
|
||
test('can set role', () => { | ||
// Given | ||
const stack = new cdk.Stack(); | ||
const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { | ||
sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, stateReason, stateValue FROM 'device/+/data'"), | ||
}); | ||
|
||
// When | ||
topicRule.addAction(new actions.CloudWatchSetAlarmStateAction( | ||
cloudwatch.Alarm.fromAlarmArn(stack, 'MyAlarm', 'arn:aws:cloudwatch:us-east-1:123456789012:alarm:MyAlarm'), | ||
{ | ||
reason: '${stateReason}', | ||
alarmStateToSet: cloudwatch.AlarmState.ALARM, | ||
role: iam.Role.fromRoleArn(stack, 'MyRole', 'arn:aws:iam::123456789012:role/ForTest'), | ||
}, | ||
)); | ||
|
||
// Then | ||
Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { | ||
TopicRulePayload: { | ||
Actions: [ | ||
Match.objectLike({ CloudwatchAlarm: { RoleArn: 'arn:aws:iam::123456789012:role/ForTest' } }), | ||
], | ||
}, | ||
}); | ||
|
||
Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { | ||
PolicyName: 'MyRolePolicy64AB00A5', | ||
Roles: ['ForTest'], | ||
}); | ||
}); | ||
|
||
test('set default reason', () => { | ||
// Given | ||
const stack = new cdk.Stack(); | ||
const topicRule = new iot.TopicRule(stack, 'MyTopicRule', { | ||
sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id, stateReason, stateValue FROM 'device/+/data'"), | ||
}); | ||
const alarm = cloudwatch.Alarm.fromAlarmArn(stack, 'MyAlarm', 'arn:aws:cloudwatch:us-east-1:123456789012:alarm:MyAlarm'); | ||
|
||
// When | ||
topicRule.addAction(new actions.CloudWatchSetAlarmStateAction(alarm, { | ||
alarmStateToSet: cloudwatch.AlarmState.ALARM, | ||
})); | ||
|
||
// Then | ||
Template.fromStack(stack).hasResourceProperties('AWS::IoT::TopicRule', { | ||
TopicRulePayload: { | ||
Actions: [ | ||
{ | ||
CloudwatchAlarm: { | ||
AlarmName: 'MyAlarm', | ||
RoleArn: { | ||
'Fn::GetAtt': ['MyTopicRuleTopicRuleActionRoleCE2D05DA', 'Arn'], | ||
}, | ||
StateReason: "Set state of 'MyAlarm' to 'ALARM'", | ||
StateValue: cloudwatch.AlarmState.ALARM, | ||
}, | ||
}, | ||
], | ||
}, | ||
}); | ||
}); |
103 changes: 103 additions & 0 deletions
103
...cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-set-alarm-state-action.expected.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
{ | ||
"Resources": { | ||
"MyAlarm696658B6": { | ||
"Type": "AWS::CloudWatch::Alarm", | ||
"Properties": { | ||
"ComparisonOperator": "GreaterThanOrEqualToThreshold", | ||
"EvaluationPeriods": 3, | ||
"DatapointsToAlarm": 2, | ||
"Dimensions": [ | ||
{ | ||
"Name": "MyDimension", | ||
"Value": "MyDimensionValue" | ||
} | ||
], | ||
"MetricName": "MyMetric", | ||
"Namespace": "MyNamespace", | ||
"Period": 300, | ||
"Statistic": "Average", | ||
"Threshold": 100 | ||
} | ||
}, | ||
"TopicRule40A4EA44": { | ||
"Type": "AWS::IoT::TopicRule", | ||
"Properties": { | ||
"TopicRulePayload": { | ||
"Actions": [ | ||
{ | ||
"CloudwatchAlarm": { | ||
"AlarmName": { | ||
"Ref": "MyAlarm696658B6" | ||
}, | ||
"RoleArn": { | ||
"Fn::GetAtt": [ | ||
"TopicRuleTopicRuleActionRole246C4F77", | ||
"Arn" | ||
] | ||
}, | ||
"StateReason": { | ||
"Fn::Join": [ | ||
"", | ||
[ | ||
"Set state of '", | ||
{ | ||
"Ref": "MyAlarm696658B6" | ||
}, | ||
"' to 'ALARM'" | ||
] | ||
] | ||
}, | ||
"StateValue": "ALARM" | ||
} | ||
} | ||
], | ||
"AwsIotSqlVersion": "2016-03-23", | ||
"Sql": "SELECT topic(2) as device_id 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": "cloudwatch:SetAlarmState", | ||
"Effect": "Allow", | ||
"Resource": { | ||
"Fn::GetAtt": [ | ||
"MyAlarm696658B6", | ||
"Arn" | ||
] | ||
} | ||
} | ||
], | ||
"Version": "2012-10-17" | ||
}, | ||
"PolicyName": "TopicRuleTopicRuleActionRoleDefaultPolicy99ADD687", | ||
"Roles": [ | ||
{ | ||
"Ref": "TopicRuleTopicRuleActionRole246C4F77" | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
packages/@aws-cdk/aws-iot-actions/test/cloudwatch/integ.cloudwatch-set-alarm-state-action.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; | ||
import * as iot from '@aws-cdk/aws-iot'; | ||
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 metric = new cloudwatch.Metric({ | ||
namespace: 'MyNamespace', | ||
metricName: 'MyMetric', | ||
dimensions: { MyDimension: 'MyDimensionValue' }, | ||
}); | ||
const alarm = new cloudwatch.Alarm(this, 'MyAlarm', { | ||
metric: metric, | ||
threshold: 100, | ||
evaluationPeriods: 3, | ||
datapointsToAlarm: 2, | ||
}); | ||
const topicRule = new iot.TopicRule(this, 'TopicRule', { | ||
sql: iot.IotSql.fromStringAsVer20160323("SELECT topic(2) as device_id FROM 'device/+/data'"), | ||
}); | ||
|
||
topicRule.addAction(new actions.CloudWatchSetAlarmStateAction(alarm, { | ||
alarmStateToSet: cloudwatch.AlarmState.ALARM, | ||
})); | ||
} | ||
} | ||
|
||
new TestStack(app, 'test-stack'); | ||
app.synth(); |