diff --git a/packages/@aws-cdk/aws-events-targets/README.md b/packages/@aws-cdk/aws-events-targets/README.md index 7dc1c9116b720..4f38f5c68752c 100644 --- a/packages/@aws-cdk/aws-events-targets/README.md +++ b/packages/@aws-cdk/aws-events-targets/README.md @@ -30,6 +30,8 @@ Currently supported are: * Put a record to a Kinesis Data Firehose stream * [Put an event on an EventBridge bus](#put-an-event-on-an-eventbridge-bus) * [Send an event to EventBridge API Destination](#invoke-an-api-destination) +* [Start a Systems Manager Run Command](#start-a-systems-manager-run-command) +* [Start a Systems Manager Automation](#start-a-systems-manager-automation) See the README of the `@aws-cdk/aws-events` library for more information on EventBridge. @@ -345,3 +347,61 @@ rule.addTarget(new targets.EventBus( ), )); ``` + +## Start a Systems Manager Run Command + +Use the `SsmRunCommand` target to trigger a Systems Manager Run Command. + +The code snippet below creates the scheduled event rule that triggers a Systems Manager Run Command every day. + +```ts +const rule = new events.Rule(this, 'Rule', { + schedule: events.Schedule.expression('rate(1 day)'), +}); + +rule.addTarget(new targets.SsmRunCommand(new ssm.CfnDocument(stack, 'MyDocument', { + content: {...}, + documentType: 'Command', + name: 'my-document', +}), { + targetKey: 'InstanceIds', + targetValues: ['i-asdfiuh2304f'], +})); +``` + +## Start a Systems Manager Automation + +Use the `SsmRunCommand` target to trigger a Systems Manager Automation. + +The code snippet below creates the scheduled event rule that triggers a Systems Manager Automation every day. It also +creates a new role to be used by the Automation. This role should have the required permissions to execute the Automation. + +```ts +const rule = new events.Rule(this, 'Rule', { + schedule: events.Schedule.expression('rate(1 day)'), +}); +const ssmAssumeRole = new iam.Role(this, 'SSMAssumeRole', { + assumedBy: new iam.ServicePrincipal('ssm.amazonaws.com'), +}); + +rule.addTarget(new targets.SsmAutomation(new ssm.CfnDocument(stack, 'MyDocument', { + content: {...}, + documentType: 'Automation', + name: 'my-document', +}), { + ssmAssumeRole, +})); +``` + +You can also target a shared document by passing the document ARN to the `SsmAutomation` target. + +```ts +const automationArn = 'arn:aws:ssm:us-east-1::automation-definition/AWS-StopRdsInstance:$DEFAULT'; + +rule.addTarget(automationArn, { + input: { + InstanceIds: ['my-rds-instance'], + }, + ssmAssumeRole, +}); +``` diff --git a/packages/@aws-cdk/aws-events-targets/lib/index.ts b/packages/@aws-cdk/aws-events-targets/lib/index.ts index 6c91810ebca33..9d6c97f2710af 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/index.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/index.ts @@ -14,4 +14,6 @@ export * from './log-group'; export * from './kinesis-firehose-stream'; export * from './api-gateway'; export * from './api-destination'; +export * from './ssm-automation'; +export * from './ssm-runcommand'; export * from './util'; diff --git a/packages/@aws-cdk/aws-events-targets/lib/ssm-automation.ts b/packages/@aws-cdk/aws-events-targets/lib/ssm-automation.ts new file mode 100644 index 0000000000000..ff5ffe212f7d9 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/lib/ssm-automation.ts @@ -0,0 +1,98 @@ +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import * as ssm from '@aws-cdk/aws-ssm'; +import * as cdk from '@aws-cdk/core'; +import { addToDeadLetterQueueResourcePolicy, bindBaseTargetConfig, singletonEventRole, TargetBaseProps } from './util'; + +/** + * Create an SSM Automation Event Target + */ +export interface SsmAutomationProps extends TargetBaseProps { + /** + * Role to be used for invoking the Automation from the Rule. This should be a + * role that allows the the events.amazonaws.com service principal to assume + * and execute the Automation. This role is not used by the Automation itself, + * to execute the actions in the document, see `automationAssumeRole` for that. + * + * @default - a new role is created. + */ + readonly role?: iam.IRole; + + /** + * The input parameters for the Automation document. + * + * @default - no input parameters passed to the document + */ + readonly input?: { [key: string]: string[] }; + + /** + * Role to be used to run the Automation on your behalf. This should be a role + * that allows the Automation service principal (ssm.amazonaws.com) to assume + * and run the actions in your Automation document. + * + * @default - no role assumed + */ + readonly automationAssumeRole?: iam.IRole; +} + +/** + * Create an SSM Automation Event Target + */ +export class SsmAutomation implements events.IRuleTarget { + private documentArn: string; + + constructor( + /** + * Can be an instance of `ssm.CfnDocument` or a share/managed document ARN. + */ + public readonly document: ssm.CfnDocument | string, + private readonly props: SsmAutomationProps, + ) { + this.documentArn = this.getDocumentArn(); + } + + /** + * Returns a RuleTarget that can be used to trigger this SSM Automation as a + * result from an EventBridge event. + * + * @see https://docs.aws.amazon.com/eventbridge/latest/userguide/resource-based-policies-eventbridge.html + */ + public bind(rule: events.IRule, _id?: string): events.RuleTargetConfig { + const role = this.props.role ?? singletonEventRole(rule); + role.addToPrincipalPolicy(this.executeStatement()); + + if (this.props.deadLetterQueue) { + addToDeadLetterQueueResourcePolicy(rule, this.props.deadLetterQueue); + } + + return { + ...bindBaseTargetConfig(this.props), + arn: this.documentArn, + input: events.RuleTargetInput.fromObject({ ...this.props.input, AutomationAssumeRole: [this.props.automationAssumeRole?.roleArn] }), + role, + targetResource: (typeof this.document === 'string') ? undefined : this.document, + }; + } + + private getDocumentArn(): string { + if (typeof this.document === 'string') { + return this.document; + } else { + return cdk.Arn.format({ + service: 'ssm', + resource: 'automation-definition', + resourceName: this.document.name, + region: cdk.Aws.REGION, + account: cdk.Aws.ACCOUNT_ID, + partition: cdk.Aws.PARTITION, + }); + } + } + + private executeStatement(): iam.PolicyStatement { + return new iam.PolicyStatement({ + actions: ['ssm:StartAutomationExecution'], + resources: [this.documentArn], + }); + } +} diff --git a/packages/@aws-cdk/aws-events-targets/lib/ssm-runcommand.ts b/packages/@aws-cdk/aws-events-targets/lib/ssm-runcommand.ts new file mode 100644 index 0000000000000..8ba65872a4ac9 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/lib/ssm-runcommand.ts @@ -0,0 +1,133 @@ +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import * as ssm from '@aws-cdk/aws-ssm'; +import * as cdk from '@aws-cdk/core'; +import { addToDeadLetterQueueResourcePolicy, bindBaseTargetConfig, singletonEventRole, TargetBaseProps } from './util'; + +/** + * SsmRunCommandProps + */ +export interface SsmRunCommandProps extends TargetBaseProps { + /** + * Role to be used to run the Document + * + * @default - a new role is created. + */ + readonly role?: iam.IRole; + + /** + * Can be either `tag:` *tag-key* or `InstanceIds` . + * + * @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-runcommandtarget.html#cfn-events-rule-runcommandtarget-key + */ + readonly targetKey: events.CfnRule.RunCommandTargetProperty['key']; + + /** + * If Target Key is 'InstanceIds', Values are the list of EC2 Instance Ids. If Target Key is 'tag:', Values are list of tag values. + */ + readonly targetValues: string[]; + + /** + * Specify input for the SSM Document if appropriate. + * + * @default - no input parameters passed to document + */ + readonly input?: { [key: string]: string[] }; +} + +/** + * Create an SSM Run Command Event Target + */ +export class SsmRunCommand implements events.IRuleTarget { + private documentArn: string; + + constructor( + /** + * Provide an instance of a `ssm.CfnDocument` + */ + public readonly document: ssm.CfnDocument, + private readonly props: SsmRunCommandProps, + ) { + this.documentArn = this.getDocumentArn(); + } + + /** + * Returns a RuleTarget that can be used to trigger this SSM Run Command as a + * result from an EventBridge event. + * + * @see https://docs.aws.amazon.com/eventbridge/latest/userguide/resource-based-policies-eventbridge.html + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public bind(rule: events.IRule, _id?: string): events.RuleTargetConfig { + const role = this.props.role ?? singletonEventRole(rule); + role.addToPrincipalPolicy(this.executeStatement()); + + if (this.props.deadLetterQueue) { + addToDeadLetterQueueResourcePolicy(rule, this.props.deadLetterQueue); + } + + return { + ...bindBaseTargetConfig(this.props), + arn: this.documentArn, + role, + input: events.RuleTargetInput.fromObject(this.props.input), + runCommandParameters: { + runCommandTargets: [ + { + key: this.props.targetKey, + values: this.props.targetValues, + }, + ], + }, + targetResource: this.document, + }; + } + + private getDocumentArn(): string { + return cdk.Arn.format({ + service: 'ssm', + resource: 'document', + resourceName: this.document.name, + region: cdk.Aws.REGION, + account: cdk.Aws.ACCOUNT_ID, + partition: cdk.Aws.PARTITION, + }); + } + + private executeStatement(): iam.PolicyStatement { + if (this.props.targetKey === 'InstanceIds') { + return new iam.PolicyStatement({ + actions: ['ssm:SendCommand'], + resources: this.props.targetValues.map(instanceId => + cdk.Arn.format({ + service: 'ec2', + resource: 'instance', + resourceName: instanceId, + region: cdk.Aws.REGION, + account: cdk.Aws.ACCOUNT_ID, + partition: cdk.Aws.PARTITION, + }), + ), + }); + } else { + return new iam.PolicyStatement({ + actions: ['ssm:SendCommand'], + resources: [ + cdk.Arn.format({ + service: 'ec2', + resource: 'instance', + resourceName: '*', + region: cdk.Aws.REGION, + account: cdk.Aws.ACCOUNT_ID, + partition: cdk.Aws.PARTITION, + }), + ], + conditions: { + StringEquals: { + 'ec2:ResourceTag/*': this.props.targetValues, + }, + }, + }); + } + } +} diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 70c65b6b65abc..d144b1d55febd 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -110,6 +110,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", @@ -133,6 +134,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/integ.ssm-automation-event-rule-target.ts b/packages/@aws-cdk/aws-events-targets/test/ssm/integ.ssm-automation-event-rule-target.ts new file mode 100644 index 0000000000000..85282707c4096 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/integ.ssm-automation-event-rule-target.ts @@ -0,0 +1,41 @@ +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { Construct } from 'constructs'; +import * as targets from '../../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const event = new events.Rule(this, 'MyRule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + const automationArn = `arn:aws:ssm:${cdk.Stack.of(this).region}::automation-definition/AWS-StopRdsInstance:$DEFAULT`; + + const deadLetterQueue = new sqs.Queue(this, 'MyDeadLetterQueue'); + + const automationAssumeRole = new iam.Role(this, 'AutomationAssumeRole', { + assumedBy: new iam.ServicePrincipal('ssm.amazonaws.com'), + }); + + event.addTarget(new targets.SsmAutomation(automationArn, { + input: { + InstanceId: ['my-rds-instance'], + }, + automationAssumeRole, + deadLetterQueue, + })); + } +} + +const app = new cdk.App(); + +new integ.IntegTest(app, 'Testing', { + testCases: [ + new TestStack(app, 'aws-cdk-ssm-automation-event-target'), + ], +}); diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/integ.ssm-runcommand-event-rule-target.ts b/packages/@aws-cdk/aws-events-targets/test/ssm/integ.ssm-runcommand-event-rule-target.ts new file mode 100644 index 0000000000000..839bd9b091ab4 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/integ.ssm-runcommand-event-rule-target.ts @@ -0,0 +1,67 @@ +import * as events from '@aws-cdk/aws-events'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as ssm from '@aws-cdk/aws-ssm'; +import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { Construct } from 'constructs'; +import * as targets from '../../lib'; + +class TestStack extends cdk.Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const event = new events.Rule(this, 'MyRule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), + }); + + const myDocument = new ssm.CfnDocument(this, 'MyDocument', { + content: { + schemaVersion: '2.2', + description: 'My Document', + parameters: { + MyParameter: { + type: 'String', + description: 'My Parameter', + }, + }, + mainSteps: [ + { + action: 'aws:runShellScript', + name: 'runShellScript', + precondition: { + StringEquals: [ + 'platformType', + 'Linux', + ], + }, + inputs: { + runCommand: ['echo "Hello World"'], + }, + }, + ], + }, + documentType: 'Command', + name: 'my-document', + }); + + const deadLetterQueue = new sqs.Queue(this, 'MyDeadLetterQueue'); + + event.addTarget(new targets.SsmRunCommand(myDocument, { + targetKey: 'InstanceIds', + targetValues: ['i-asdfiuh2304f'], + input: { + MyParameter: ['MyParameterValue'], + }, + retryAttempts: 0, + deadLetterQueue, + })); + } +} + +const app = new cdk.App(); + +new integ.IntegTest(app, 'Testing', { + testCases: [ + new TestStack(app, 'aws-cdk-ssm-runcommand-event-target'), + ], +}); diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.assets.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.assets.json new file mode 100644 index 0000000000000..466a97dc1d284 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "TestingDefaultTestDeployAssertE4BE5621.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.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-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.template.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/aws-cdk-ssm-automation-event-target.assets.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/aws-cdk-ssm-automation-event-target.assets.json new file mode 100644 index 0000000000000..3ee3f94311227 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/aws-cdk-ssm-automation-event-target.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "ce4f6c1816c6a77aa60915291668f6ceb537b8a131557390c35b976cb8b2dc74": { + "source": { + "path": "aws-cdk-ssm-automation-event-target.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "ce4f6c1816c6a77aa60915291668f6ceb537b8a131557390c35b976cb8b2dc74.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-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/aws-cdk-ssm-automation-event-target.template.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/aws-cdk-ssm-automation-event-target.template.json new file mode 100644 index 0000000000000..ef269c03f9c70 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/aws-cdk-ssm-automation-event-target.template.json @@ -0,0 +1,201 @@ +{ + "Resources": { + "MyRuleA44AB831": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "State": "ENABLED", + "Targets": [ + { + "Arn": { + "Fn::Join": [ + "", + [ + "arn:aws:ssm:", + { + "Ref": "AWS::Region" + }, + "::automation-definition/AWS-StopRdsInstance:$DEFAULT" + ] + ] + }, + "DeadLetterConfig": { + "Arn": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + } + }, + "Id": "Target0", + "Input": { + "Fn::Join": [ + "", + [ + "{\"InstanceId\":[\"my-rds-instance\"],\"AutomationAssumeRole\":[\"", + { + "Fn::GetAtt": [ + "SSMAssumeRole9F66527C", + "Arn" + ] + }, + "\"]}" + ] + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "MyRuleEventsRoleF186CAE5", + "Arn" + ] + } + } + ] + } + }, + "MyRuleEventsRoleF186CAE5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "MyRuleEventsRoleDefaultPolicy5D01F508": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ssm:StartAutomationExecution", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:ssm:", + { + "Ref": "AWS::Region" + }, + "::automation-definition/AWS-StopRdsInstance:$DEFAULT" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyRuleEventsRoleDefaultPolicy5D01F508", + "Roles": [ + { + "Ref": "MyRuleEventsRoleF186CAE5" + } + ] + } + }, + "MyDeadLetterQueueD997968A": { + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "MyDeadLetterQueuePolicyCC35D52C": { + "Type": "AWS::SQS::QueuePolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "MyRuleA44AB831", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + }, + "Resource": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + }, + "Sid": "AllowEventRuleawscdkssmautomationeventtargetMyRuleCA6803FD" + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "MyDeadLetterQueueD997968A" + } + ] + } + }, + "SSMAssumeRole9F66527C": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ssm.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..8ecc185e9dbee --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/integ.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/integ.json new file mode 100644 index 0000000000000..10ea350e91149 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "21.0.0", + "testCases": { + "Testing/DefaultTest": { + "stacks": [ + "aws-cdk-ssm-automation-event-target" + ], + "assertionStack": "Testing/DefaultTest/DeployAssert", + "assertionStackName": "TestingDefaultTestDeployAssertE4BE5621" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..83c00d9ac1423 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/manifest.json @@ -0,0 +1,141 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-ssm-automation-event-target.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-ssm-automation-event-target.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-ssm-automation-event-target": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-ssm-automation-event-target.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/ce4f6c1816c6a77aa60915291668f6ceb537b8a131557390c35b976cb8b2dc74.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-ssm-automation-event-target.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-ssm-automation-event-target.assets" + ], + "metadata": { + "/aws-cdk-ssm-automation-event-target/MyRule/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyRuleA44AB831" + } + ], + "/aws-cdk-ssm-automation-event-target/MyRule/EventsRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyRuleEventsRoleF186CAE5" + } + ], + "/aws-cdk-ssm-automation-event-target/MyRule/EventsRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyRuleEventsRoleDefaultPolicy5D01F508" + } + ], + "/aws-cdk-ssm-automation-event-target/MyDeadLetterQueue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyDeadLetterQueueD997968A" + } + ], + "/aws-cdk-ssm-automation-event-target/MyDeadLetterQueue/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyDeadLetterQueuePolicyCC35D52C" + } + ], + "/aws-cdk-ssm-automation-event-target/SSMAssumeRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SSMAssumeRole9F66527C" + } + ], + "/aws-cdk-ssm-automation-event-target/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-ssm-automation-event-target/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-ssm-automation-event-target" + }, + "TestingDefaultTestDeployAssertE4BE5621.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TestingDefaultTestDeployAssertE4BE5621.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TestingDefaultTestDeployAssertE4BE5621": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TestingDefaultTestDeployAssertE4BE5621.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "TestingDefaultTestDeployAssertE4BE5621.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "TestingDefaultTestDeployAssertE4BE5621.assets" + ], + "metadata": { + "/Testing/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Testing/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Testing/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/tree.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/tree.json new file mode 100644 index 0000000000000..67d2f27d6001e --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation-event-rule-target.integ.snapshot/tree.json @@ -0,0 +1,337 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.133" + } + }, + "aws-cdk-ssm-automation-event-target": { + "id": "aws-cdk-ssm-automation-event-target", + "path": "aws-cdk-ssm-automation-event-target", + "children": { + "MyRule": { + "id": "MyRule", + "path": "aws-cdk-ssm-automation-event-target/MyRule", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-automation-event-target/MyRule/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Events::Rule", + "aws:cdk:cloudformation:props": { + "scheduleExpression": "rate(1 minute)", + "state": "ENABLED", + "targets": [ + { + "id": "Target0", + "arn": { + "Fn::Join": [ + "", + [ + "arn:aws:ssm:", + { + "Ref": "AWS::Region" + }, + "::automation-definition/AWS-StopRdsInstance:$DEFAULT" + ] + ] + }, + "roleArn": { + "Fn::GetAtt": [ + "MyRuleEventsRoleF186CAE5", + "Arn" + ] + }, + "deadLetterConfig": { + "arn": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + } + }, + "input": { + "Fn::Join": [ + "", + [ + "{\"InstanceId\":[\"my-rds-instance\"],\"AutomationAssumeRole\":[\"", + { + "Fn::GetAtt": [ + "SSMAssumeRole9F66527C", + "Arn" + ] + }, + "\"]}" + ] + ] + } + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-events.CfnRule", + "version": "0.0.0" + } + }, + "EventsRole": { + "id": "EventsRole", + "path": "aws-cdk-ssm-automation-event-target/MyRule/EventsRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-automation-event-target/MyRule/EventsRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-ssm-automation-event-target/MyRule/EventsRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-automation-event-target/MyRule/EventsRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "ssm:StartAutomationExecution", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:ssm:", + { + "Ref": "AWS::Region" + }, + "::automation-definition/AWS-StopRdsInstance:$DEFAULT" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "MyRuleEventsRoleDefaultPolicy5D01F508", + "roles": [ + { + "Ref": "MyRuleEventsRoleF186CAE5" + } + ] + } + }, + "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-events.Rule", + "version": "0.0.0" + } + }, + "MyDeadLetterQueue": { + "id": "MyDeadLetterQueue", + "path": "aws-cdk-ssm-automation-event-target/MyDeadLetterQueue", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-automation-event-target/MyDeadLetterQueue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sqs.CfnQueue", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "aws-cdk-ssm-automation-event-target/MyDeadLetterQueue/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-automation-event-target/MyDeadLetterQueue/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::QueuePolicy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "MyRuleA44AB831", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + }, + "Resource": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + }, + "Sid": "AllowEventRuleawscdkssmautomationeventtargetMyRuleCA6803FD" + } + ], + "Version": "2012-10-17" + }, + "queues": [ + { + "Ref": "MyDeadLetterQueueD997968A" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sqs.CfnQueuePolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sqs.QueuePolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sqs.Queue", + "version": "0.0.0" + } + }, + "SSMAssumeRole": { + "id": "SSMAssumeRole", + "path": "aws-cdk-ssm-automation-event-target/SSMAssumeRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-automation-event-target/SSMAssumeRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ssm.amazonaws.com" + } + } + ], + "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" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "Testing": { + "id": "Testing", + "path": "Testing", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "Testing/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "Testing/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.133" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "Testing/DefaultTest/DeployAssert", + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "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-events-targets/test/ssm/ssm-automation.test.ts b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation.test.ts new file mode 100644 index 0000000000000..7f93705aed017 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-automation.test.ts @@ -0,0 +1,143 @@ +import { Template } from '@aws-cdk/assertions'; +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import * as sqs from '@aws-cdk/aws-sqs'; +import { Duration, Stack } from '@aws-cdk/core'; +import * as targets from '../../lib'; + +test('ssm automation as an event rule target', () => { + // GIVEN + const stack = new Stack(); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(Duration.hours(1)), + }); + const automationArn = 'arn:aws:ssm:us-east-1:123456789012:automation-definition/MyAutomation:1'; + const automationAssumeRole = new iam.Role(stack, 'AutomationAssumeRole', { + assumedBy: new iam.ServicePrincipal('ssm.amazonaws.com'), + }); + + // WHEN + rule.addTarget(new targets.SsmAutomation(automationArn, { + input: { + MyParameter: ['MyParameterValue'], + }, + automationAssumeRole, + })); + + // THEN + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: automationArn, + Id: 'Target0', + }, + ], + }); +}); + +test('dead letter queue is configured correctly', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue', { fifo: true }); + const deadLetterQueue = new sqs.Queue(stack, 'MyDeadLetterQueue'); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SqsQueue(queue, { + deadLetterQueue, + })); + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'MyQueueE6CA6235', + 'Arn', + ], + }, + Id: 'Target0', + DeadLetterConfig: { + Arn: { + 'Fn::GetAtt': [ + 'MyDeadLetterQueueD997968A', + 'Arn', + ], + }, + }, + }, + ], + }); +}); + +test('specifying retry policy', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue', { fifo: true }); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SqsQueue(queue, { + retryAttempts: 2, + maxEventAge: Duration.hours(2), + })); + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'MyQueueE6CA6235', + 'Arn', + ], + }, + Id: 'Target0', + RetryPolicy: { + MaximumEventAgeInSeconds: 7200, + MaximumRetryAttempts: 2, + }, + }, + ], + }); +}); + +test('specifying retry policy with 0 retryAttempts', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue', { fifo: true }); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SqsQueue(queue, { + retryAttempts: 0, + })); + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'MyQueueE6CA6235', + 'Arn', + ], + }, + Id: 'Target0', + RetryPolicy: { + MaximumRetryAttempts: 0, + }, + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.assets.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.assets.json new file mode 100644 index 0000000000000..466a97dc1d284 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "TestingDefaultTestDeployAssertE4BE5621.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.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-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.template.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/TestingDefaultTestDeployAssertE4BE5621.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/aws-cdk-ssm-runcommand-event-target.assets.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/aws-cdk-ssm-runcommand-event-target.assets.json new file mode 100644 index 0000000000000..164e77e521a6a --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/aws-cdk-ssm-runcommand-event-target.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "63529148a45bce330dafffec6c918d431de85bcd8f72e124096d90eaa707bd84": { + "source": { + "path": "aws-cdk-ssm-runcommand-event-target.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "63529148a45bce330dafffec6c918d431de85bcd8f72e124096d90eaa707bd84.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-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/aws-cdk-ssm-runcommand-event-target.template.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/aws-cdk-ssm-runcommand-event-target.template.json new file mode 100644 index 0000000000000..a5b403ee9833d --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/aws-cdk-ssm-runcommand-event-target.template.json @@ -0,0 +1,233 @@ +{ + "Resources": { + "MyRuleA44AB831": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "State": "ENABLED", + "Targets": [ + { + "Arn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ssm:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":document/my-document" + ] + ] + }, + "DeadLetterConfig": { + "Arn": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + } + }, + "Id": "Target0", + "Input": "{\"MyParameter\":[\"MyParameterValue\"]}", + "RetryPolicy": { + "MaximumRetryAttempts": 0 + }, + "RoleArn": { + "Fn::GetAtt": [ + "MyRuleEventsRoleF186CAE5", + "Arn" + ] + }, + "RunCommandParameters": { + "RunCommandTargets": [ + { + "Key": "InstanceIds", + "Values": [ + "i-asdfiuh2304f" + ] + } + ] + } + } + ] + } + }, + "MyRuleEventsRoleF186CAE5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "MyRuleEventsRoleDefaultPolicy5D01F508": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ssm:SendCommand", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ec2:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":instance/i-asdfiuh2304f" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyRuleEventsRoleDefaultPolicy5D01F508", + "Roles": [ + { + "Ref": "MyRuleEventsRoleF186CAE5" + } + ] + } + }, + "MyDocument": { + "Type": "AWS::SSM::Document", + "Properties": { + "Content": { + "schemaVersion": "2.2", + "description": "My Document", + "parameters": { + "MyParameter": { + "type": "String", + "description": "My Parameter" + } + }, + "mainSteps": [ + { + "action": "aws:runShellScript", + "name": "runShellScript", + "precondition": { + "StringEquals": [ + "platformType", + "Linux" + ] + }, + "inputs": { + "runCommand": [ + "echo \"Hello World\"" + ] + } + } + ] + }, + "DocumentType": "Command", + "Name": "my-document" + } + }, + "MyDeadLetterQueueD997968A": { + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "MyDeadLetterQueuePolicyCC35D52C": { + "Type": "AWS::SQS::QueuePolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "MyRuleA44AB831", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + }, + "Resource": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + }, + "Sid": "AllowEventRuleawscdkssmruncommandeventtargetMyRule6B9F9D33" + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "MyDeadLetterQueueD997968A" + } + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..8ecc185e9dbee --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/integ.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/integ.json new file mode 100644 index 0000000000000..65665147ed98d --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "21.0.0", + "testCases": { + "Testing/DefaultTest": { + "stacks": [ + "aws-cdk-ssm-runcommand-event-target" + ], + "assertionStack": "Testing/DefaultTest/DeployAssert", + "assertionStackName": "TestingDefaultTestDeployAssertE4BE5621" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..cbb4244fffe53 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/manifest.json @@ -0,0 +1,141 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-ssm-runcommand-event-target.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-ssm-runcommand-event-target.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-ssm-runcommand-event-target": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-ssm-runcommand-event-target.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/63529148a45bce330dafffec6c918d431de85bcd8f72e124096d90eaa707bd84.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-ssm-runcommand-event-target.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-ssm-runcommand-event-target.assets" + ], + "metadata": { + "/aws-cdk-ssm-runcommand-event-target/MyRule/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyRuleA44AB831" + } + ], + "/aws-cdk-ssm-runcommand-event-target/MyRule/EventsRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyRuleEventsRoleF186CAE5" + } + ], + "/aws-cdk-ssm-runcommand-event-target/MyRule/EventsRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyRuleEventsRoleDefaultPolicy5D01F508" + } + ], + "/aws-cdk-ssm-runcommand-event-target/MyDocument": [ + { + "type": "aws:cdk:logicalId", + "data": "MyDocument" + } + ], + "/aws-cdk-ssm-runcommand-event-target/MyDeadLetterQueue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyDeadLetterQueueD997968A" + } + ], + "/aws-cdk-ssm-runcommand-event-target/MyDeadLetterQueue/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyDeadLetterQueuePolicyCC35D52C" + } + ], + "/aws-cdk-ssm-runcommand-event-target/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-ssm-runcommand-event-target/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-ssm-runcommand-event-target" + }, + "TestingDefaultTestDeployAssertE4BE5621.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TestingDefaultTestDeployAssertE4BE5621.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TestingDefaultTestDeployAssertE4BE5621": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TestingDefaultTestDeployAssertE4BE5621.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "TestingDefaultTestDeployAssertE4BE5621.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "TestingDefaultTestDeployAssertE4BE5621.assets" + ], + "metadata": { + "/Testing/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Testing/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Testing/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/tree.json b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/tree.json new file mode 100644 index 0000000000000..7732562d534b5 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand-event-rule-target.integ.snapshot/tree.json @@ -0,0 +1,359 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.133" + } + }, + "aws-cdk-ssm-runcommand-event-target": { + "id": "aws-cdk-ssm-runcommand-event-target", + "path": "aws-cdk-ssm-runcommand-event-target", + "children": { + "MyRule": { + "id": "MyRule", + "path": "aws-cdk-ssm-runcommand-event-target/MyRule", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-runcommand-event-target/MyRule/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Events::Rule", + "aws:cdk:cloudformation:props": { + "scheduleExpression": "rate(1 minute)", + "state": "ENABLED", + "targets": [ + { + "id": "Target0", + "arn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ssm:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":document/my-document" + ] + ] + }, + "roleArn": { + "Fn::GetAtt": [ + "MyRuleEventsRoleF186CAE5", + "Arn" + ] + }, + "runCommandParameters": { + "runCommandTargets": [ + { + "key": "InstanceIds", + "values": [ + "i-asdfiuh2304f" + ] + } + ] + }, + "deadLetterConfig": { + "arn": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + } + }, + "retryPolicy": { + "maximumRetryAttempts": 0 + }, + "input": "{\"MyParameter\":[\"MyParameterValue\"]}" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-events.CfnRule", + "version": "0.0.0" + } + }, + "EventsRole": { + "id": "EventsRole", + "path": "aws-cdk-ssm-runcommand-event-target/MyRule/EventsRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-runcommand-event-target/MyRule/EventsRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-ssm-runcommand-event-target/MyRule/EventsRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-runcommand-event-target/MyRule/EventsRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "ssm:SendCommand", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ec2:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":instance/i-asdfiuh2304f" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "MyRuleEventsRoleDefaultPolicy5D01F508", + "roles": [ + { + "Ref": "MyRuleEventsRoleF186CAE5" + } + ] + } + }, + "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-events.Rule", + "version": "0.0.0" + } + }, + "MyDocument": { + "id": "MyDocument", + "path": "aws-cdk-ssm-runcommand-event-target/MyDocument", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SSM::Document", + "aws:cdk:cloudformation:props": { + "content": { + "schemaVersion": "2.2", + "description": "My Document", + "parameters": { + "MyParameter": { + "type": "String", + "description": "My Parameter" + } + }, + "mainSteps": [ + { + "action": "aws:runShellScript", + "name": "runShellScript", + "precondition": { + "StringEquals": [ + "platformType", + "Linux" + ] + }, + "inputs": { + "runCommand": [ + "echo \"Hello World\"" + ] + } + } + ] + }, + "documentType": "Command", + "name": "my-document" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ssm.CfnDocument", + "version": "0.0.0" + } + }, + "MyDeadLetterQueue": { + "id": "MyDeadLetterQueue", + "path": "aws-cdk-ssm-runcommand-event-target/MyDeadLetterQueue", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-runcommand-event-target/MyDeadLetterQueue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sqs.CfnQueue", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "aws-cdk-ssm-runcommand-event-target/MyDeadLetterQueue/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-ssm-runcommand-event-target/MyDeadLetterQueue/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::QueuePolicy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "MyRuleA44AB831", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + }, + "Resource": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + }, + "Sid": "AllowEventRuleawscdkssmruncommandeventtargetMyRule6B9F9D33" + } + ], + "Version": "2012-10-17" + }, + "queues": [ + { + "Ref": "MyDeadLetterQueueD997968A" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sqs.CfnQueuePolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sqs.QueuePolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-sqs.Queue", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "Testing": { + "id": "Testing", + "path": "Testing", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "Testing/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "Testing/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.133" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "Testing/DefaultTest/DeployAssert", + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "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-events-targets/test/ssm/ssm-runcommand.test.ts b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand.test.ts new file mode 100644 index 0000000000000..d8d1f6fa19475 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/ssm/ssm-runcommand.test.ts @@ -0,0 +1,281 @@ +import { Template } from '@aws-cdk/assertions'; +import * as events from '@aws-cdk/aws-events'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as ssm from '@aws-cdk/aws-ssm'; +import * as cdk from '@aws-cdk/core'; +import * as targets from '../../lib'; + +test('ssm run command as an event rule target', () => { + // GIVEN + const stack = new cdk.Stack(); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(cdk.Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SsmRunCommand(new ssm.CfnDocument(stack, 'MyDocument', { + content: {}, + documentType: 'Command', + name: 'my-document', + }), { + targetKey: 'InstanceIds', + targetValues: ['i-asdfiuh2304f'], + })); + + // THEN + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':document/my-document', + ], + ], + }, + Id: 'Target0', + RoleArn: { + 'Fn::GetAtt': [ + 'MyRuleEventsRoleF186CAE5', + 'Arn', + ], + }, + RunCommandParameters: { + RunCommandTargets: [ + { + Key: 'InstanceIds', + Values: [ + 'i-asdfiuh2304f', + ], + }, + ], + }, + }, + ], + }); +}); + +test('dead letter queue is configured correctly', () => { + const stack = new cdk.Stack(); + const deadLetterQueue = new sqs.Queue(stack, 'MyDeadLetterQueue'); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(cdk.Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SsmRunCommand(new ssm.CfnDocument(stack, 'MyDocument', { + content: {}, + documentType: 'Command', + name: 'my-document', + }), { + targetKey: 'InstanceIds', + targetValues: ['i-asdfiuh2304f'], + deadLetterQueue, + })); + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':document/my-document', + ], + ], + }, + Id: 'Target0', + RoleArn: { + 'Fn::GetAtt': [ + 'MyRuleEventsRoleF186CAE5', + 'Arn', + ], + }, + RunCommandParameters: { + RunCommandTargets: [ + { + Key: 'InstanceIds', + Values: [ + 'i-asdfiuh2304f', + ], + }, + ], + }, + DeadLetterConfig: { + Arn: { + 'Fn::GetAtt': [ + 'MyDeadLetterQueueD997968A', + 'Arn', + ], + }, + }, + }, + ], + }); +}); + +test('specifying retry policy', () => { + const stack = new cdk.Stack(); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(cdk.Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SsmRunCommand(new ssm.CfnDocument(stack, 'MyDocument', { + content: {}, + documentType: 'Command', + name: 'my-document', + }), { + targetKey: 'InstanceIds', + targetValues: ['i-asdfiuh2304f'], + retryAttempts: 2, + maxEventAge: cdk.Duration.hours(2), + })); + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':document/my-document', + ], + ], + }, + Id: 'Target0', + RoleArn: { + 'Fn::GetAtt': [ + 'MyRuleEventsRoleF186CAE5', + 'Arn', + ], + }, + RunCommandParameters: { + RunCommandTargets: [ + { + Key: 'InstanceIds', + Values: [ + 'i-asdfiuh2304f', + ], + }, + ], + }, + RetryPolicy: { + MaximumEventAgeInSeconds: 7200, + MaximumRetryAttempts: 2, + }, + }, + ], + }); +}); + +test('specifying retry policy with 0 retryAttempts', () => { + const stack = new cdk.Stack(); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(cdk.Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SsmRunCommand(new ssm.CfnDocument(stack, 'MyDocument', { + content: {}, + documentType: 'Command', + name: 'my-document', + }), { + targetKey: 'InstanceIds', + targetValues: ['i-asdfiuh2304f'], + retryAttempts: 0, + })); + + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':document/my-document', + ], + ], + }, + Id: 'Target0', + RoleArn: { + 'Fn::GetAtt': [ + 'MyRuleEventsRoleF186CAE5', + 'Arn', + ], + }, + RunCommandParameters: { + RunCommandTargets: [ + { + Key: 'InstanceIds', + Values: [ + 'i-asdfiuh2304f', + ], + }, + ], + }, + RetryPolicy: { + MaximumRetryAttempts: 0, + }, + }, + ], + }); +});