From 18aff6b4c0a5e17c64685ac384b243c16cd910f1 Mon Sep 17 00:00:00 2001 From: david-doyle-as24 <78368860+david-doyle-as24@users.noreply.github.com> Date: Fri, 10 Sep 2021 12:19:59 +0200 Subject: [PATCH] feat(sns): adding support for firehose subscription protocol (#15764) This PR adds support for the firehose subscription protocol by extending the protocol enum and by requiring the field "subscriptionRoleArn" if the protocol is set to firehose. This is so that users can take advantage of the new SNS-to-Firehose integration introduced in February 2021 (see [here](https://aws.amazon.com/blogs/compute/introducing-message-archiving-and-analytics-for-amazon-sns/) for the announcement). Here also is a link to the [sample cloudformation](https://docs.aws.amazon.com/sns/latest/dg/firehose-example-cfn.html), documenting the SNS-to-Firehose integration. *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-sns/README.md | 14 +++++++++ packages/@aws-cdk/aws-sns/lib/subscription.ts | 30 +++++++++++++++++-- packages/@aws-cdk/aws-sns/package.json | 6 ++-- .../aws-sns/test/subscription.test.ts | 29 +++++++++++++++--- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/packages/@aws-cdk/aws-sns/README.md b/packages/@aws-cdk/aws-sns/README.md index ab7120411df39..23ee15e4af508 100644 --- a/packages/@aws-cdk/aws-sns/README.md +++ b/packages/@aws-cdk/aws-sns/README.md @@ -95,6 +95,20 @@ topic.addSubscription(new subs.LambdaSubscription(fn, { })); ``` +### Example of Firehose Subscription + +```typescript + import { Subscription, SubscriptionProtocol, Topic } from '@aws-cdk/aws-sns'; + import { DeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; + const topic = new Topic(stack, 'Topic'); + const stream = new DeliveryStream(stack, 'DeliveryStream', ...) + new Subscription(stack, 'Subscription', { + endpoint: stream.deliveryStreamArn, + protocol: SubscriptionProtocol.FIREHOSE, + subscriptionRoleArn: "SAMPLE_ARN", //role with permissions to send messages to a firehose delivery stream + }) +``` + ## DLQ setup for SNS Subscription CDK can attach provided Queue as DLQ for your SNS subscription. diff --git a/packages/@aws-cdk/aws-sns/lib/subscription.ts b/packages/@aws-cdk/aws-sns/lib/subscription.ts index 88817b6db6fdd..54e26cd24eb60 100644 --- a/packages/@aws-cdk/aws-sns/lib/subscription.ts +++ b/packages/@aws-cdk/aws-sns/lib/subscription.ts @@ -52,6 +52,13 @@ export interface SubscriptionOptions { * @default - No dead letter queue enabled. */ readonly deadLetterQueue?: IQueue; + + /** + * Arn of role allowing access to firehose delivery stream. + * Required for a firehose subscription protocol. + * @default - No subscription role is provided + */ + readonly subscriptionRoleArn?: string; } /** * Properties for creating a new subscription @@ -81,8 +88,15 @@ export class Subscription extends Resource { constructor(scope: Construct, id: string, props: SubscriptionProps) { super(scope, id); - if (props.rawMessageDelivery && ['http', 'https', 'sqs'].indexOf(props.protocol) < 0) { - throw new Error('Raw message delivery can only be enabled for HTTP/S and SQS subscriptions.'); + if (props.rawMessageDelivery && + [ + SubscriptionProtocol.HTTP, + SubscriptionProtocol.HTTPS, + SubscriptionProtocol.SQS, + SubscriptionProtocol.FIREHOSE, + ] + .indexOf(props.protocol) < 0) { + throw new Error('Raw message delivery can only be enabled for HTTP, HTTPS, SQS, and Firehose subscriptions.'); } if (props.filterPolicy) { @@ -103,6 +117,10 @@ export class Subscription extends Resource { } } + if (props.protocol === SubscriptionProtocol.FIREHOSE && !props.subscriptionRoleArn) { + throw new Error('Subscription role arn is required field for subscriptions with a firehose protocol.'); + } + this.deadLetterQueue = this.buildDeadLetterQueue(props); new CfnSubscription(this, 'Resource', { @@ -113,6 +131,7 @@ export class Subscription extends Resource { filterPolicy: this.filterPolicy, region: props.region, redrivePolicy: this.buildDeadLetterConfig(this.deadLetterQueue), + subscriptionRoleArn: props.subscriptionRoleArn, }); } @@ -189,5 +208,10 @@ export enum SubscriptionProtocol { /** * Notifications trigger a Lambda function. */ - LAMBDA = 'lambda' + LAMBDA = 'lambda', + + /** + * Notifications put records into a firehose delivery stream. + */ + FIREHOSE = 'firehose' } diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index c7734d512cdfd..26d7441d5ee6d 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -76,8 +76,8 @@ }, "license": "Apache-2.0", "devDependencies": { - "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "@types/jest": "^26.0.24", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", @@ -86,8 +86,8 @@ "pkglint": "0.0.0" }, "dependencies": { - "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -97,8 +97,8 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns/test/subscription.test.ts b/packages/@aws-cdk/aws-sns/test/subscription.test.ts index 0c19eddc0c7d5..a495769648d4b 100644 --- a/packages/@aws-cdk/aws-sns/test/subscription.test.ts +++ b/packages/@aws-cdk/aws-sns/test/subscription.test.ts @@ -2,6 +2,7 @@ import { Template } from '@aws-cdk/assertions'; import { Queue } from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import * as sns from '../lib'; +import { SubscriptionProtocol } from '../lib'; describe('Subscription', () => { test('create a subscription', () => { @@ -176,19 +177,26 @@ describe('Subscription', () => { }); - test('throws with raw delivery for protocol other than http, https or sqs', () => { + + test.each( + [ + SubscriptionProtocol.LAMBDA, + SubscriptionProtocol.EMAIL, + SubscriptionProtocol.EMAIL_JSON, + SubscriptionProtocol.SMS, + SubscriptionProtocol.APPLICATION, + ]) + ('throws with raw delivery for %s protocol', (protocol: SubscriptionProtocol) => { // GIVEN const stack = new cdk.Stack(); const topic = new sns.Topic(stack, 'Topic'); - // THEN expect(() => new sns.Subscription(stack, 'Subscription', { endpoint: 'endpoint', - protocol: sns.SubscriptionProtocol.LAMBDA, + protocol: protocol, topic, rawMessageDelivery: true, })).toThrow(/Raw message delivery/); - }); test('throws with more than 5 attributes in a filter policy', () => { @@ -232,4 +240,17 @@ describe('Subscription', () => { })).toThrow(/\(120\) must not exceed 100/); }); + + test('throws an error when subscription role arn is not entered with firehose subscription protocol', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'Topic'); + + //THEN + expect(() => new sns.Subscription(stack, 'Subscription', { + endpoint: 'endpoint', + protocol: sns.SubscriptionProtocol.FIREHOSE, + topic, + })).toThrow(/Subscription role arn is required field for subscriptions with a firehose protocol./); + }); });