From 1d48e14461793186696e61810d54e568fbe6be1d Mon Sep 17 00:00:00 2001 From: Ross Date: Sun, 5 Jan 2025 12:46:17 +0000 Subject: [PATCH] feat(events): configure schema discovery on event bus --- ...efaultTestDeployAssertE6DF8EA9.assets.json | 2 +- .../Stack.assets.json | 6 +- .../Stack.template.json | 24 ++++ .../test/integ.eventbus.js.snapshot/cdk.out | 2 +- .../integ.eventbus.js.snapshot/integ.json | 2 +- .../integ.eventbus.js.snapshot/manifest.json | 10 +- .../test/integ.eventbus.js.snapshot/tree.json | 96 ++++++++----- .../test/aws-events/test/integ.eventbus.ts | 2 + packages/aws-cdk-lib/aws-events/README.md | 16 +++ .../aws-cdk-lib/aws-events/lib/event-bus.ts | 37 +++++ .../aws-events/test/event-bus.test.ts | 126 ++++++++++++++++++ 11 files changed, 283 insertions(+), 40 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/IntegTestEventBusStackDefaultTestDeployAssertE6DF8EA9.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/IntegTestEventBusStackDefaultTestDeployAssertE6DF8EA9.assets.json index b016e8fe026ce..0171b7659e384 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/IntegTestEventBusStackDefaultTestDeployAssertE6DF8EA9.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/IntegTestEventBusStackDefaultTestDeployAssertE6DF8EA9.assets.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "39.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/Stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/Stack.assets.json index 8283986c144e7..ba40004cecb4c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/Stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/Stack.assets.json @@ -1,7 +1,7 @@ { - "version": "36.0.0", + "version": "39.0.0", "files": { - "4c3d1a4b2e322a4753eb4eaf49c45451cc6a8bd2662a6d2c740c369f3e55d10f": { + "8e311f0e30a6fad41c23c084bcc45970b66b1a61fa5030cf6d26f613dba7932b": { "source": { "path": "Stack.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "4c3d1a4b2e322a4753eb4eaf49c45451cc6a8bd2662a6d2c740c369f3e55d10f.json", + "objectKey": "8e311f0e30a6fad41c23c084bcc45970b66b1a61fa5030cf6d26f613dba7932b.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/Stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/Stack.template.json index 0ca0b5065f5e4..e7a595fc9ea3d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/Stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/Stack.template.json @@ -95,6 +95,30 @@ }, "StatementId": "cdk-Statement2" } + }, + "BusSchemaDiscoveryE6A342A5": { + "Type": "AWS::EventSchemas::Discoverer", + "Properties": { + "CrossAccount": true, + "Description": { + "Fn::Join": [ + "", + [ + "Schema Discoverer for ", + { + "Ref": "BusEA82B648" + }, + " Event Bus" + ] + ] + }, + "SourceArn": { + "Fn::GetAtt": [ + "BusEA82B648", + "Arn" + ] + } + } } }, "Parameters": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/cdk.out index 1f0068d32659a..91e1a8b9901d5 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"36.0.0"} \ No newline at end of file +{"version":"39.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/integ.json index c5e97be0cb324..dc700ea532ad8 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "39.0.0", "testCases": { "IntegTest-EventBusStack/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/manifest.json index bf76759facbc8..c9f6520037a25 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "36.0.0", + "version": "39.0.0", "artifacts": { "Stack.assets": { "type": "cdk:asset-manifest", @@ -18,7 +18,7 @@ "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}/4c3d1a4b2e322a4753eb4eaf49c45451cc6a8bd2662a6d2c740c369f3e55d10f.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/8e311f0e30a6fad41c23c084bcc45970b66b1a61fa5030cf6d26f613dba7932b.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -58,6 +58,12 @@ "data": "BuscdkStatement2341A5B58" } ], + "/Stack/Bus/SchemaDiscovery": [ + { + "type": "aws:cdk:logicalId", + "data": "BusSchemaDiscoveryE6A342A5" + } + ], "/Stack/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/tree.json index 05f7895c8c043..6e3fe3e4b9601 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.js.snapshot/tree.json @@ -20,14 +20,14 @@ "aws:cdk:cloudformation:props": {} }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_sqs.CfnQueue", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_sqs.Queue", + "version": "0.0.0" } }, "Bus": { @@ -53,8 +53,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_events.CfnEventBus", + "version": "0.0.0" } }, "cdk-Statement1": { @@ -103,14 +103,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_events.CfnEventBusPolicy", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_events.EventBusPolicy", + "version": "0.0.0" } }, "cdk-Statement2": { @@ -159,42 +159,74 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_events.CfnEventBusPolicy", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_events.EventBusPolicy", + "version": "0.0.0" + } + }, + "SchemaDiscovery": { + "id": "SchemaDiscovery", + "path": "Stack/Bus/SchemaDiscovery", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EventSchemas::Discoverer", + "aws:cdk:cloudformation:props": { + "crossAccount": true, + "description": { + "Fn::Join": [ + "", + [ + "Schema Discoverer for ", + { + "Ref": "BusEA82B648" + }, + " Event Bus" + ] + ] + }, + "sourceArn": { + "Fn::GetAtt": [ + "BusEA82B648", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_eventschemas.CfnDiscoverer", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.aws_events.EventBus", + "version": "0.0.0" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "Stack/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "Stack/CheckBootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" } }, "IntegTest-EventBusStack": { @@ -210,7 +242,7 @@ "path": "IntegTest-EventBusStack/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.3.0" + "version": "10.4.2" } }, "DeployAssert": { @@ -221,22 +253,22 @@ "id": "BootstrapVersion", "path": "IntegTest-EventBusStack/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "IntegTest-EventBusStack/DefaultTest/DeployAssert/CheckBootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" } } }, @@ -256,13 +288,13 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.3.0" + "version": "10.4.2" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.ts index 331dec2c9bb63..47efdf74dd15b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events/test/integ.eventbus.ts @@ -30,6 +30,8 @@ bus.addToResourcePolicy(new iam.PolicyStatement({ resources: [bus.eventBusArn], })); +bus.schemaDiscovery('SchemaDiscovery'); + new IntegTest(app, 'IntegTest-EventBusStack', { testCases: [stack], }); diff --git a/packages/aws-cdk-lib/aws-events/README.md b/packages/aws-cdk-lib/aws-events/README.md index a4bc633b94b2f..9510ac93c2e37 100644 --- a/packages/aws-cdk-lib/aws-events/README.md +++ b/packages/aws-cdk-lib/aws-events/README.md @@ -272,6 +272,22 @@ bus.archive('MyArchive', { }); ``` +## Schema Discovery + +It is possible to automatically generate schemas in Schema Registry for events sent to an event bus. This is useful for discovering what events are sent to the event bus. + +```ts +const bus = new events.EventBus(this, 'bus', { + eventBusName: 'MyCustomEventBus', + description: 'MyCustomEventBus', +}); + +bus.schemaDiscovery('MySchemaDiscovery', { + crossAccount: true, + description: 'MyCustomerEventBus Schema Discovery', +}); +``` + ## Dead-Letter Queue for EventBus It is possible to configure a [Dead Letter Queue for an EventBus](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rule-event-delivery.html#eb-rule-dlq). This is useful when you want to capture events that could not be delivered to any of the targets. diff --git a/packages/aws-cdk-lib/aws-events/lib/event-bus.ts b/packages/aws-cdk-lib/aws-events/lib/event-bus.ts index 9af6134018d18..be99fdfe83b4c 100644 --- a/packages/aws-cdk-lib/aws-events/lib/event-bus.ts +++ b/packages/aws-cdk-lib/aws-events/lib/event-bus.ts @@ -1,11 +1,33 @@ import { Construct } from 'constructs'; import { Archive, BaseArchiveProps } from './archive'; import { CfnEventBus, CfnEventBusPolicy } from './events.generated'; +import * as eventschemas from '../../aws-eventschemas'; import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as sqs from '../../aws-sqs'; import { ArnFormat, IResource, Lazy, Names, Resource, Stack, Token } from '../../core'; +/** + * Properties to configure schema discovery on an event bus + */ +interface SchemaDiscoveryProps { + /** + * Allows for the discovery of the event schemas that are sent to the event bus from another account + * + * @link https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eventschemas-discoverer.html#cfn-eventschemas-discoverer-crossaccount + * @default - none + */ + readonly crossAccount: boolean; + + /** + * A description for the discoverer + * + * @link https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eventschemas-discoverer.html#cfn-eventschemas-discoverer-description + * @default - none + */ + readonly description: string; +}; + /** * Interface which all EventBus based classes MUST implement */ @@ -50,6 +72,13 @@ export interface IEventBus extends IResource { */ archive(id: string, props: BaseArchiveProps): Archive; + /** + * Create an EventBridge schema discoverer to automatically generate schemas based on events on this event bus. + * + * @param props Properties of the schema discoverer + */ + schemaDiscovery(id: string, props?: SchemaDiscoveryProps): eventschemas.CfnDiscoverer; + /** * Grants an IAM Principal to send custom events to the eventBus * so that they can be matched to rules. @@ -175,6 +204,14 @@ abstract class EventBusBase extends Resource implements IEventBus { }); } + public schemaDiscovery(id: string, props?: SchemaDiscoveryProps): eventschemas.CfnDiscoverer { + return new eventschemas.CfnDiscoverer(this, id, { + crossAccount: props?.crossAccount ?? true, + description: props?.description || `Schema Discoverer for ${this.eventBusName} Event Bus`, + sourceArn: this.eventBusArn, + }); + } + public grantPutEventsTo(grantee: iam.IGrantable): iam.Grant { return iam.Grant.addToPrincipal({ grantee, diff --git a/packages/aws-cdk-lib/aws-events/test/event-bus.test.ts b/packages/aws-cdk-lib/aws-events/test/event-bus.test.ts index bc48153cf9ee1..7f2068b52583b 100644 --- a/packages/aws-cdk-lib/aws-events/test/event-bus.test.ts +++ b/packages/aws-cdk-lib/aws-events/test/event-bus.test.ts @@ -531,6 +531,132 @@ describe('event bus', () => { }); }); + test('can be configured for schema discovery with default properties', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const event = new EventBus(stack, 'Bus'); + + event.schemaDiscovery('MySchemaDiscoverer'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Events::EventBus', { + Name: 'Bus', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::EventSchemas::Discoverer', { + SourceArn: { + 'Fn::GetAtt': [ + 'BusEA82B648', + 'Arn', + ], + }, + Description: { + 'Fn::Join': [ + '', + [ + 'Schema Discoverer for ', + { + Ref: 'BusEA82B648', + }, + ' Event Bus', + ], + ], + }, + }); + }); + + test('can be configured for schema discovery with custom properties', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const event = new EventBus(stack, 'Bus'); + + event.schemaDiscovery('MySchemaDiscoverer', { + crossAccount: false, + description: 'A custom schema discovery description.', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Events::EventBus', { + Name: 'Bus', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::EventSchemas::Discoverer', { + SourceArn: { + 'Fn::GetAtt': [ + 'BusEA82B648', + 'Arn', + ], + }, + Description: 'A custom schema discovery description.', + CrossAccount: false, + }); + }); + + test('can be configured for schema discovery from an imported EventBus', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const bus = new EventBus(stack, 'Bus'); + + const importedBus = EventBus.fromEventBusArn(stack, 'ImportedBus', bus.eventBusArn); + + importedBus.schemaDiscovery('MySchemaDiscoverer'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Events::EventBus', { + Name: 'Bus', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::EventSchemas::Discoverer', { + SourceArn: { + 'Fn::GetAtt': [ + 'BusEA82B648', + 'Arn', + ], + }, + Description: { + 'Fn::Join': [ + '', + [ + 'Schema Discoverer for ', + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '/', + { + 'Fn::Select': [ + 5, + { + 'Fn::Split': [ + ':', + { + 'Fn::GetAtt': [ + 'BusEA82B648', + 'Arn', + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ' Event Bus', + ], + ], + }, + }); + }); + test('cross account event bus uses generated physical name', () => { // GIVEN const app = new App();