diff --git a/packages/@aws-cdk/aws-events-targets/README.md b/packages/@aws-cdk/aws-events-targets/README.md index 686c26c270bbc..10d088bc74458 100644 --- a/packages/@aws-cdk/aws-events-targets/README.md +++ b/packages/@aws-cdk/aws-events-targets/README.md @@ -23,6 +23,7 @@ Currently supported are: * Queue a Batch job * Make an AWS API call * Put a record to a Kinesis stream +* Put a record to a Kinesis Firehose stream See the README of the `@aws-cdk/aws-events` library for more information on EventBridge. diff --git a/packages/@aws-cdk/aws-events-targets/lib/firehose-stream.ts b/packages/@aws-cdk/aws-events-targets/lib/firehose-stream.ts new file mode 100644 index 0000000000000..14ba7f5093e3b --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/lib/firehose-stream.ts @@ -0,0 +1,47 @@ +import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; +import * as firehose from '@aws-cdk/aws-kinesisfirehose'; +import { singletonEventRole } from './util'; + +/** + * Customize the Firehose Stream Event Target + */ +export interface FirehoseStreamProps { + /** + * The message to send to the stream. + * + * Must be a valid JSON text passed to the target stream. + * + * @default - the entire CloudWatch event + */ + readonly message?: events.RuleTargetInput; +} + + +/** + * Customize the Firehose Stream Event Target + */ +export class FirehoseStream implements events.IRuleTarget { + + constructor(private readonly stream: firehose.CfnDeliveryStream, private readonly props: FirehoseStreamProps = {}) { + } + + /** + * Returns a RuleTarget that can be used to trigger this Firehose Stream as a + * result from a CloudWatch event. + */ + public bind(_rule: events.IRule, _id?: string): events.RuleTargetConfig { + const policyStatements = [new iam.PolicyStatement({ + actions: ['firehose:PutRecord', 'firehose:PutRecordBatch'], + resources: [this.stream.attrArn], + })]; + + return { + id: '', + arn: this.stream.attrArn, + role: singletonEventRole(this.stream, policyStatements), + input: this.props.message, + targetResource: this.stream, + }; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/lib/index.ts b/packages/@aws-cdk/aws-events-targets/lib/index.ts index 7031423e6b739..9c4df9e57173e 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/index.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/index.ts @@ -9,3 +9,4 @@ export * from './ecs-task-properties'; export * from './ecs-task'; export * from './state-machine'; export * from './kinesis-stream'; +export * from './firehose-stream'; diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 1d5b00a5f6308..52a69cdb23c83 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -77,39 +77,41 @@ "pkglint": "0.0.0" }, "dependencies": { + "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kinesis": "0.0.0", + "@aws-cdk/aws-kinesisfirehose": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@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-sns-subscriptions": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", - "@aws-cdk/aws-kinesis": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.0.4" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kinesis": "0.0.0", + "@aws-cdk/aws-kinesisfirehose": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@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-sns-subscriptions": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.0.4", - "@aws-cdk/aws-kinesis": "0.0.0" + "constructs": "^3.0.4" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-events-targets/test/firehose/firehose-stream.test.ts b/packages/@aws-cdk/aws-events-targets/test/firehose/firehose-stream.test.ts new file mode 100644 index 0000000000000..5ad1af6be36f3 --- /dev/null +++ b/packages/@aws-cdk/aws-events-targets/test/firehose/firehose-stream.test.ts @@ -0,0 +1,80 @@ +import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; +import * as events from '@aws-cdk/aws-events'; +import * as firehose from '@aws-cdk/aws-kinesisfirehose'; +import { Stack } from '@aws-cdk/core'; +import * as targets from '../../lib'; + +describe('FirehoseStream event target', () => { + let stack: Stack; + let stream: firehose.CfnDeliveryStream; + let streamArn: any; + + beforeEach(() => { + stack = new Stack(); + stream = new firehose.CfnDeliveryStream(stack, 'MyStream'); + streamArn = { 'Fn::GetAtt': ['MyStream', 'Arn'] }; + }); + + describe('when added to an event rule as a target', () => { + let rule: events.Rule; + + beforeEach(() => { + rule = new events.Rule(stack, 'rule', { + schedule: events.Schedule.expression('rate(1 minute)'), + }); + }); + + describe('with default settings', () => { + beforeEach(() => { + rule.addTarget(new targets.FirehoseStream(stream)); + }); + + test("adds the stream's ARN and role to the targets of the rule", () => { + expect(stack).to(haveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: streamArn, + Id: 'Target0', + RoleArn: { 'Fn::GetAtt': ['MyStreamEventsRole5B6CC6AF', 'Arn'] }, + }, + ], + })); + }); + + test("creates a policy that has PutRecord and PutRecords permissions on the stream's ARN", () => { + expect(stack).to(haveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: ['firehose:PutRecord', 'firehose:PutRecordBatch'], + Effect: 'Allow', + Resource: streamArn, + }, + ], + Version: '2012-10-17', + }, + })); + }); + }); + + describe('with an explicit message', () => { + beforeEach(() => { + rule.addTarget(new targets.FirehoseStream(stream, { + message: events.RuleTargetInput.fromText('fooBar'), + })); + }); + + test('sets the input', () => { + expect(stack).to(haveResourceLike('AWS::Events::Rule', { + Targets: [ + { + Arn: streamArn, + Id: 'Target0', + Input: '"fooBar"', + }, + ], + })); + }); + }); + }); +});