diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.assets.json new file mode 100644 index 0000000000000..bb11ef00ebc55 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD Template", + "source": { + "path": "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-d8d86b35": { + "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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/cdk.out new file mode 100644 index 0000000000000..523a9aac37cbf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"48.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/integ.json new file mode 100644 index 0000000000000..672b9a8f90688 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "48.0.0", + "testCases": { + "LambdaEventSourceKafkaDlqTest/DefaultTest": { + "stacks": [ + "lambda-event-source-self-managed-kafka-dlq" + ], + "assertionStack": "LambdaEventSourceKafkaDlqTest/DefaultTest/DeployAssert", + "assertionStackName": "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD" + } + }, + "minimumCliVersion": "2.1027.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/lambda-event-source-self-managed-kafka-dlq.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/lambda-event-source-self-managed-kafka-dlq.assets.json new file mode 100644 index 0000000000000..132e0c595a820 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/lambda-event-source-self-managed-kafka-dlq.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "457d39b8f4743fd62862658c4f58c720dc89747080bbaf6c68a824ea08e5e731": { + "displayName": "lambda-event-source-self-managed-kafka-dlq Template", + "source": { + "path": "lambda-event-source-self-managed-kafka-dlq.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-01826928": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "457d39b8f4743fd62862658c4f58c720dc89747080bbaf6c68a824ea08e5e731.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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/lambda-event-source-self-managed-kafka-dlq.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/lambda-event-source-self-managed-kafka-dlq.template.json new file mode 100644 index 0000000000000..4fc3bf3b43673 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/lambda-event-source-self-managed-kafka-dlq.template.json @@ -0,0 +1,184 @@ +{ + "Resources": { + "SelfManagedKafkaFunctionServiceRole8B4CD784": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "SelfManagedKafkaFunctionServiceRoleDefaultPolicy93A35EC6": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": [ + { + "Ref": "ClientCertSecret84224011" + }, + { + "Ref": "RootCASecret21632BB9" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SelfManagedKafkaFunctionServiceRoleDefaultPolicy93A35EC6", + "Roles": [ + { + "Ref": "SelfManagedKafkaFunctionServiceRole8B4CD784" + } + ] + } + }, + "SelfManagedKafkaFunction79CF5C6C": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SelfManagedKafkaFunctionServiceRole8B4CD784", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "SelfManagedKafkaFunctionServiceRoleDefaultPolicy93A35EC6", + "SelfManagedKafkaFunctionServiceRole8B4CD784" + ] + }, + "SelfManagedKafkaFunctionKafkaEventSource99e655d80fe5967cadc6359fb2218a33selfmanagedtesttopic9AE37B25": { + "Type": "AWS::Lambda::EventSourceMapping", + "Properties": { + "BatchSize": 100, + "DestinationConfig": { + "OnFailure": { + "Destination": "kafka://self-managed-kafka-failure-topic" + } + }, + "FunctionName": { + "Ref": "SelfManagedKafkaFunction79CF5C6C" + }, + "ProvisionedPollerConfig": { + "MaximumPollers": 1, + "MinimumPollers": 1 + }, + "SelfManagedEventSource": { + "Endpoints": { + "KafkaBootstrapServers": [ + "self-managed-kafka-broker-1:9092", + "self-managed-kafka-broker-2:9092", + "self-managed-kafka-broker-3:9092" + ] + } + }, + "SelfManagedKafkaEventSourceConfig": { + "ConsumerGroupId": "self-managed-test-consumer-group" + }, + "SourceAccessConfigurations": [ + { + "Type": "CLIENT_CERTIFICATE_TLS_AUTH", + "URI": { + "Ref": "ClientCertSecret84224011" + } + }, + { + "Type": "SERVER_ROOT_CA_CERTIFICATE", + "URI": { + "Ref": "RootCASecret21632BB9" + } + } + ], + "StartingPosition": "TRIM_HORIZON", + "Topics": [ + "self-managed-test-topic" + ] + } + }, + "RootCASecret21632BB9": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "SecretString": "{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuaAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClientCertSecret84224011": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "SecretString": "{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuaAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\",\"privateKey\":\"-----BEGIN ENCRYPTED PRIVATE KEY-----\\nzp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==\\n-----END ENCRYPTED PRIVATE KEY-----\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/manifest.json new file mode 100644 index 0000000000000..d9169bdd3036e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/manifest.json @@ -0,0 +1,804 @@ +{ + "version": "48.0.0", + "artifacts": { + "lambda-event-source-self-managed-kafka-dlq.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "lambda-event-source-self-managed-kafka-dlq.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "lambda-event-source-self-managed-kafka-dlq": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "lambda-event-source-self-managed-kafka-dlq.template.json", + "terminationProtection": false, + "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}/457d39b8f4743fd62862658c4f58c720dc89747080bbaf6c68a824ea08e5e731.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "lambda-event-source-self-managed-kafka-dlq.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": [ + "lambda-event-source-self-managed-kafka-dlq.assets" + ], + "metadata": { + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "handler": "*", + "code": "*", + "runtime": "*" + } + } + ], + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole": [ + { + "type": "aws:cdk:warning", + "data": "Failed to add construct metadata for node [ServiceRole]. Reason: ValidationError: The result of fromAwsManagedPolicyName can not be used in this API [ack: @aws-cdk/core:addConstructMetadataFailed]" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SelfManagedKafkaFunctionServiceRole8B4CD784" + } + ], + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SelfManagedKafkaFunctionServiceRoleDefaultPolicy93A35EC6" + } + ], + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SelfManagedKafkaFunction79CF5C6C" + } + ], + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/KafkaEventSource:99e655d80fe5967cadc6359fb2218a33:self-managed-test-topic": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "target": "*", + "filters": "*", + "filterEncryption": "*", + "kafkaBootstrapServers": "*", + "kafkaTopic": "*", + "kafkaConsumerGroupId": "*", + "startingPosition": "TRIM_HORIZON", + "startingPositionTimestamp": "*", + "sourceAccessConfigurations": [ + { + "type": "*", + "uri": "*" + }, + { + "type": "*", + "uri": "*" + } + ], + "onFailure": "*", + "supportS3OnFailureDestination": true, + "provisionedPollerConfig": { + "minimumPollers": "*", + "maximumPollers": "*" + }, + "schemaRegistryConfig": "*", + "batchSize": "*", + "bisectBatchOnError": "*", + "reportBatchItemFailures": "*", + "maxBatchingWindow": "*", + "maxRecordAge": "*", + "retryAttempts": "*", + "parallelizationFactor": "*", + "tumblingWindow": "*", + "enabled": "*" + } + } + ], + "/lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/KafkaEventSource:99e655d80fe5967cadc6359fb2218a33:self-managed-test-topic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SelfManagedKafkaFunctionKafkaEventSource99e655d80fe5967cadc6359fb2218a33selfmanagedtesttopic9AE37B25" + } + ], + "/lambda-event-source-self-managed-kafka-dlq/RootCASecret": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "secretObjectValue": "*" + } + } + ], + "/lambda-event-source-self-managed-kafka-dlq/RootCASecret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "RootCASecret21632BB9" + } + ], + "/lambda-event-source-self-managed-kafka-dlq/ClientCertSecret": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "secretObjectValue": "*" + } + } + ], + "/lambda-event-source-self-managed-kafka-dlq/ClientCertSecret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClientCertSecret84224011" + } + ], + "/lambda-event-source-self-managed-kafka-dlq/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/lambda-event-source-self-managed-kafka-dlq/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "lambda-event-source-self-managed-kafka-dlq" + }, + "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.template.json", + "terminationProtection": false, + "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": [ + "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.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": [ + "LambdaEventSourceKafkaDlqTestDefaultTestDeployAssert0E9E64FD.assets" + ], + "metadata": { + "/LambdaEventSourceKafkaDlqTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/LambdaEventSourceKafkaDlqTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "LambdaEventSourceKafkaDlqTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-lib/feature-flag-report": { + "type": "cdk:feature-flag-report", + "properties": { + "module": "aws-cdk-lib", + "flags": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": { + "userValue": true, + "recommendedValue": true, + "explanation": "Pass signingProfileName to CfnSigningProfile" + }, + "@aws-cdk/core:newStyleStackSynthesis": { + "recommendedValue": true, + "explanation": "Switch to new stack synthesis method which enables CI/CD", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:stackRelativeExports": { + "recommendedValue": true, + "explanation": "Name exports based on the construct paths relative to the stack, rather than the global construct path", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": { + "userValue": true, + "recommendedValue": true, + "explanation": "Disable implicit openListener when custom security groups are provided" + }, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": { + "recommendedValue": true, + "explanation": "Force lowercasing of RDS Cluster names in CDK", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": { + "recommendedValue": true, + "explanation": "Allow adding/removing multiple UsagePlanKeys independently", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeVersionProps": { + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeLayerVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`." + }, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": { + "recommendedValue": true, + "explanation": "Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:checkSecretUsage": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations" + }, + "@aws-cdk/core:target-partitions": { + "recommendedValue": [ + "aws", + "aws-cn" + ], + "explanation": "What regions to include in lookup tables of environment agnostic stacks" + }, + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": { + "userValue": true, + "recommendedValue": true, + "explanation": "ECS extensions will automatically add an `awslogs` driver if no logging is specified" + }, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names." + }, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": { + "userValue": true, + "recommendedValue": true, + "explanation": "ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID." + }, + "@aws-cdk/aws-iam:minimizePolicies": { + "userValue": true, + "recommendedValue": true, + "explanation": "Minimize IAM policies by combining Statements" + }, + "@aws-cdk/core:validateSnapshotRemovalPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Error on snapshot removal policies on resources that do not support it." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate key aliases that include the stack name" + }, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist." + }, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict KMS key policy for encrypted Queues a bit more" + }, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make default CloudWatch Role behavior safe for multiple API Gateways in one environment" + }, + "@aws-cdk/core:enablePartitionLiterals": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make ARNs concrete if AWS partition is known" + }, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": { + "userValue": true, + "recommendedValue": true, + "explanation": "Event Rules may only push to encrypted SQS queues in the same account" + }, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": { + "userValue": true, + "recommendedValue": true, + "explanation": "Avoid setting the \"ECS\" deployment controller when adding a circuit breaker" + }, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature to create default policy names for imported roles that depend on the stack the role is in." + }, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use S3 Bucket Policy instead of ACLs for Server Access Logging" + }, + "@aws-cdk/aws-route53-patters:useCertificate": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use the official `Certificate` resource instead of `DnsValidatedCertificate`" + }, + "@aws-cdk/customresources:installLatestAwsSdkDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "Whether to install the latest SDK by default in AwsCustomResource" + }, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use unique resource name for Database Proxy" + }, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Remove CloudWatch alarms from deployment group" + }, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include authorizer configuration in the calculation of the API deployment logical ID." + }, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": { + "userValue": true, + "recommendedValue": true, + "explanation": "Define user data for a launch template by default when a machine image is provided." + }, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": { + "userValue": true, + "recommendedValue": true, + "explanation": "SecretTargetAttachments uses the ResourcePolicy of the attached Secret." + }, + "@aws-cdk/aws-redshift:columnId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Whether to use an ID to track Redshift column changes" + }, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable AmazonEMRServicePolicy_v2 managed policies" + }, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict access to the VPC default security group" + }, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a unique id for each RequestValidator added to a method" + }, + "@aws-cdk/aws-kms:aliasNameRef": { + "userValue": true, + "recommendedValue": true, + "explanation": "KMS Alias name and keyArn will have implicit reference to KMS Key" + }, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable grant methods on Aliases imported by name to use kms:ResourceAliases condition" + }, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a launch template when creating an AutoScalingGroup" + }, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include the stack prefix in the stack name generation process" + }, + "@aws-cdk/aws-efs:denyAnonymousAccess": { + "userValue": true, + "recommendedValue": true, + "explanation": "EFS denies anonymous clients accesses" + }, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables support for Multi-AZ with Standby deployment for opensearch domains" + }, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables aws-lambda-nodejs.Function to use the latest available NodeJs runtime as the default" + }, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, mount targets will have a stable logicalId that is linked to the associated subnet." + }, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a scope of InstanceParameterGroup for AuroraClusterInstance with each parameters will change." + }, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, will always use the arn for identifiers for CfnSourceApiAssociation in the GraphqlApi construct rather than id." + }, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, creating an RDS database cluster from a snapshot will only render credentials for snapshot credentials." + }, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the CodeCommit source action is using the default branch name 'main'." + }, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the logical ID of a Lambda permission for a Lambda action includes an alarm ID." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default value for crossAccountKeys to false." + }, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default pipeline type to V2." + }, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, IAM Policy created from KMS key grant will reduce the resource scope to this key only." + }, + "@aws-cdk/pipelines:reduceAssetRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from PipelineAssetsFileRole trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-eks:nodegroupNameAttribute": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, nodegroupName attribute of the provisioned EKS NodeGroup will not have the cluster name prefix." + }, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default volume type of the EBS volume will be GP3" + }, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, remove default deployment alarm settings" + }, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default" + }, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack." + }, + "@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": { + "recommendedValue": true, + "explanation": "When enabled, use new props for S3 URI field in task definition of state machine for bedrock invoke model.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:explicitStackTags": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, stack tags need to be assigned explicitly on a Stack." + }, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": { + "userValue": false, + "recommendedValue": false, + "explanation": "When set to true along with canContainersAccessInstanceRole=false in ECS cluster, new updated commands will be added to UserData to block container accessing IMDS. **Applicable to Linux only. IMPORTANT: See [details.](#aws-cdkaws-ecsenableImdsBlockingDeprecatedFeature)**" + }, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, CDK synth will throw exception if canContainersAccessInstanceRole is false. **IMPORTANT: See [details.](#aws-cdkaws-ecsdisableEcsImdsBlocking)**" + }, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, we will only grant the necessary permissions when users specify cloudwatch log group through logConfiguration" + }, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled will allow you to specify a resource policy per replica, and not copy the source table policy to all replicas" + }, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, initOptions.timeout and resourceSignalTimeout values will be summed together." + }, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a Lambda authorizer Permission created when using GraphqlApi will be properly scoped with a SourceArn." + }, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the value of property `instanceResourceId` in construct `DatabaseInstanceReadReplica` will be set to the correct value which is `DbiResourceId` instead of currently `DbInstanceArn`" + }, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CFN templates added with `cfn-include` will error if the template contains Resource Update or Create policies with CFN Intrinsics that include non-primitive values." + }, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, both `@aws-sdk` and `@smithy` packages will be excluded from the Lambda Node.js 18.x runtime to prevent version mismatches in bundled applications." + }, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resource of IAM Run Ecs policy generated by SFN EcsRunTask will reference the definition, instead of constructing ARN." + }, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the BastionHost construct will use the latest Amazon Linux 2023 AMI, instead of Amazon Linux 2." + }, + "@aws-cdk/core:aspectStabilization": { + "recommendedValue": true, + "explanation": "When enabled, a stabilization loop will be run when invoking Aspects during synthesis.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, use a new method for DNS Name of user pool domain target without creating a custom resource." + }, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default security group ingress rules will allow IPv6 ingress from anywhere" + }, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default behaviour of OIDC provider will reject unauthorized connections" + }, + "@aws-cdk/core:enableAdditionalMetadataCollection": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will expand the scope of usage data collected to better inform CDK development and improve communication for security concerns and emerging issues." + }, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": { + "userValue": false, + "recommendedValue": false, + "explanation": "[Deprecated] When enabled, Lambda will create new inline policies with AddToRolePolicy instead of adding to the Default Policy Statement" + }, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will automatically generate a unique role name that is used for s3 object replication." + }, + "@aws-cdk/pipelines:reduceStageRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from Stage addActions trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-events:requireEventBusPolicySid": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, grantPutEventsTo() will use resource policies with Statement IDs for service principals." + }, + "@aws-cdk/core:aspectPrioritiesMutating": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, Aspects added by the construct library on your behalf will be given a priority of MUTATING." + }, + "@aws-cdk/aws-dynamodb:retainTableReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, table replica will be default to the removal policy of source table unless specified otherwise." + }, + "@aws-cdk/cognito:logUserPoolClientSecretValue": { + "recommendedValue": false, + "explanation": "When disabled, the value of the user pool client secret will not be logged in the custom resource lambda function logs." + }, + "@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": { + "recommendedValue": true, + "explanation": "When enabled, scopes down the trust policy for the cross-account action role", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resultWriterV2 property of DistributedMap will be used insted of resultWriter" + }, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": { + "userValue": true, + "recommendedValue": true, + "explanation": "Add an S3 trust policy to a KMS key resource policy for SNS subscriptions." + }, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the EgressOnlyGateway resource is only created if private subnets are defined in the dual-stack VPC." + }, + "@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": { + "recommendedValue": false, + "explanation": "When enabled, use resource IDs for VPC V2 migration" + }, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, setting any combination of options for BlockPublicAccess will automatically set true for any options not defined." + }, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": { + "userValue": false, + "recommendedValue": true, + "explanation": "When enabled, CDK creates and manages loggroup for the lambda function" + }, + "@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault": { + "recommendedValue": true, + "explanation": "When enabled, Network Load Balancer will be created with a security group by default." + }, + "@aws-cdk/aws-stepfunctions-tasks:httpInvokeDynamicJsonPathEndpoint": { + "recommendedValue": true, + "explanation": "When enabled, allows using a dynamic apiEndpoint with JSONPath format in HttpInvoke tasks.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-ecs-patterns:uniqueTargetGroupId": { + "recommendedValue": true, + "explanation": "When enabled, ECS patterns will generate unique target group IDs to prevent conflicts during load balancer replacement" + } + } + } + } + }, + "minimumCliVersion": "2.1031.2" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/tree.json new file mode 100644 index 0000000000000..fb8da642519ce --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"lambda-event-source-self-managed-kafka-dlq":{"id":"lambda-event-source-self-managed-kafka-dlq","path":"lambda-event-source-self-managed-kafka-dlq","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"SelfManagedKafkaFunction":{"id":"SelfManagedKafkaFunction","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"handler":"*","code":"*","runtime":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:DescribeSecret","secretsmanager:GetSecretValue"],"Effect":"Allow","Resource":[{"Ref":"ClientCertSecret84224011"},{"Ref":"RootCASecret21632BB9"}]}],"Version":"2012-10-17"},"policyName":"SelfManagedKafkaFunctionServiceRoleDefaultPolicy93A35EC6","roles":[{"Ref":"SelfManagedKafkaFunctionServiceRole8B4CD784"}]}}}}}}},"Resource":{"id":"Resource","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}"},"handler":"index.handler","role":{"Fn::GetAtt":["SelfManagedKafkaFunctionServiceRole8B4CD784","Arn"]},"runtime":"nodejs18.x"}}},"KafkaEventSource:99e655d80fe5967cadc6359fb2218a33:self-managed-test-topic":{"id":"KafkaEventSource:99e655d80fe5967cadc6359fb2218a33:self-managed-test-topic","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/KafkaEventSource:99e655d80fe5967cadc6359fb2218a33:self-managed-test-topic","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.EventSourceMapping","version":"0.0.0","metadata":[{"target":"*","filters":"*","filterEncryption":"*","kafkaBootstrapServers":"*","kafkaTopic":"*","kafkaConsumerGroupId":"*","startingPosition":"TRIM_HORIZON","startingPositionTimestamp":"*","sourceAccessConfigurations":[{"type":"*","uri":"*"},{"type":"*","uri":"*"}],"onFailure":"*","supportS3OnFailureDestination":true,"provisionedPollerConfig":{"minimumPollers":"*","maximumPollers":"*"},"schemaRegistryConfig":"*","batchSize":"*","bisectBatchOnError":"*","reportBatchItemFailures":"*","maxBatchingWindow":"*","maxRecordAge":"*","retryAttempts":"*","parallelizationFactor":"*","tumblingWindow":"*","enabled":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-self-managed-kafka-dlq/SelfManagedKafkaFunction/KafkaEventSource:99e655d80fe5967cadc6359fb2218a33:self-managed-test-topic/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnEventSourceMapping","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::EventSourceMapping","aws:cdk:cloudformation:props":{"batchSize":100,"destinationConfig":{"onFailure":{"destination":"kafka://self-managed-kafka-failure-topic"}},"functionName":{"Ref":"SelfManagedKafkaFunction79CF5C6C"},"provisionedPollerConfig":{"minimumPollers":1,"maximumPollers":1},"selfManagedEventSource":{"endpoints":{"kafkaBootstrapServers":["self-managed-kafka-broker-1:9092","self-managed-kafka-broker-2:9092","self-managed-kafka-broker-3:9092"]}},"selfManagedKafkaEventSourceConfig":{"consumerGroupId":"self-managed-test-consumer-group"},"sourceAccessConfigurations":[{"type":"CLIENT_CERTIFICATE_TLS_AUTH","uri":{"Ref":"ClientCertSecret84224011"}},{"type":"SERVER_ROOT_CA_CERTIFICATE","uri":{"Ref":"RootCASecret21632BB9"}}],"startingPosition":"TRIM_HORIZON","topics":["self-managed-test-topic"]}}}}}}},"RootCASecret":{"id":"RootCASecret","path":"lambda-event-source-self-managed-kafka-dlq/RootCASecret","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.Secret","version":"0.0.0","metadata":[{"secretObjectValue":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-self-managed-kafka-dlq/RootCASecret/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.CfnSecret","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::SecretsManager::Secret","aws:cdk:cloudformation:props":{"secretString":"{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuaAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\"}"}}}}},"ClientCertSecret":{"id":"ClientCertSecret","path":"lambda-event-source-self-managed-kafka-dlq/ClientCertSecret","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.Secret","version":"0.0.0","metadata":[{"secretObjectValue":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-self-managed-kafka-dlq/ClientCertSecret/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.CfnSecret","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::SecretsManager::Secret","aws:cdk:cloudformation:props":{"secretString":"{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuaAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\",\"privateKey\":\"-----BEGIN ENCRYPTED PRIVATE KEY-----\\nzp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==\\n-----END ENCRYPTED PRIVATE KEY-----\"}"}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"lambda-event-source-self-managed-kafka-dlq/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"lambda-event-source-self-managed-kafka-dlq/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"LambdaEventSourceKafkaDlqTest":{"id":"LambdaEventSourceKafkaDlqTest","path":"LambdaEventSourceKafkaDlqTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"LambdaEventSourceKafkaDlqTest/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"LambdaEventSourceKafkaDlqTest/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"LambdaEventSourceKafkaDlqTest/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"LambdaEventSourceKafkaDlqTest/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"LambdaEventSourceKafkaDlqTest/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.ts new file mode 100644 index 0000000000000..de33f55d2338d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-dlq.ts @@ -0,0 +1,92 @@ +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'; +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import { TestFunction } from './test-function'; +import { + AuthenticationMethod, + SelfManagedKafkaEventSource, + KafkaDlq, +} from 'aws-cdk-lib/aws-lambda-event-sources'; + +/** + * Integration test stack for SelfManagedKafka with KafkaDlq destination + */ +class SelfManagedKafkaWithKafkaDlqStack extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const dummyCertString = `-----BEGIN CERTIFICATE----- +MIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw +cmUuaAii9R0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb +c8PH3PSoAaRwMMgOSA2ALJvbRz8mpg== +-----END CERTIFICATE-----`; + + const dummyPrivateKey = `-----BEGIN ENCRYPTED PRIVATE KEY----- +zp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA== +-----END ENCRYPTED PRIVATE KEY-----`; + + const fn = new TestFunction(this, 'SelfManagedKafkaFunction'); + + const rootCASecret = new secretsmanager.Secret(this, 'RootCASecret', { + secretObjectValue: { + certificate: cdk.SecretValue.unsafePlainText(dummyCertString), + }, + }); + + const clientCertificatesSecret = new secretsmanager.Secret(this, 'ClientCertSecret', { + secretObjectValue: { + certificate: cdk.SecretValue.unsafePlainText(dummyCertString), + privateKey: cdk.SecretValue.unsafePlainText(dummyPrivateKey), + }, + }); + + rootCASecret.grantRead(fn); + clientCertificatesSecret.grantRead(fn); + + const bootstrapServers = [ + 'self-managed-kafka-broker-1:9092', + 'self-managed-kafka-broker-2:9092', + 'self-managed-kafka-broker-3:9092', + ]; + + // Create KafkaDlq destination + const kafkaDlq = new KafkaDlq('self-managed-kafka-failure-topic'); + + // Add SelfManagedKafka event source with KafkaDlq destination + fn.addEventSource(new SelfManagedKafkaEventSource({ + bootstrapServers, + topic: 'self-managed-test-topic', + consumerGroupId: 'self-managed-test-consumer-group', + secret: clientCertificatesSecret, + authenticationMethod: AuthenticationMethod.CLIENT_CERTIFICATE_TLS_AUTH, + rootCACertificate: rootCASecret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 1, + }, + })); + } +} + +const app = new cdk.App({ + postCliContext: { + '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false, + }, +}); + +const selfManagedKafkaStack = new SelfManagedKafkaWithKafkaDlqStack( + app, + 'lambda-event-source-self-managed-kafka-dlq', +); + +new integ.IntegTest(app, 'LambdaEventSourceKafkaDlqTest', { + testCases: [selfManagedKafkaStack], +}); + +app.synth(); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.assets.json new file mode 100644 index 0000000000000..97c6f842df029 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A Template", + "source": { + "path": "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-d8d86b35": { + "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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/cdk.out new file mode 100644 index 0000000000000..523a9aac37cbf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"48.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/integ.json new file mode 100644 index 0000000000000..34fa431d8bb96 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "48.0.0", + "testCases": { + "LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest": { + "stacks": [ + "lambda-event-source-kafka-poller-group-name" + ], + "assertionStack": "LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest/DeployAssert", + "assertionStackName": "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A" + } + }, + "minimumCliVersion": "2.1027.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/lambda-event-source-kafka-poller-group-name.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/lambda-event-source-kafka-poller-group-name.assets.json new file mode 100644 index 0000000000000..67b94d4e747eb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/lambda-event-source-kafka-poller-group-name.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "ac34b1bd2925039e18b6b7d53e3c3735bd06babcd38d102d92ec2270b3469bb9": { + "displayName": "lambda-event-source-kafka-poller-group-name Template", + "source": { + "path": "lambda-event-source-kafka-poller-group-name.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-579bad8a": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "ac34b1bd2925039e18b6b7d53e3c3735bd06babcd38d102d92ec2270b3469bb9.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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/lambda-event-source-kafka-poller-group-name.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/lambda-event-source-kafka-poller-group-name.template.json new file mode 100644 index 0000000000000..5ae5686f15b4d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/lambda-event-source-kafka-poller-group-name.template.json @@ -0,0 +1,180 @@ +{ + "Resources": { + "SelfManagedFunctionServiceRoleE09BE638": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "SelfManagedFunctionServiceRoleDefaultPolicyE4544C2E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": [ + { + "Ref": "ClientCertSecret84224011" + }, + { + "Ref": "RootCASecret21632BB9" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SelfManagedFunctionServiceRoleDefaultPolicyE4544C2E", + "Roles": [ + { + "Ref": "SelfManagedFunctionServiceRoleE09BE638" + } + ] + } + }, + "SelfManagedFunctionCD01B313": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SelfManagedFunctionServiceRoleE09BE638", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "SelfManagedFunctionServiceRoleDefaultPolicyE4544C2E", + "SelfManagedFunctionServiceRoleE09BE638" + ] + }, + "SelfManagedFunctionKafkaEventSource838c4d5ff3c99c1a617120adfca83e5bmytesttopicwithpollergroup255B39D4": { + "Type": "AWS::Lambda::EventSourceMapping", + "Properties": { + "BatchSize": 100, + "FunctionName": { + "Ref": "SelfManagedFunctionCD01B313" + }, + "ProvisionedPollerConfig": { + "MaximumPollers": 3, + "MinimumPollers": 1, + "PollerGroupName": "test-poller-group-self-managed" + }, + "SelfManagedEventSource": { + "Endpoints": { + "KafkaBootstrapServers": [ + "my-self-hosted-kafka-broker-1:9092", + "my-self-hosted-kafka-broker-2:9092", + "my-self-hosted-kafka-broker-3:9092" + ] + } + }, + "SelfManagedKafkaEventSourceConfig": { + "ConsumerGroupId": "myTestConsumerGroupWithPollerGroup" + }, + "SourceAccessConfigurations": [ + { + "Type": "CLIENT_CERTIFICATE_TLS_AUTH", + "URI": { + "Ref": "ClientCertSecret84224011" + } + }, + { + "Type": "SERVER_ROOT_CA_CERTIFICATE", + "URI": { + "Ref": "RootCASecret21632BB9" + } + } + ], + "StartingPosition": "TRIM_HORIZON", + "Topics": [ + "my-test-topic-with-poller-group" + ] + } + }, + "RootCASecret21632BB9": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "SecretString": "{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuaAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\\\"\\n\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClientCertSecret84224011": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "SecretString": "{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuaAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\\\"\\n\",\"privateKey\":\"-----BEGIN ENCRYPTED PRIVATE KEY-----\\nzp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==\\n-----END ENCRYPTED PRIVATE KEY-----\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/manifest.json new file mode 100644 index 0000000000000..607c64757ad26 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/manifest.json @@ -0,0 +1,804 @@ +{ + "version": "48.0.0", + "artifacts": { + "lambda-event-source-kafka-poller-group-name.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "lambda-event-source-kafka-poller-group-name.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "lambda-event-source-kafka-poller-group-name": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "lambda-event-source-kafka-poller-group-name.template.json", + "terminationProtection": false, + "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}/ac34b1bd2925039e18b6b7d53e3c3735bd06babcd38d102d92ec2270b3469bb9.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "lambda-event-source-kafka-poller-group-name.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": [ + "lambda-event-source-kafka-poller-group-name.assets" + ], + "metadata": { + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "handler": "*", + "code": "*", + "runtime": "*" + } + } + ], + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole": [ + { + "type": "aws:cdk:warning", + "data": "Failed to add construct metadata for node [ServiceRole]. Reason: ValidationError: The result of fromAwsManagedPolicyName can not be used in this API [ack: @aws-cdk/core:addConstructMetadataFailed]" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SelfManagedFunctionServiceRoleE09BE638" + } + ], + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SelfManagedFunctionServiceRoleDefaultPolicyE4544C2E" + } + ], + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SelfManagedFunctionCD01B313" + } + ], + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction/KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:my-test-topic-with-poller-group": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "target": "*", + "filters": "*", + "filterEncryption": "*", + "kafkaBootstrapServers": "*", + "kafkaTopic": "*", + "kafkaConsumerGroupId": "*", + "startingPosition": "TRIM_HORIZON", + "startingPositionTimestamp": "*", + "sourceAccessConfigurations": [ + { + "type": "*", + "uri": "*" + }, + { + "type": "*", + "uri": "*" + } + ], + "onFailure": "*", + "supportS3OnFailureDestination": true, + "provisionedPollerConfig": { + "minimumPollers": "*", + "maximumPollers": "*" + }, + "schemaRegistryConfig": "*", + "batchSize": "*", + "bisectBatchOnError": "*", + "reportBatchItemFailures": "*", + "maxBatchingWindow": "*", + "maxRecordAge": "*", + "retryAttempts": "*", + "parallelizationFactor": "*", + "tumblingWindow": "*", + "enabled": "*" + } + } + ], + "/lambda-event-source-kafka-poller-group-name/SelfManagedFunction/KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:my-test-topic-with-poller-group/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SelfManagedFunctionKafkaEventSource838c4d5ff3c99c1a617120adfca83e5bmytesttopicwithpollergroup255B39D4" + } + ], + "/lambda-event-source-kafka-poller-group-name/RootCASecret": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "secretObjectValue": "*" + } + } + ], + "/lambda-event-source-kafka-poller-group-name/RootCASecret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "RootCASecret21632BB9" + } + ], + "/lambda-event-source-kafka-poller-group-name/ClientCertSecret": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "secretObjectValue": "*" + } + } + ], + "/lambda-event-source-kafka-poller-group-name/ClientCertSecret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClientCertSecret84224011" + } + ], + "/lambda-event-source-kafka-poller-group-name/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/lambda-event-source-kafka-poller-group-name/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "lambda-event-source-kafka-poller-group-name" + }, + "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.template.json", + "terminationProtection": false, + "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": [ + "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.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": [ + "LambdaEventSourceKafkaPollerGroupNameTestDefaultTestDeployAssertF412EA4A.assets" + ], + "metadata": { + "/LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-lib/feature-flag-report": { + "type": "cdk:feature-flag-report", + "properties": { + "module": "aws-cdk-lib", + "flags": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": { + "userValue": true, + "recommendedValue": true, + "explanation": "Pass signingProfileName to CfnSigningProfile" + }, + "@aws-cdk/core:newStyleStackSynthesis": { + "recommendedValue": true, + "explanation": "Switch to new stack synthesis method which enables CI/CD", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:stackRelativeExports": { + "recommendedValue": true, + "explanation": "Name exports based on the construct paths relative to the stack, rather than the global construct path", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": { + "userValue": true, + "recommendedValue": true, + "explanation": "Disable implicit openListener when custom security groups are provided" + }, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": { + "recommendedValue": true, + "explanation": "Force lowercasing of RDS Cluster names in CDK", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": { + "recommendedValue": true, + "explanation": "Allow adding/removing multiple UsagePlanKeys independently", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeVersionProps": { + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeLayerVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`." + }, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": { + "recommendedValue": true, + "explanation": "Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:checkSecretUsage": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations" + }, + "@aws-cdk/core:target-partitions": { + "recommendedValue": [ + "aws", + "aws-cn" + ], + "explanation": "What regions to include in lookup tables of environment agnostic stacks" + }, + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": { + "userValue": true, + "recommendedValue": true, + "explanation": "ECS extensions will automatically add an `awslogs` driver if no logging is specified" + }, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names." + }, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": { + "userValue": true, + "recommendedValue": true, + "explanation": "ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID." + }, + "@aws-cdk/aws-iam:minimizePolicies": { + "userValue": true, + "recommendedValue": true, + "explanation": "Minimize IAM policies by combining Statements" + }, + "@aws-cdk/core:validateSnapshotRemovalPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Error on snapshot removal policies on resources that do not support it." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate key aliases that include the stack name" + }, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist." + }, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict KMS key policy for encrypted Queues a bit more" + }, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make default CloudWatch Role behavior safe for multiple API Gateways in one environment" + }, + "@aws-cdk/core:enablePartitionLiterals": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make ARNs concrete if AWS partition is known" + }, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": { + "userValue": true, + "recommendedValue": true, + "explanation": "Event Rules may only push to encrypted SQS queues in the same account" + }, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": { + "userValue": true, + "recommendedValue": true, + "explanation": "Avoid setting the \"ECS\" deployment controller when adding a circuit breaker" + }, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature to create default policy names for imported roles that depend on the stack the role is in." + }, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use S3 Bucket Policy instead of ACLs for Server Access Logging" + }, + "@aws-cdk/aws-route53-patters:useCertificate": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use the official `Certificate` resource instead of `DnsValidatedCertificate`" + }, + "@aws-cdk/customresources:installLatestAwsSdkDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "Whether to install the latest SDK by default in AwsCustomResource" + }, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use unique resource name for Database Proxy" + }, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Remove CloudWatch alarms from deployment group" + }, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include authorizer configuration in the calculation of the API deployment logical ID." + }, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": { + "userValue": true, + "recommendedValue": true, + "explanation": "Define user data for a launch template by default when a machine image is provided." + }, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": { + "userValue": true, + "recommendedValue": true, + "explanation": "SecretTargetAttachments uses the ResourcePolicy of the attached Secret." + }, + "@aws-cdk/aws-redshift:columnId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Whether to use an ID to track Redshift column changes" + }, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable AmazonEMRServicePolicy_v2 managed policies" + }, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict access to the VPC default security group" + }, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a unique id for each RequestValidator added to a method" + }, + "@aws-cdk/aws-kms:aliasNameRef": { + "userValue": true, + "recommendedValue": true, + "explanation": "KMS Alias name and keyArn will have implicit reference to KMS Key" + }, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable grant methods on Aliases imported by name to use kms:ResourceAliases condition" + }, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a launch template when creating an AutoScalingGroup" + }, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include the stack prefix in the stack name generation process" + }, + "@aws-cdk/aws-efs:denyAnonymousAccess": { + "userValue": true, + "recommendedValue": true, + "explanation": "EFS denies anonymous clients accesses" + }, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables support for Multi-AZ with Standby deployment for opensearch domains" + }, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables aws-lambda-nodejs.Function to use the latest available NodeJs runtime as the default" + }, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, mount targets will have a stable logicalId that is linked to the associated subnet." + }, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a scope of InstanceParameterGroup for AuroraClusterInstance with each parameters will change." + }, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, will always use the arn for identifiers for CfnSourceApiAssociation in the GraphqlApi construct rather than id." + }, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, creating an RDS database cluster from a snapshot will only render credentials for snapshot credentials." + }, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the CodeCommit source action is using the default branch name 'main'." + }, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the logical ID of a Lambda permission for a Lambda action includes an alarm ID." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default value for crossAccountKeys to false." + }, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default pipeline type to V2." + }, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, IAM Policy created from KMS key grant will reduce the resource scope to this key only." + }, + "@aws-cdk/pipelines:reduceAssetRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from PipelineAssetsFileRole trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-eks:nodegroupNameAttribute": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, nodegroupName attribute of the provisioned EKS NodeGroup will not have the cluster name prefix." + }, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default volume type of the EBS volume will be GP3" + }, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, remove default deployment alarm settings" + }, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default" + }, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack." + }, + "@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": { + "recommendedValue": true, + "explanation": "When enabled, use new props for S3 URI field in task definition of state machine for bedrock invoke model.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:explicitStackTags": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, stack tags need to be assigned explicitly on a Stack." + }, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": { + "userValue": false, + "recommendedValue": false, + "explanation": "When set to true along with canContainersAccessInstanceRole=false in ECS cluster, new updated commands will be added to UserData to block container accessing IMDS. **Applicable to Linux only. IMPORTANT: See [details.](#aws-cdkaws-ecsenableImdsBlockingDeprecatedFeature)**" + }, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, CDK synth will throw exception if canContainersAccessInstanceRole is false. **IMPORTANT: See [details.](#aws-cdkaws-ecsdisableEcsImdsBlocking)**" + }, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, we will only grant the necessary permissions when users specify cloudwatch log group through logConfiguration" + }, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled will allow you to specify a resource policy per replica, and not copy the source table policy to all replicas" + }, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, initOptions.timeout and resourceSignalTimeout values will be summed together." + }, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a Lambda authorizer Permission created when using GraphqlApi will be properly scoped with a SourceArn." + }, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the value of property `instanceResourceId` in construct `DatabaseInstanceReadReplica` will be set to the correct value which is `DbiResourceId` instead of currently `DbInstanceArn`" + }, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CFN templates added with `cfn-include` will error if the template contains Resource Update or Create policies with CFN Intrinsics that include non-primitive values." + }, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, both `@aws-sdk` and `@smithy` packages will be excluded from the Lambda Node.js 18.x runtime to prevent version mismatches in bundled applications." + }, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resource of IAM Run Ecs policy generated by SFN EcsRunTask will reference the definition, instead of constructing ARN." + }, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the BastionHost construct will use the latest Amazon Linux 2023 AMI, instead of Amazon Linux 2." + }, + "@aws-cdk/core:aspectStabilization": { + "recommendedValue": true, + "explanation": "When enabled, a stabilization loop will be run when invoking Aspects during synthesis.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, use a new method for DNS Name of user pool domain target without creating a custom resource." + }, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default security group ingress rules will allow IPv6 ingress from anywhere" + }, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default behaviour of OIDC provider will reject unauthorized connections" + }, + "@aws-cdk/core:enableAdditionalMetadataCollection": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will expand the scope of usage data collected to better inform CDK development and improve communication for security concerns and emerging issues." + }, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": { + "userValue": false, + "recommendedValue": false, + "explanation": "[Deprecated] When enabled, Lambda will create new inline policies with AddToRolePolicy instead of adding to the Default Policy Statement" + }, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will automatically generate a unique role name that is used for s3 object replication." + }, + "@aws-cdk/pipelines:reduceStageRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from Stage addActions trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-events:requireEventBusPolicySid": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, grantPutEventsTo() will use resource policies with Statement IDs for service principals." + }, + "@aws-cdk/core:aspectPrioritiesMutating": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, Aspects added by the construct library on your behalf will be given a priority of MUTATING." + }, + "@aws-cdk/aws-dynamodb:retainTableReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, table replica will be default to the removal policy of source table unless specified otherwise." + }, + "@aws-cdk/cognito:logUserPoolClientSecretValue": { + "recommendedValue": false, + "explanation": "When disabled, the value of the user pool client secret will not be logged in the custom resource lambda function logs." + }, + "@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": { + "recommendedValue": true, + "explanation": "When enabled, scopes down the trust policy for the cross-account action role", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resultWriterV2 property of DistributedMap will be used insted of resultWriter" + }, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": { + "userValue": true, + "recommendedValue": true, + "explanation": "Add an S3 trust policy to a KMS key resource policy for SNS subscriptions." + }, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the EgressOnlyGateway resource is only created if private subnets are defined in the dual-stack VPC." + }, + "@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": { + "recommendedValue": false, + "explanation": "When enabled, use resource IDs for VPC V2 migration" + }, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, setting any combination of options for BlockPublicAccess will automatically set true for any options not defined." + }, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": { + "userValue": false, + "recommendedValue": true, + "explanation": "When enabled, CDK creates and manages loggroup for the lambda function" + }, + "@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault": { + "recommendedValue": true, + "explanation": "When enabled, Network Load Balancer will be created with a security group by default." + }, + "@aws-cdk/aws-stepfunctions-tasks:httpInvokeDynamicJsonPathEndpoint": { + "recommendedValue": true, + "explanation": "When enabled, allows using a dynamic apiEndpoint with JSONPath format in HttpInvoke tasks.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-ecs-patterns:uniqueTargetGroupId": { + "recommendedValue": true, + "explanation": "When enabled, ECS patterns will generate unique target group IDs to prevent conflicts during load balancer replacement" + } + } + } + } + }, + "minimumCliVersion": "2.1031.2" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/tree.json new file mode 100644 index 0000000000000..395542df2b77d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"lambda-event-source-kafka-poller-group-name":{"id":"lambda-event-source-kafka-poller-group-name","path":"lambda-event-source-kafka-poller-group-name","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"SelfManagedFunction":{"id":"SelfManagedFunction","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"handler":"*","code":"*","runtime":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:DescribeSecret","secretsmanager:GetSecretValue"],"Effect":"Allow","Resource":[{"Ref":"ClientCertSecret84224011"},{"Ref":"RootCASecret21632BB9"}]}],"Version":"2012-10-17"},"policyName":"SelfManagedFunctionServiceRoleDefaultPolicyE4544C2E","roles":[{"Ref":"SelfManagedFunctionServiceRoleE09BE638"}]}}}}}}},"Resource":{"id":"Resource","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}"},"handler":"index.handler","role":{"Fn::GetAtt":["SelfManagedFunctionServiceRoleE09BE638","Arn"]},"runtime":"nodejs18.x"}}},"KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:my-test-topic-with-poller-group":{"id":"KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:my-test-topic-with-poller-group","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction/KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:my-test-topic-with-poller-group","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.EventSourceMapping","version":"0.0.0","metadata":[{"target":"*","filters":"*","filterEncryption":"*","kafkaBootstrapServers":"*","kafkaTopic":"*","kafkaConsumerGroupId":"*","startingPosition":"TRIM_HORIZON","startingPositionTimestamp":"*","sourceAccessConfigurations":[{"type":"*","uri":"*"},{"type":"*","uri":"*"}],"onFailure":"*","supportS3OnFailureDestination":true,"provisionedPollerConfig":{"minimumPollers":"*","maximumPollers":"*"},"schemaRegistryConfig":"*","batchSize":"*","bisectBatchOnError":"*","reportBatchItemFailures":"*","maxBatchingWindow":"*","maxRecordAge":"*","retryAttempts":"*","parallelizationFactor":"*","tumblingWindow":"*","enabled":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-kafka-poller-group-name/SelfManagedFunction/KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:my-test-topic-with-poller-group/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnEventSourceMapping","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::EventSourceMapping","aws:cdk:cloudformation:props":{"batchSize":100,"functionName":{"Ref":"SelfManagedFunctionCD01B313"},"provisionedPollerConfig":{"minimumPollers":1,"maximumPollers":3,"pollerGroupName":"test-poller-group-self-managed"},"selfManagedEventSource":{"endpoints":{"kafkaBootstrapServers":["my-self-hosted-kafka-broker-1:9092","my-self-hosted-kafka-broker-2:9092","my-self-hosted-kafka-broker-3:9092"]}},"selfManagedKafkaEventSourceConfig":{"consumerGroupId":"myTestConsumerGroupWithPollerGroup"},"sourceAccessConfigurations":[{"type":"CLIENT_CERTIFICATE_TLS_AUTH","uri":{"Ref":"ClientCertSecret84224011"}},{"type":"SERVER_ROOT_CA_CERTIFICATE","uri":{"Ref":"RootCASecret21632BB9"}}],"startingPosition":"TRIM_HORIZON","topics":["my-test-topic-with-poller-group"]}}}}}}},"RootCASecret":{"id":"RootCASecret","path":"lambda-event-source-kafka-poller-group-name/RootCASecret","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.Secret","version":"0.0.0","metadata":[{"secretObjectValue":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-kafka-poller-group-name/RootCASecret/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.CfnSecret","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::SecretsManager::Secret","aws:cdk:cloudformation:props":{"secretString":"{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuaAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\\\"\\n\"}"}}}}},"ClientCertSecret":{"id":"ClientCertSecret","path":"lambda-event-source-kafka-poller-group-name/ClientCertSecret","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.Secret","version":"0.0.0","metadata":[{"secretObjectValue":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-kafka-poller-group-name/ClientCertSecret/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.CfnSecret","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::SecretsManager::Secret","aws:cdk:cloudformation:props":{"secretString":"{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuaAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\\\"\\n\",\"privateKey\":\"-----BEGIN ENCRYPTED PRIVATE KEY-----\\nzp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==\\n-----END ENCRYPTED PRIVATE KEY-----\"}"}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"lambda-event-source-kafka-poller-group-name/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"lambda-event-source-kafka-poller-group-name/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"LambdaEventSourceKafkaPollerGroupNameTest":{"id":"LambdaEventSourceKafkaPollerGroupNameTest","path":"LambdaEventSourceKafkaPollerGroupNameTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"LambdaEventSourceKafkaPollerGroupNameTest/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.ts new file mode 100644 index 0000000000000..68e55528ab9b8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-poller-group-name.ts @@ -0,0 +1,78 @@ +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'; +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import { TestFunction } from './test-function'; +import { AuthenticationMethod, SelfManagedKafkaEventSource } from 'aws-cdk-lib/aws-lambda-event-sources'; + +class KafkaPollerGroupNameTest extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const dummyCertString = `-----BEGIN CERTIFICATE----- +MIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw +cmUuaAii9R0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb +c8PH3PSoAaRwMMgOSA2ALJvbRz8mpg== +-----END CERTIFICATE-----" +`; + + const dummyPrivateKey = `-----BEGIN ENCRYPTED PRIVATE KEY----- +zp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA== +-----END ENCRYPTED PRIVATE KEY-----`; + + const fn1 = new TestFunction(this, 'SelfManagedFunction'); + const rootCASecret = new secretsmanager.Secret(this, 'RootCASecret', { + secretObjectValue: { + certificate: cdk.SecretValue.unsafePlainText(dummyCertString), + }, + }); + const clientCertificatesSecret = new secretsmanager.Secret(this, 'ClientCertSecret', { + secretObjectValue: { + certificate: cdk.SecretValue.unsafePlainText(dummyCertString), + privateKey: cdk.SecretValue.unsafePlainText(dummyPrivateKey), + }, + }); + rootCASecret.grantRead(fn1); + clientCertificatesSecret.grantRead(fn1); + + const bootstrapServers = [ + 'my-self-hosted-kafka-broker-1:9092', + 'my-self-hosted-kafka-broker-2:9092', + 'my-self-hosted-kafka-broker-3:9092', + ]; + + fn1.addEventSource( + new SelfManagedKafkaEventSource({ + bootstrapServers, + topic: 'my-test-topic-with-poller-group', + consumerGroupId: 'myTestConsumerGroupWithPollerGroup', + secret: clientCertificatesSecret, + authenticationMethod: AuthenticationMethod.CLIENT_CERTIFICATE_TLS_AUTH, + rootCACertificate: rootCASecret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 3, + pollerGroupName: 'test-poller-group-self-managed', + }, + }), + ); + } +} + +const app = new cdk.App({ + postCliContext: { + '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false, + }, +}); +const stack = new KafkaPollerGroupNameTest( + app, + 'lambda-event-source-kafka-poller-group-name', +); +new integ.IntegTest(app, 'LambdaEventSourceKafkaPollerGroupNameTest', { + testCases: [stack], +}); +app.synth(); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.assets.json new file mode 100644 index 0000000000000..651dc666221b2 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE Template", + "source": { + "path": "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-d8d86b35": { + "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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/cdk.out new file mode 100644 index 0000000000000..523a9aac37cbf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"48.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/integ.json new file mode 100644 index 0000000000000..355dd4d9189c8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "48.0.0", + "testCases": { + "LambdaEventSourceKafkaErrorHandlingTest/DefaultTest": { + "stacks": [ + "lambda-event-source-kafka-error-handling" + ], + "assertionStack": "LambdaEventSourceKafkaErrorHandlingTest/DefaultTest/DeployAssert", + "assertionStackName": "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE" + } + }, + "minimumCliVersion": "2.1027.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/lambda-event-source-kafka-error-handling.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/lambda-event-source-kafka-error-handling.assets.json new file mode 100644 index 0000000000000..0bb17829e0440 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/lambda-event-source-kafka-error-handling.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "4acaeb41811b2c95056a45ac80701a3435d93ad9db2e53f929a50bf324f89395": { + "displayName": "lambda-event-source-kafka-error-handling Template", + "source": { + "path": "lambda-event-source-kafka-error-handling.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-8d416080": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "4acaeb41811b2c95056a45ac80701a3435d93ad9db2e53f929a50bf324f89395.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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/lambda-event-source-kafka-error-handling.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/lambda-event-source-kafka-error-handling.template.json new file mode 100644 index 0000000000000..d6cd9886e13bd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/lambda-event-source-kafka-error-handling.template.json @@ -0,0 +1,185 @@ +{ + "Resources": { + "RootCASecret21632BB9": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "SecretString": "{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuiAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\\\"\\n\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClientCertSecret84224011": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "SecretString": "{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuiAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\\\"\\n\",\"privateKey\":\"-----BEGIN ENCRYPTED PRIVATE KEY-----\\nzp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==\\n-----END ENCRYPTED PRIVATE KEY-----\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ErrorHandlingFunctionServiceRole17C3A809": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "ErrorHandlingFunctionServiceRoleDefaultPolicy73BB7661": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": [ + { + "Ref": "ClientCertSecret84224011" + }, + { + "Ref": "RootCASecret21632BB9" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ErrorHandlingFunctionServiceRoleDefaultPolicy73BB7661", + "Roles": [ + { + "Ref": "ErrorHandlingFunctionServiceRole17C3A809" + } + ] + } + }, + "ErrorHandlingFunctionC7AA2D94": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "ErrorHandlingFunctionServiceRole17C3A809", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "ErrorHandlingFunctionServiceRoleDefaultPolicy73BB7661", + "ErrorHandlingFunctionServiceRole17C3A809" + ] + }, + "ErrorHandlingFunctionKafkaEventSource838c4d5ff3c99c1a617120adfca83e5berrorhandlingtopic9E5CD809": { + "Type": "AWS::Lambda::EventSourceMapping", + "Properties": { + "BatchSize": 50, + "FunctionName": { + "Ref": "ErrorHandlingFunctionC7AA2D94" + }, + "FunctionResponseTypes": [ + "ReportBatchItemFailures" + ], + "MaximumBatchingWindowInSeconds": 10, + "MaximumRecordAgeInSeconds": 86400, + "MaximumRetryAttempts": 3, + "ProvisionedPollerConfig": { + "MaximumPollers": 1, + "MinimumPollers": 1 + }, + "SelfManagedEventSource": { + "Endpoints": { + "KafkaBootstrapServers": [ + "my-self-hosted-kafka-broker-1:9092", + "my-self-hosted-kafka-broker-2:9092", + "my-self-hosted-kafka-broker-3:9092" + ] + } + }, + "SelfManagedKafkaEventSourceConfig": { + "ConsumerGroupId": "errorHandlingConsumerGroup" + }, + "SourceAccessConfigurations": [ + { + "Type": "CLIENT_CERTIFICATE_TLS_AUTH", + "URI": { + "Ref": "ClientCertSecret84224011" + } + }, + { + "Type": "SERVER_ROOT_CA_CERTIFICATE", + "URI": { + "Ref": "RootCASecret21632BB9" + } + } + ], + "StartingPosition": "TRIM_HORIZON", + "Topics": [ + "error-handling-topic" + ] + } + } + }, + "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-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/manifest.json new file mode 100644 index 0000000000000..90819a25e699d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/manifest.json @@ -0,0 +1,858 @@ +{ + "version": "48.0.0", + "artifacts": { + "lambda-event-source-kafka-error-handling.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "lambda-event-source-kafka-error-handling.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "lambda-event-source-kafka-error-handling": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "lambda-event-source-kafka-error-handling.template.json", + "terminationProtection": false, + "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}/4acaeb41811b2c95056a45ac80701a3435d93ad9db2e53f929a50bf324f89395.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "lambda-event-source-kafka-error-handling.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": [ + "lambda-event-source-kafka-error-handling.assets" + ], + "metadata": { + "/lambda-event-source-kafka-error-handling/RootCASecret": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "secretObjectValue": "*" + } + } + ], + "/lambda-event-source-kafka-error-handling/RootCASecret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "RootCASecret21632BB9" + } + ], + "/lambda-event-source-kafka-error-handling/ClientCertSecret": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "secretObjectValue": "*" + } + } + ], + "/lambda-event-source-kafka-error-handling/ClientCertSecret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClientCertSecret84224011" + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "handler": "*", + "code": "*", + "runtime": "*" + } + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole": [ + { + "type": "aws:cdk:warning", + "data": "Failed to add construct metadata for node [ServiceRole]. Reason: ValidationError: The result of fromAwsManagedPolicyName can not be used in this API [ack: @aws-cdk/core:addConstructMetadataFailed]" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachInlinePolicy": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addToPrincipalPolicy": [ + {} + ] + } + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ErrorHandlingFunctionServiceRole17C3A809" + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole/DefaultPolicy": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "attachToRole": [ + "*" + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + }, + { + "type": "aws:cdk:analytics:method", + "data": { + "addStatements": [ + {} + ] + } + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ErrorHandlingFunctionServiceRoleDefaultPolicy73BB7661" + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ErrorHandlingFunctionC7AA2D94" + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction/KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:error-handling-topic": [ + { + "type": "aws:cdk:analytics:construct", + "data": { + "target": "*", + "filters": "*", + "filterEncryption": "*", + "kafkaBootstrapServers": "*", + "kafkaTopic": "*", + "kafkaConsumerGroupId": "*", + "startingPosition": "TRIM_HORIZON", + "startingPositionTimestamp": "*", + "sourceAccessConfigurations": [ + { + "type": "*", + "uri": "*" + }, + { + "type": "*", + "uri": "*" + } + ], + "onFailure": "*", + "supportS3OnFailureDestination": true, + "provisionedPollerConfig": { + "minimumPollers": "*", + "maximumPollers": "*" + }, + "schemaRegistryConfig": "*", + "bisectBatchOnError": "*", + "retryAttempts": "*", + "reportBatchItemFailures": true, + "maxRecordAge": "*", + "batchSize": "*", + "maxBatchingWindow": "*", + "parallelizationFactor": "*", + "tumblingWindow": "*", + "enabled": "*" + } + } + ], + "/lambda-event-source-kafka-error-handling/ErrorHandlingFunction/KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:error-handling-topic/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ErrorHandlingFunctionKafkaEventSource838c4d5ff3c99c1a617120adfca83e5berrorhandlingtopic9E5CD809" + } + ], + "/lambda-event-source-kafka-error-handling/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/lambda-event-source-kafka-error-handling/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ], + "RootCASecretA6BCF3F1": [ + { + "type": "aws:cdk:logicalId", + "data": "RootCASecretA6BCF3F1", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ClientCertSecret8B3F6F8E": [ + { + "type": "aws:cdk:logicalId", + "data": "ClientCertSecret8B3F6F8E", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ErrorHandlingFunctionServiceRole0E9F8B3A": [ + { + "type": "aws:cdk:logicalId", + "data": "ErrorHandlingFunctionServiceRole0E9F8B3A", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ErrorHandlingFunctionServiceRoleDefaultPolicy8C7E9F4D": [ + { + "type": "aws:cdk:logicalId", + "data": "ErrorHandlingFunctionServiceRoleDefaultPolicy8C7E9F4D", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ErrorHandlingFunction4E8B9C2A": [ + { + "type": "aws:cdk:logicalId", + "data": "ErrorHandlingFunction4E8B9C2A", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "ErrorHandlingFunctionKafkaEventSource838c4d5ff3c99c1a617120adfca83e5berrorhandlingtopic7E8F9A3B": [ + { + "type": "aws:cdk:logicalId", + "data": "ErrorHandlingFunctionKafkaEventSource838c4d5ff3c99c1a617120adfca83e5berrorhandlingtopic7E8F9A3B", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ] + }, + "displayName": "lambda-event-source-kafka-error-handling" + }, + "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.template.json", + "terminationProtection": false, + "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": [ + "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.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": [ + "LambdaEventSourceKafkaErrorHandlingTestDefaultTestDeployAssert6CB171EE.assets" + ], + "metadata": { + "/LambdaEventSourceKafkaErrorHandlingTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/LambdaEventSourceKafkaErrorHandlingTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "LambdaEventSourceKafkaErrorHandlingTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-lib/feature-flag-report": { + "type": "cdk:feature-flag-report", + "properties": { + "module": "aws-cdk-lib", + "flags": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": { + "userValue": true, + "recommendedValue": true, + "explanation": "Pass signingProfileName to CfnSigningProfile" + }, + "@aws-cdk/core:newStyleStackSynthesis": { + "recommendedValue": true, + "explanation": "Switch to new stack synthesis method which enables CI/CD", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:stackRelativeExports": { + "recommendedValue": true, + "explanation": "Name exports based on the construct paths relative to the stack, rather than the global construct path", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": { + "userValue": true, + "recommendedValue": true, + "explanation": "Disable implicit openListener when custom security groups are provided" + }, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": { + "recommendedValue": true, + "explanation": "Force lowercasing of RDS Cluster names in CDK", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": { + "recommendedValue": true, + "explanation": "Allow adding/removing multiple UsagePlanKeys independently", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeVersionProps": { + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeLayerVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`." + }, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": { + "recommendedValue": true, + "explanation": "Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:checkSecretUsage": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations" + }, + "@aws-cdk/core:target-partitions": { + "recommendedValue": [ + "aws", + "aws-cn" + ], + "explanation": "What regions to include in lookup tables of environment agnostic stacks" + }, + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": { + "userValue": true, + "recommendedValue": true, + "explanation": "ECS extensions will automatically add an `awslogs` driver if no logging is specified" + }, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names." + }, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": { + "userValue": true, + "recommendedValue": true, + "explanation": "ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID." + }, + "@aws-cdk/aws-iam:minimizePolicies": { + "userValue": true, + "recommendedValue": true, + "explanation": "Minimize IAM policies by combining Statements" + }, + "@aws-cdk/core:validateSnapshotRemovalPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Error on snapshot removal policies on resources that do not support it." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate key aliases that include the stack name" + }, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist." + }, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict KMS key policy for encrypted Queues a bit more" + }, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make default CloudWatch Role behavior safe for multiple API Gateways in one environment" + }, + "@aws-cdk/core:enablePartitionLiterals": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make ARNs concrete if AWS partition is known" + }, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": { + "userValue": true, + "recommendedValue": true, + "explanation": "Event Rules may only push to encrypted SQS queues in the same account" + }, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": { + "userValue": true, + "recommendedValue": true, + "explanation": "Avoid setting the \"ECS\" deployment controller when adding a circuit breaker" + }, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature to create default policy names for imported roles that depend on the stack the role is in." + }, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use S3 Bucket Policy instead of ACLs for Server Access Logging" + }, + "@aws-cdk/aws-route53-patters:useCertificate": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use the official `Certificate` resource instead of `DnsValidatedCertificate`" + }, + "@aws-cdk/customresources:installLatestAwsSdkDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "Whether to install the latest SDK by default in AwsCustomResource" + }, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use unique resource name for Database Proxy" + }, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Remove CloudWatch alarms from deployment group" + }, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include authorizer configuration in the calculation of the API deployment logical ID." + }, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": { + "userValue": true, + "recommendedValue": true, + "explanation": "Define user data for a launch template by default when a machine image is provided." + }, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": { + "userValue": true, + "recommendedValue": true, + "explanation": "SecretTargetAttachments uses the ResourcePolicy of the attached Secret." + }, + "@aws-cdk/aws-redshift:columnId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Whether to use an ID to track Redshift column changes" + }, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable AmazonEMRServicePolicy_v2 managed policies" + }, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict access to the VPC default security group" + }, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a unique id for each RequestValidator added to a method" + }, + "@aws-cdk/aws-kms:aliasNameRef": { + "userValue": true, + "recommendedValue": true, + "explanation": "KMS Alias name and keyArn will have implicit reference to KMS Key" + }, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable grant methods on Aliases imported by name to use kms:ResourceAliases condition" + }, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a launch template when creating an AutoScalingGroup" + }, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include the stack prefix in the stack name generation process" + }, + "@aws-cdk/aws-efs:denyAnonymousAccess": { + "userValue": true, + "recommendedValue": true, + "explanation": "EFS denies anonymous clients accesses" + }, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables support for Multi-AZ with Standby deployment for opensearch domains" + }, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables aws-lambda-nodejs.Function to use the latest available NodeJs runtime as the default" + }, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, mount targets will have a stable logicalId that is linked to the associated subnet." + }, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a scope of InstanceParameterGroup for AuroraClusterInstance with each parameters will change." + }, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, will always use the arn for identifiers for CfnSourceApiAssociation in the GraphqlApi construct rather than id." + }, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, creating an RDS database cluster from a snapshot will only render credentials for snapshot credentials." + }, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the CodeCommit source action is using the default branch name 'main'." + }, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the logical ID of a Lambda permission for a Lambda action includes an alarm ID." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default value for crossAccountKeys to false." + }, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default pipeline type to V2." + }, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, IAM Policy created from KMS key grant will reduce the resource scope to this key only." + }, + "@aws-cdk/pipelines:reduceAssetRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from PipelineAssetsFileRole trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-eks:nodegroupNameAttribute": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, nodegroupName attribute of the provisioned EKS NodeGroup will not have the cluster name prefix." + }, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default volume type of the EBS volume will be GP3" + }, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, remove default deployment alarm settings" + }, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default" + }, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack." + }, + "@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": { + "recommendedValue": true, + "explanation": "When enabled, use new props for S3 URI field in task definition of state machine for bedrock invoke model.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:explicitStackTags": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, stack tags need to be assigned explicitly on a Stack." + }, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": { + "userValue": false, + "recommendedValue": false, + "explanation": "When set to true along with canContainersAccessInstanceRole=false in ECS cluster, new updated commands will be added to UserData to block container accessing IMDS. **Applicable to Linux only. IMPORTANT: See [details.](#aws-cdkaws-ecsenableImdsBlockingDeprecatedFeature)**" + }, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, CDK synth will throw exception if canContainersAccessInstanceRole is false. **IMPORTANT: See [details.](#aws-cdkaws-ecsdisableEcsImdsBlocking)**" + }, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, we will only grant the necessary permissions when users specify cloudwatch log group through logConfiguration" + }, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled will allow you to specify a resource policy per replica, and not copy the source table policy to all replicas" + }, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, initOptions.timeout and resourceSignalTimeout values will be summed together." + }, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a Lambda authorizer Permission created when using GraphqlApi will be properly scoped with a SourceArn." + }, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the value of property `instanceResourceId` in construct `DatabaseInstanceReadReplica` will be set to the correct value which is `DbiResourceId` instead of currently `DbInstanceArn`" + }, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CFN templates added with `cfn-include` will error if the template contains Resource Update or Create policies with CFN Intrinsics that include non-primitive values." + }, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, both `@aws-sdk` and `@smithy` packages will be excluded from the Lambda Node.js 18.x runtime to prevent version mismatches in bundled applications." + }, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resource of IAM Run Ecs policy generated by SFN EcsRunTask will reference the definition, instead of constructing ARN." + }, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the BastionHost construct will use the latest Amazon Linux 2023 AMI, instead of Amazon Linux 2." + }, + "@aws-cdk/core:aspectStabilization": { + "recommendedValue": true, + "explanation": "When enabled, a stabilization loop will be run when invoking Aspects during synthesis.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, use a new method for DNS Name of user pool domain target without creating a custom resource." + }, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default security group ingress rules will allow IPv6 ingress from anywhere" + }, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default behaviour of OIDC provider will reject unauthorized connections" + }, + "@aws-cdk/core:enableAdditionalMetadataCollection": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will expand the scope of usage data collected to better inform CDK development and improve communication for security concerns and emerging issues." + }, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": { + "userValue": false, + "recommendedValue": false, + "explanation": "[Deprecated] When enabled, Lambda will create new inline policies with AddToRolePolicy instead of adding to the Default Policy Statement" + }, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will automatically generate a unique role name that is used for s3 object replication." + }, + "@aws-cdk/pipelines:reduceStageRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from Stage addActions trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-events:requireEventBusPolicySid": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, grantPutEventsTo() will use resource policies with Statement IDs for service principals." + }, + "@aws-cdk/core:aspectPrioritiesMutating": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, Aspects added by the construct library on your behalf will be given a priority of MUTATING." + }, + "@aws-cdk/aws-dynamodb:retainTableReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, table replica will be default to the removal policy of source table unless specified otherwise." + }, + "@aws-cdk/cognito:logUserPoolClientSecretValue": { + "recommendedValue": false, + "explanation": "When disabled, the value of the user pool client secret will not be logged in the custom resource lambda function logs." + }, + "@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": { + "recommendedValue": true, + "explanation": "When enabled, scopes down the trust policy for the cross-account action role", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resultWriterV2 property of DistributedMap will be used insted of resultWriter" + }, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": { + "userValue": true, + "recommendedValue": true, + "explanation": "Add an S3 trust policy to a KMS key resource policy for SNS subscriptions." + }, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the EgressOnlyGateway resource is only created if private subnets are defined in the dual-stack VPC." + }, + "@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": { + "recommendedValue": false, + "explanation": "When enabled, use resource IDs for VPC V2 migration" + }, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, setting any combination of options for BlockPublicAccess will automatically set true for any options not defined." + }, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": { + "userValue": false, + "recommendedValue": true, + "explanation": "When enabled, CDK creates and manages loggroup for the lambda function" + }, + "@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault": { + "recommendedValue": true, + "explanation": "When enabled, Network Load Balancer will be created with a security group by default." + }, + "@aws-cdk/aws-stepfunctions-tasks:httpInvokeDynamicJsonPathEndpoint": { + "recommendedValue": true, + "explanation": "When enabled, allows using a dynamic apiEndpoint with JSONPath format in HttpInvoke tasks.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-ecs-patterns:uniqueTargetGroupId": { + "recommendedValue": true, + "explanation": "When enabled, ECS patterns will generate unique target group IDs to prevent conflicts during load balancer replacement" + } + } + } + } + }, + "minimumCliVersion": "2.1031.2" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/tree.json new file mode 100644 index 0000000000000..7c1ed17e90cd5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"aws-cdk-lib.App","version":"0.0.0"},"children":{"lambda-event-source-kafka-error-handling":{"id":"lambda-event-source-kafka-error-handling","path":"lambda-event-source-kafka-error-handling","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"RootCASecret":{"id":"RootCASecret","path":"lambda-event-source-kafka-error-handling/RootCASecret","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.Secret","version":"0.0.0","metadata":[{"secretObjectValue":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-kafka-error-handling/RootCASecret/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.CfnSecret","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::SecretsManager::Secret","aws:cdk:cloudformation:props":{"secretString":"{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuiAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\\\"\\n\"}"}}}}},"ClientCertSecret":{"id":"ClientCertSecret","path":"lambda-event-source-kafka-error-handling/ClientCertSecret","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.Secret","version":"0.0.0","metadata":[{"secretObjectValue":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-kafka-error-handling/ClientCertSecret/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_secretsmanager.CfnSecret","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::SecretsManager::Secret","aws:cdk:cloudformation:props":{"secretString":"{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw\\ncmUuiAii9R0=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb\\nc8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==\\n-----END CERTIFICATE-----\\\"\\n\",\"privateKey\":\"-----BEGIN ENCRYPTED PRIVATE KEY-----\\nzp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==\\n-----END ENCRYPTED PRIVATE KEY-----\"}"}}}}},"ErrorHandlingFunction":{"id":"ErrorHandlingFunction","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.Function","version":"0.0.0","metadata":[{"handler":"*","code":"*","runtime":"*"}]},"children":{"ServiceRole":{"id":"ServiceRole","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Role","version":"0.0.0","metadata":[{"addToPrincipalPolicy":[{}]},{"attachInlinePolicy":["*"]},{"attachInlinePolicy":["*"]},{"addToPrincipalPolicy":[{}]},{"addToPrincipalPolicy":[{}]}]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"aws-cdk-lib.Resource","version":"0.0.0","metadata":["*"]}},"Resource":{"id":"Resource","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnRole","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}},"DefaultPolicy":{"id":"DefaultPolicy","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole/DefaultPolicy","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.Policy","version":"0.0.0","metadata":["*",{"attachToRole":["*"]},{"attachToRole":["*"]},{"addStatements":[{}]},{"addStatements":[{}]},{"addStatements":[{}]}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction/ServiceRole/DefaultPolicy/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_iam.CfnPolicy","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["secretsmanager:DescribeSecret","secretsmanager:GetSecretValue"],"Effect":"Allow","Resource":[{"Ref":"ClientCertSecret84224011"},{"Ref":"RootCASecret21632BB9"}]}],"Version":"2012-10-17"},"policyName":"ErrorHandlingFunctionServiceRoleDefaultPolicy73BB7661","roles":[{"Ref":"ErrorHandlingFunctionServiceRole17C3A809"}]}}}}}}},"Resource":{"id":"Resource","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnFunction","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}"},"handler":"index.handler","role":{"Fn::GetAtt":["ErrorHandlingFunctionServiceRole17C3A809","Arn"]},"runtime":"nodejs18.x"}}},"KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:error-handling-topic":{"id":"KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:error-handling-topic","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction/KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:error-handling-topic","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.EventSourceMapping","version":"0.0.0","metadata":[{"target":"*","filters":"*","filterEncryption":"*","kafkaBootstrapServers":"*","kafkaTopic":"*","kafkaConsumerGroupId":"*","startingPosition":"TRIM_HORIZON","startingPositionTimestamp":"*","sourceAccessConfigurations":[{"type":"*","uri":"*"},{"type":"*","uri":"*"}],"onFailure":"*","supportS3OnFailureDestination":true,"provisionedPollerConfig":{"minimumPollers":"*","maximumPollers":"*"},"schemaRegistryConfig":"*","bisectBatchOnError":"*","retryAttempts":"*","reportBatchItemFailures":true,"maxRecordAge":"*","batchSize":"*","maxBatchingWindow":"*","parallelizationFactor":"*","tumblingWindow":"*","enabled":"*"}]},"children":{"Resource":{"id":"Resource","path":"lambda-event-source-kafka-error-handling/ErrorHandlingFunction/KafkaEventSource:838c4d5ff3c99c1a617120adfca83e5b:error-handling-topic/Resource","constructInfo":{"fqn":"aws-cdk-lib.aws_lambda.CfnEventSourceMapping","version":"0.0.0"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::EventSourceMapping","aws:cdk:cloudformation:props":{"batchSize":50,"functionName":{"Ref":"ErrorHandlingFunctionC7AA2D94"},"functionResponseTypes":["ReportBatchItemFailures"],"maximumBatchingWindowInSeconds":10,"maximumRecordAgeInSeconds":86400,"maximumRetryAttempts":3,"provisionedPollerConfig":{"minimumPollers":1,"maximumPollers":1},"selfManagedEventSource":{"endpoints":{"kafkaBootstrapServers":["my-self-hosted-kafka-broker-1:9092","my-self-hosted-kafka-broker-2:9092","my-self-hosted-kafka-broker-3:9092"]}},"selfManagedKafkaEventSourceConfig":{"consumerGroupId":"errorHandlingConsumerGroup"},"sourceAccessConfigurations":[{"type":"CLIENT_CERTIFICATE_TLS_AUTH","uri":{"Ref":"ClientCertSecret84224011"}},{"type":"SERVER_ROOT_CA_CERTIFICATE","uri":{"Ref":"RootCASecret21632BB9"}}],"startingPosition":"TRIM_HORIZON","topics":["error-handling-topic"]}}}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"lambda-event-source-kafka-error-handling/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"lambda-event-source-kafka-error-handling/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}},"LambdaEventSourceKafkaErrorHandlingTest":{"id":"LambdaEventSourceKafkaErrorHandlingTest","path":"LambdaEventSourceKafkaErrorHandlingTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"LambdaEventSourceKafkaErrorHandlingTest/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"LambdaEventSourceKafkaErrorHandlingTest/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"LambdaEventSourceKafkaErrorHandlingTest/DefaultTest/DeployAssert","constructInfo":{"fqn":"aws-cdk-lib.Stack","version":"0.0.0"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"LambdaEventSourceKafkaErrorHandlingTest/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnParameter","version":"0.0.0"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"LambdaEventSourceKafkaErrorHandlingTest/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"aws-cdk-lib.CfnRule","version":"0.0.0"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.ts new file mode 100644 index 0000000000000..ca3538587cdd1 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged-error-handling.ts @@ -0,0 +1,83 @@ +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'; +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import { TestFunction } from './test-function'; +import { AuthenticationMethod, SelfManagedKafkaEventSource } from 'aws-cdk-lib/aws-lambda-event-sources'; + +class KafkaSelfManagedErrorHandlingTest extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const dummyCertString = `-----BEGIN CERTIFICATE----- +MIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw +cmUuiAii9R0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb +c8PH3PSoAaRwMMgOSA2ALJvbRz8mpg== +-----END CERTIFICATE-----" +`; + + const dummyPrivateKey = `-----BEGIN ENCRYPTED PRIVATE KEY----- +zp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA== +-----END ENCRYPTED PRIVATE KEY-----`; + + const rootCASecret = new secretsmanager.Secret(this, 'RootCASecret', { + secretObjectValue: { + certificate: cdk.SecretValue.unsafePlainText(dummyCertString), + }, + }); + + const clientCertificatesSecret = new secretsmanager.Secret(this, 'ClientCertSecret', { + secretObjectValue: { + certificate: cdk.SecretValue.unsafePlainText(dummyCertString), + privateKey: cdk.SecretValue.unsafePlainText(dummyPrivateKey), + }, + }); + + const bootstrapServers = [ + 'my-self-hosted-kafka-broker-1:9092', + 'my-self-hosted-kafka-broker-2:9092', + 'my-self-hosted-kafka-broker-3:9092', + ]; + + // Test with function response type and retry configuration + const fn = new TestFunction(this, 'ErrorHandlingFunction'); + rootCASecret.grantRead(fn); + clientCertificatesSecret.grantRead(fn); + + fn.addEventSource(new SelfManagedKafkaEventSource({ + bootstrapServers, + topic: 'error-handling-topic', + consumerGroupId: 'errorHandlingConsumerGroup', + secret: clientCertificatesSecret, + authenticationMethod: AuthenticationMethod.CLIENT_CERTIFICATE_TLS_AUTH, + rootCACertificate: rootCASecret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + retryAttempts: 3, + maxBatchingWindow: cdk.Duration.seconds(10), + batchSize: 50, + maxRecordAge: cdk.Duration.hours(24), + reportBatchItemFailures: true, + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 1, + }, + })); + } +} + +const app = new cdk.App({ + postCliContext: { + '@aws-cdk/aws-lambda:useCdkManagedLogGroup': false, + }, +}); +const stack = new KafkaSelfManagedErrorHandlingTest( + app, + 'lambda-event-source-kafka-error-handling', +); +new integ.IntegTest(app, 'LambdaEventSourceKafkaErrorHandlingTest', { + testCases: [stack], +}); +app.synth(); diff --git a/packages/aws-cdk-lib/aws-lambda-event-sources/README.md b/packages/aws-cdk-lib/aws-lambda-event-sources/README.md index c3ec512e21880..d61bccb5fd53f 100644 --- a/packages/aws-cdk-lib/aws-lambda-event-sources/README.md +++ b/packages/aws-cdk-lib/aws-lambda-event-sources/README.md @@ -279,6 +279,10 @@ You can write Lambda functions to process data either from [Amazon MSK](https:// * __maxBatchingWindow__: The maximum amount of time to gather records before invoking the lambda. This increases the likelihood of a full batch at the cost of possibly delaying processing. * __onFailure__: In the event a record fails and consumes all retries, the record will be sent to SQS queue or SNS topic that is specified here * __enabled__: If the Kafka event source mapping should be enabled. The default is true. +* __bisectBatchOnError__: If a batch encounters an error, this will cause the batch to be split in two and have each new smaller batch retried, allowing the records in error to be isolated. Available in provisioned mode only. +* __reportBatchItemFailures__: Allow functions to return partially successful responses for a batch of records. Available in provisioned mode only. +* __retryAttempts__: The maximum number of times a record should be retried in the event of failure. Available in provisioned mode only. +* __maxRecordAge__: The maximum age of a record that will be sent to the function for processing. Records that exceed the max age will be treated as failures. Available in provisioned mode only. The following code sets up Amazon MSK as an event source for a lambda function. Credentials will need to be configured to access the MSK cluster, as described in [Username/Password authentication](https://docs.aws.amazon.com/msk/latest/developerguide/msk-password.html). @@ -294,7 +298,6 @@ const clusterArn = 'arn:aws:kafka:us-east-1:0123456789019:cluster/SalesCluster/a const topic = 'some-cool-topic'; // The secret that allows access to your MSK cluster -// You still have to make sure that it is associated with your cluster as described in the documentation const secret = new Secret(this, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); declare const myFunction: lambda.Function; @@ -304,6 +307,14 @@ myFunction.addEventSource(new ManagedKafkaEventSource({ secret: secret, batchSize: 100, // default startingPosition: lambda.StartingPosition.TRIM_HORIZON, + bisectBatchOnError: true, + reportBatchItemFailures: true, + retryAttempts: 3, + maxRecordAge: Duration.hours(24), + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 3, + }, })); ``` @@ -334,6 +345,14 @@ myFunction.addEventSource(new SelfManagedKafkaEventSource({ secret: secret, batchSize: 100, // default startingPosition: lambda.StartingPosition.TRIM_HORIZON, + bisectBatchOnError: true, + reportBatchItemFailures: true, + retryAttempts: 3, + maxRecordAge: Duration.hours(24), + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 3, + }, })); ``` @@ -397,6 +416,64 @@ myFunction.addEventSource(new ManagedKafkaEventSource({ })); ``` +### Failure Destinations + +You can specify failure destinations for records that fail processing. Kafka event sources support Kafka Topic Destinations, S3 Bucket Destinations, SQS Queue and SNS topic: + +#### Kafka Topic Destination + +For Kafka event sources, you can send failed records to another Kafka topic using `KafkaDlq`: + +```ts +import { ManagedKafkaEventSource, KafkaDlq } from 'aws-cdk-lib/aws-lambda-event-sources'; + +// Your MSK cluster arn +const clusterArn = 'arn:aws:kafka:us-east-1:0123456789019:cluster/SalesCluster/abcd1234-abcd-cafe-abab-9876543210ab-4'; + +// The Kafka topic you want to subscribe to +const topic = 'some-cool-topic'; + +declare const myFunction: lambda.Function; + +// Create a Kafka DLQ destination +const kafkaDlq = new KafkaDlq('failure-topic'); + +myFunction.addEventSource(new ManagedKafkaEventSource({ + clusterArn, + topic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 1, + }, +})); +``` + +The same approach works with self-managed Kafka: + +```ts +import { SelfManagedKafkaEventSource, KafkaDlq } from 'aws-cdk-lib/aws-lambda-event-sources'; + +const bootstrapServers = ['kafka-broker:9092']; +const topic = 'some-cool-topic'; + +declare const myFunction: lambda.Function; + +myFunction.addEventSource(new SelfManagedKafkaEventSource({ + bootstrapServers, + topic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: new KafkaDlq('error-topic'), + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 1, + }, +})); +``` + +#### S3 Bucket Destination + You can also specify an S3 bucket as an "on failure" destination: ```ts @@ -428,7 +505,7 @@ Set configuration for provisioned pollers that read from the event source. import { ManagedKafkaEventSource } from 'aws-cdk-lib/aws-lambda-event-sources'; // Your MSK cluster arn -declare const clusterArn: string +declare const clusterArn: string; // The Kafka topic you want to subscribe to const topic = 'some-cool-topic'; @@ -445,6 +522,28 @@ myFunction.addEventSource(new ManagedKafkaEventSource({ })); ``` +You can reduce costs by sharing provisioned pollers across multiple Kafka event sources using the `pollerGroupName` property. This is particularly useful when you have multiple Kafka topics that don't require dedicated polling capacity. + +```ts +import { ManagedKafkaEventSource } from 'aws-cdk-lib/aws-lambda-event-sources'; + +declare const clusterArn: string; +declare const ordersFunction: lambda.Function; + +// Orders processing function +ordersFunction.addEventSource(new ManagedKafkaEventSource({ + clusterArn, + topic: 'orders-topic', + startingPosition: lambda.StartingPosition.LATEST, + provisionedPollerConfig: { + minimumPollers: 2, + maximumPollers: 10, + pollerGroupName: 'shared-kafka-pollers', + }, +})); + +``` + Set a confluent or self-managed schema registry to de-serialize events from the event source. Note, this will similarly work for `SelfManagedKafkaEventSource` but the example only shows setup for `ManagedKafkaEventSource`. ```ts diff --git a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/index.ts b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/index.ts index ea710d869e1af..2ce9344932995 100644 --- a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/index.ts +++ b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/index.ts @@ -1,6 +1,7 @@ export * from './api'; export * from './dynamodb'; export * from './kafka'; +export * from './kafka-dlq'; export * from './kinesis'; export * from './s3'; export * from './sns'; diff --git a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka-dlq.ts b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka-dlq.ts new file mode 100644 index 0000000000000..31d41e909e875 --- /dev/null +++ b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka-dlq.ts @@ -0,0 +1,66 @@ +import { DlqDestinationConfig, IEventSourceDlq, IEventSourceMapping, IFunction } from '../../aws-lambda'; +import { Token } from '../../core'; + +/** + * A Kafka topic dead letter queue destination configuration for a Lambda event source. + * + * This destination can only be used with Kafka-based event sources (MSK and self-managed Kafka). + * When used with other event source types, a validation error will be thrown. + * + * ## Kafka URI Format + * + * new KafkaDlq('my-topic'); + * + * ## Topic Naming Requirements + * + * Kafka topic names must follow these rules: + * - Only alphanumeric characters, dots (.), underscores (_), and hyphens (-) are allowed + * - Cannot be empty + * - Must be a valid Kafka topic name + * + */ +export class KafkaDlq implements IEventSourceDlq { + private readonly topicName: string; + + /** + * Creates a new Kafka DLQ destination. + * + * @throws {TypeError} When the topic name is empty or contains invalid characters + */ + constructor(topicName: string) { + if (!Token.isUnresolved(topicName)) { + if (!topicName || topicName.trim().length === 0) { + throw new TypeError('Topic name cannot be empty'); + } + + // Validate basic Kafka topic naming rules + const cleanTopicName = topicName.startsWith('kafka://') ? topicName.substring(8) : topicName; + if (cleanTopicName.length === 0) { + throw new TypeError('Topic name cannot be empty after removing kafka:// prefix'); + } + + // Basic validation for Kafka topic names + if (!/^[a-zA-Z0-9._-]+$/.test(cleanTopicName)) { + throw new TypeError('Topic name contains invalid characters. Only alphanumeric characters, dots, underscores, and hyphens are allowed'); + } + this.topicName = topicName.startsWith('kafka://') ? topicName : `kafka://${topicName}`; + } else { + this.topicName = topicName; + } + } + + /** + * Returns a destination configuration for the DLQ. + * + * The returned configuration is used in the AWS Lambda EventSourceMapping's DestinationConfig + * to specify where failed records should be sent. + * + * @returns The DLQ destination configuration with the properly formatted Kafka URI + * + */ + public bind(_target: IEventSourceMapping, _targetHandler: IFunction): DlqDestinationConfig { + return { + destination: this.topicName, + }; + } +} diff --git a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka.ts b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka.ts index e341be604c31e..f0ff896cc154b 100644 --- a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka.ts +++ b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka.ts @@ -6,7 +6,7 @@ import { IKey } from '../../aws-kms'; import * as lambda from '../../aws-lambda'; import { ISchemaRegistry } from '../../aws-lambda/lib/schema-registry'; import * as secretsmanager from '../../aws-secretsmanager'; -import { Stack, Names, Annotations, UnscopedValidationError, ValidationError } from '../../core'; +import { Stack, Names, Annotations, UnscopedValidationError, ValidationError, Duration } from '../../core'; import { md5hash } from '../../core/lib/helpers-internal'; /** @@ -51,7 +51,13 @@ export interface KafkaEventSourceProps extends BaseStreamEventSourceProps { readonly filterEncryption?: IKey; /** - * Add an on Failure Destination for this Kafka event. SNS/SQS/S3 are supported + * Add an on Failure Destination for this Kafka event. + * + * Supported destinations: + * - {@link KafkaDlq} - Send failed records to a Kafka topic + * - SNS topics - Send failed records to an SNS topic + * - SQS queues - Send failed records to an SQS queue + * - S3 buckets - Send failed records to an S3 bucket * * @default - discarded records are ignored */ @@ -70,6 +76,40 @@ export interface KafkaEventSourceProps extends BaseStreamEventSourceProps { * @default - none */ readonly schemaRegistryConfig?: ISchemaRegistry; + + /*** + * If the function returns an error, split the batch in two and retry. + * + * @default false + */ + readonly bisectBatchOnError?: boolean; + + /** + * The maximum age of a record that Lambda sends to a function for processing. + * + * The default value is -1, which sets the maximum age to infinite. + * When the value is set to infinite, Lambda never discards old records. + * Record are valid until it expires in the event source. + * + * @default -1 + */ + readonly maxRecordAge?: Duration; + + /*** + * Maximum number of retry attempts. + * + * Set to -1 for infinite retries (until the record expires in the event source). + * + * @default -1 (infinite retries) + */ + readonly retryAttempts?: number; + + /*** + * Allow functions to return partially successful responses for a batch of records. + * + * @default false + */ + readonly reportBatchItemFailures?: boolean; } /** @@ -154,6 +194,23 @@ export interface SelfManagedKafkaEventSourceProps extends KafkaEventSourceProps /** * Use a MSK cluster as a streaming source for AWS Lambda + * + * @example + * import { ManagedKafkaEventSource } from 'aws-cdk-lib/aws-lambda-event-sources'; + * import { StartingPosition, Function } from 'aws-cdk-lib/aws-lambda'; + * + * // With provisioned pollers and poller group for cost optimization + * declare const myFunction: Function; + * myFunction.addEventSource(new ManagedKafkaEventSource({ + * clusterArn: 'arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abcd1234-abcd-cafe-abab-9876543210ab-4', + * topic: 'orders-topic', + * startingPosition: StartingPosition.LATEST, + * provisionedPollerConfig: { + * minimumPollers: 2, + * maximumPollers: 10, + * pollerGroupName: 'shared-kafka-pollers', + * }, + * })); */ export class ManagedKafkaEventSource extends StreamEventSource { // This is to work around JSII inheritance problems @@ -190,6 +247,10 @@ export class ManagedKafkaEventSource extends StreamEventSource { supportS3OnFailureDestination: true, provisionedPollerConfig: this.innerProps.provisionedPollerConfig, schemaRegistryConfig: this.innerProps.schemaRegistryConfig, + bisectBatchOnError: this.innerProps.bisectBatchOnError, + retryAttempts: this.innerProps.retryAttempts, + reportBatchItemFailures: this.innerProps.reportBatchItemFailures, + maxRecordAge: this.innerProps.maxRecordAge, }), ); @@ -248,6 +309,27 @@ export class ManagedKafkaEventSource extends StreamEventSource { /** * Use a self hosted Kafka installation as a streaming source for AWS Lambda. + * + * @example + * import { SelfManagedKafkaEventSource, AuthenticationMethod } from 'aws-cdk-lib/aws-lambda-event-sources'; + * import { StartingPosition, Function } from 'aws-cdk-lib/aws-lambda'; + * import { ISecret } from 'aws-cdk-lib/aws-secretsmanager'; + * + * // With provisioned pollers and poller group for cost optimization + * declare const myFunction: Function; + * declare const kafkaCredentials: ISecret; + * myFunction.addEventSource(new SelfManagedKafkaEventSource({ + * bootstrapServers: ['kafka-broker1.example.com:9092', 'kafka-broker2.example.com:9092'], + * topic: 'events-topic', + * secret: kafkaCredentials, + * startingPosition: StartingPosition.LATEST, + * authenticationMethod: AuthenticationMethod.SASL_SCRAM_512_AUTH, + * provisionedPollerConfig: { + * minimumPollers: 1, + * maximumPollers: 8, + * pollerGroupName: 'self-managed-kafka-group', // Group pollers to reduce costs + * }, + * })); */ export class SelfManagedKafkaEventSource extends StreamEventSource { // This is to work around JSII inheritance problems @@ -294,6 +376,10 @@ export class SelfManagedKafkaEventSource extends StreamEventSource { supportS3OnFailureDestination: true, provisionedPollerConfig: this.innerProps.provisionedPollerConfig, schemaRegistryConfig: this.innerProps.schemaRegistryConfig, + bisectBatchOnError: this.innerProps.bisectBatchOnError, + retryAttempts: this.innerProps.retryAttempts, + reportBatchItemFailures: this.innerProps.reportBatchItemFailures, + maxRecordAge: this.innerProps.maxRecordAge, }), ); diff --git a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/stream.ts b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/stream.ts index 9a7a5df80f151..b57f84b18c53e 100644 --- a/packages/aws-cdk-lib/aws-lambda-event-sources/lib/stream.ts +++ b/packages/aws-cdk-lib/aws-lambda-event-sources/lib/stream.ts @@ -7,7 +7,7 @@ import { Duration, UnscopedValidationError } from '../../core'; * The set of properties for streaming event sources shared by * Dynamo, Kinesis and Kafka. */ -export interface BaseStreamEventSourceProps{ +export interface BaseStreamEventSourceProps { /** * The largest number of records that AWS Lambda will retrieve from your event * source at the time of invoking your function. Your function receives an @@ -70,6 +70,14 @@ export interface ProvisionedPollerConfig { * @default 200 */ readonly maximumPollers: number; + /** + * An optional identifier that groups multiple ESMs to share EPU capacity + * and reduce costs. ESMs with the same PollerGroupName share compute + * resources. + * + * @default - not set, dedicated compute resource per event source. + */ + readonly pollerGroupName?: string; } /** diff --git a/packages/aws-cdk-lib/aws-lambda-event-sources/test/kafka-dlq.test.ts b/packages/aws-cdk-lib/aws-lambda-event-sources/test/kafka-dlq.test.ts new file mode 100644 index 0000000000000..739859994ef52 --- /dev/null +++ b/packages/aws-cdk-lib/aws-lambda-event-sources/test/kafka-dlq.test.ts @@ -0,0 +1,84 @@ +import { Template } from '../../assertions'; +import * as cdk from '../../core'; +import * as sources from '../lib'; + +describe('KafkaDlq', () => { + describe('constructor', () => { + test('creates destination with topic name', () => { + const dlq = new sources.KafkaDlq('my-topic'); + expect(dlq).toBeDefined(); + }); + + test('adds kafka:// prefix when not present', () => { + const dlq = new sources.KafkaDlq('my-topic'); + const config = dlq.bind({} as any, {} as any); + expect(config.destination).toBe('kafka://my-topic'); + }); + + test('does not duplicate kafka:// prefix', () => { + const dlq = new sources.KafkaDlq('kafka://my-topic'); + const config = dlq.bind({} as any, {} as any); + expect(config.destination).toBe('kafka://my-topic'); + }); + + test('throws error for empty topic name', () => { + expect(() => new sources.KafkaDlq('')).toThrow('Topic name cannot be empty'); + }); + + test('throws error for whitespace-only topic name', () => { + expect(() => new sources.KafkaDlq(' ')).toThrow('Topic name cannot be empty'); + }); + + test('throws error for empty topic name after removing kafka:// prefix', () => { + expect(() => new sources.KafkaDlq('kafka://')).toThrow('Topic name cannot be empty after removing kafka:// prefix'); + }); + + test('throws error for invalid characters in topic name', () => { + expect(() => new sources.KafkaDlq('invalid@topic')).toThrow('Topic name contains invalid characters'); + expect(() => new sources.KafkaDlq('invalid#topic')).toThrow('Topic name contains invalid characters'); + expect(() => new sources.KafkaDlq('invalid topic')).toThrow('Topic name contains invalid characters'); + }); + + test('accepts valid topic names with allowed characters', () => { + expect(() => new sources.KafkaDlq('valid-topic')).not.toThrow(); + expect(() => new sources.KafkaDlq('valid_topic')).not.toThrow(); + expect(() => new sources.KafkaDlq('valid.topic')).not.toThrow(); + expect(() => new sources.KafkaDlq('ValidTopic123')).not.toThrow(); + }); + + test('appends token as is without validation or prefix', () => { + const stack = new cdk.Stack(); + const token = cdk.Fn.ref('MyTopicParameter'); + + const dlq = new sources.KafkaDlq(token); + const config = dlq.bind({} as any, {} as any); + + expect(cdk.Token.isUnresolved(config.destination)).toBe(true); + }); + }); + + describe('bind method', () => { + test('returns correct DlqDestinationConfig', () => { + const dlq = new sources.KafkaDlq('test-topic'); + const config = dlq.bind({} as any, {} as any); + + expect(config).toEqual({ + destination: 'kafka://test-topic', + }); + }); + + test('preserves kafka:// prefix in destination', () => { + const dlq = new sources.KafkaDlq('kafka://existing-prefix-topic'); + const config = dlq.bind({} as any, {} as any); + + expect(config.destination).toBe('kafka://existing-prefix-topic'); + }); + + test('handles topic names with dots and underscores', () => { + const dlq = new sources.KafkaDlq('my.complex_topic-name'); + const config = dlq.bind({} as any, {} as any); + + expect(config.destination).toBe('kafka://my.complex_topic-name'); + }); + }); +}); diff --git a/packages/aws-cdk-lib/aws-lambda-event-sources/test/kafka.test.ts b/packages/aws-cdk-lib/aws-lambda-event-sources/test/kafka.test.ts index 4c1ceb76d9d2b..0ff219db48854 100644 --- a/packages/aws-cdk-lib/aws-lambda-event-sources/test/kafka.test.ts +++ b/packages/aws-cdk-lib/aws-lambda-event-sources/test/kafka.test.ts @@ -6,6 +6,8 @@ import { Key } from '../../aws-kms'; import * as lambda from '../../aws-lambda'; import { Bucket } from '../../aws-s3'; import { Secret } from '../../aws-secretsmanager'; +import { Topic } from '../../aws-sns'; +import { Queue } from '../../aws-sqs'; import * as cdk from '../../core'; import * as cxapi from '../../cx-api'; import * as sources from '../lib'; @@ -574,6 +576,7 @@ describe('KafkaEventSource', () => { }, }))).toThrow(/Minimum provisioned pollers must be less than or equal to maximum provisioned pollers/); }); + test('Setting startingPositionTimestamp for kafka event source ', () => { const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -593,6 +596,42 @@ describe('KafkaEventSource', () => { StartingPositionTimestamp: 1640995200, }); }); + + test('Setting error handling properties', () => { + const stack = new cdk.Stack(); + const testLambdaFunction = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + const bucket = Bucket.fromBucketName(stack, 'BucketByName', 'my-bucket'); + const s3OnFailureDestination = new sources.S3OnFailureDestination(bucket); + + testLambdaFunction.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 3, + }, + bisectBatchOnError: true, + retryAttempts: 5, + reportBatchItemFailures: true, + maxRecordAge: cdk.Duration.hours(1), + }), + ); + + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + StartingPosition: 'TRIM_HORIZON', + BisectBatchOnFunctionError: true, + MaximumRetryAttempts: 5, + FunctionResponseTypes: ['ReportBatchItemFailures'], + MaximumRecordAgeInSeconds: 3600, // 1 hour in seconds + ProvisionedPollerConfig: { + MinimumPollers: 1, + MaximumPollers: 3, + }, + }); + }); }); describe('self-managed kafka', () => { @@ -2034,5 +2073,1253 @@ describe('KafkaEventSource', () => { }, }); }); + + test('SelfManagedKafkaEventSource inherits error handling properties correctly', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); + const bootstrapServers = ['kafka-broker:9092']; + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers: bootstrapServers, + topic: kafkaTopic, + secret: secret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + // Error handling properties that should be inherited from StreamEventSourceProps + bisectBatchOnError: true, + retryAttempts: 5, + reportBatchItemFailures: true, + maxRecordAge: cdk.Duration.hours(1), + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + FunctionName: { + Ref: 'Fn9270CBC0', + }, + BatchSize: 100, + SelfManagedEventSource: { + Endpoints: { + KafkaBootstrapServers: bootstrapServers, + }, + }, + StartingPosition: 'TRIM_HORIZON', + Topics: [kafkaTopic], + // Verify error handling properties are correctly mapped to CloudFormation + BisectBatchOnFunctionError: true, + MaximumRetryAttempts: 5, + FunctionResponseTypes: ['ReportBatchItemFailures'], + MaximumRecordAgeInSeconds: 3600, // 1 hour in seconds + SourceAccessConfigurations: [ + { + Type: 'SASL_SCRAM_512_AUTH', + URI: { + Ref: 'SecretA720EF05', + }, + }, + ], + }); + }); + }); + + describe('PollerGroupName tests', () => { + test('ManagedKafkaEventSource with PollerGroupName', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource( + { + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + provisionedPollerConfig: { + minimumPollers: 2, + maximumPollers: 5, + pollerGroupName: 'managed-kafka-group', + }, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + FunctionName: { + Ref: 'Fn9270CBC0', + }, + BatchSize: 100, + StartingPosition: 'TRIM_HORIZON', + Topics: [ + kafkaTopic, + ], + ProvisionedPollerConfig: { + MinimumPollers: 2, + MaximumPollers: 5, + PollerGroupName: 'managed-kafka-group', + }, + }); + }); + + test('SelfManagedKafkaEventSource with PollerGroupName', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); + const bootstrapServers = ['kafka-broker:9092']; + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource( + { + bootstrapServers: bootstrapServers, + topic: kafkaTopic, + secret: secret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + provisionedPollerConfig: { + minimumPollers: 1, + maximumPollers: 4, + pollerGroupName: 'self-managed-kafka-group', + }, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + FunctionName: { + Ref: 'Fn9270CBC0', + }, + BatchSize: 100, + SelfManagedEventSource: { + Endpoints: { + KafkaBootstrapServers: bootstrapServers, + }, + }, + StartingPosition: 'TRIM_HORIZON', + Topics: [ + kafkaTopic, + ], + ProvisionedPollerConfig: { + MinimumPollers: 1, + MaximumPollers: 4, + PollerGroupName: 'self-managed-kafka-group', + }, + SourceAccessConfigurations: [ + { + Type: 'SASL_SCRAM_512_AUTH', + URI: { + Ref: 'SecretA720EF05', + }, + }, + ], + }); + }); + }); +}); + +describe('KafkaDlq integration', () => { + describe('ManagedKafkaEventSource with KafkaDlq', () => { + test('includes correct DestinationConfig in CloudFormation template', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + FunctionName: { + Ref: 'Fn9270CBC0', + }, + BatchSize: 100, + StartingPosition: 'TRIM_HORIZON', + Topics: [kafkaTopic], + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('works with kafka:// prefix in topic name', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + const kafkaDlq = new sources.KafkaDlq('kafka://failure-topic'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('works with complex topic names', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + const kafkaDlq = new sources.KafkaDlq('my.complex_failure-topic'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + DestinationConfig: { + OnFailure: { + Destination: 'kafka://my.complex_failure-topic', + }, + }, + }); + }); + }); + + describe('SelfManagedKafkaEventSource with KafkaDlq', () => { + test('includes correct DestinationConfig in CloudFormation template', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); + const bootstrapServers = ['kafka-broker:9092']; + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers, + topic: kafkaTopic, + secret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + FunctionName: { + Ref: 'Fn9270CBC0', + }, + BatchSize: 100, + SelfManagedEventSource: { + Endpoints: { + KafkaBootstrapServers: bootstrapServers, + }, + }, + StartingPosition: 'TRIM_HORIZON', + Topics: [kafkaTopic], + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + SourceAccessConfigurations: [ + { + Type: 'SASL_SCRAM_512_AUTH', + URI: { + Ref: 'SecretA720EF05', + }, + }, + ], + }); + }); + + test('works with kafka:// prefix in topic name', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); + const bootstrapServers = ['kafka-broker:9092']; + const kafkaDlq = new sources.KafkaDlq('kafka://failure-topic'); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers, + topic: kafkaTopic, + secret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('works with VPC configuration', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const bootstrapServers = ['kafka-broker:9092']; + const sg = SecurityGroup.fromSecurityGroupId(stack, 'SecurityGroup', 'sg-0123456789'); + const vpc = new Vpc(stack, 'Vpc'); + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + vpc, + vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS }, + securityGroup: sg, + onFailure: kafkaDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + SourceAccessConfigurations: [ + { + Type: 'VPC_SECURITY_GROUP', + URI: 'sg-0123456789', + }, + { + Type: 'VPC_SUBNET', + URI: { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + }, + { + Type: 'VPC_SUBNET', + URI: { + Ref: 'VpcPrivateSubnet2Subnet3788AAA1', + }, + }, + ], + }); + }); + }); +}); + +describe('backwards compatibility', () => { + describe('existing onFailure destinations continue to work', () => { + test('ManagedKafka with S3OnFailureDestination still works', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + const bucket = Bucket.fromBucketName(stack, 'BucketByName', 'my-bucket'); + const s3OnFailureDestination = new sources.S3OnFailureDestination(bucket); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: s3OnFailureDestination, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + DestinationConfig: { + OnFailure: { + Destination: { + 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':s3:::my-bucket']], + }, + }, + }, + }); + }); + + test('SelfManagedKafka with S3OnFailureDestination still works', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); + const bootstrapServers = ['kafka-broker:9092']; + const bucket = Bucket.fromBucketName(stack, 'BucketByName', 'my-bucket'); + const s3OnFailureDestination = new sources.S3OnFailureDestination(bucket); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers, + topic: kafkaTopic, + secret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: s3OnFailureDestination, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + SelfManagedEventSource: { + Endpoints: { + KafkaBootstrapServers: bootstrapServers, + }, + }, + DestinationConfig: { + OnFailure: { + Destination: { + 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':s3:::my-bucket']], + }, + }, + }, + }); + }); + + test('multiple destination types can be used in same stack', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn1 = new TestFunction(stack, 'Fn1'); + const fn2 = new TestFunction(stack, 'Fn2'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + + const bucket = Bucket.fromBucketName(stack, 'BucketByName', 'my-bucket'); + const s3OnFailureDestination = new sources.S3OnFailureDestination(bucket); + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN + fn1.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: s3OnFailureDestination, + })); + + fn2.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: 'another-topic', + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + })); + + // THEN + const template = Template.fromStack(stack); + + // Should have 2 event source mappings + template.resourceCountIs('AWS::Lambda::EventSourceMapping', 2); + + // Verify S3 destination exists + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + Topics: ['some-topic'], + DestinationConfig: { + OnFailure: { + Destination: { + 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':s3:::my-bucket']], + }, + }, + }, + }); + + // Verify Kafka destination exists + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + Topics: ['another-topic'], + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('ManagedKafka with SnsDlq still works', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + const topic = new Topic(stack, 'Topic'); + const snsDlq = new sources.SnsDlq(topic); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: snsDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + DestinationConfig: { + OnFailure: { + Destination: { + Ref: 'TopicBFC7AF6E', + }, + }, + }, + }); + }); + + test('SelfManagedKafka with SnsDlq still works', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); + const bootstrapServers = ['kafka-broker:9092']; + const topic = new Topic(stack, 'Topic'); + const snsDlq = new sources.SnsDlq(topic); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers, + topic: kafkaTopic, + secret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: snsDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + SelfManagedEventSource: { + Endpoints: { + KafkaBootstrapServers: bootstrapServers, + }, + }, + DestinationConfig: { + OnFailure: { + Destination: { + Ref: 'TopicBFC7AF6E', + }, + }, + }, + }); + }); + + test('ManagedKafka with SqsDlq still works', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + const queue = new Queue(stack, 'Queue'); + const sqsDlq = new sources.SqsDlq(queue); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: sqsDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + DestinationConfig: { + OnFailure: { + Destination: { + 'Fn::GetAtt': ['Queue4A7E3555', 'Arn'], + }, + }, + }, + }); + }); + + test('SelfManagedKafka with SqsDlq still works', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'some-topic'; + const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }); + const bootstrapServers = ['kafka-broker:9092']; + const queue = new Queue(stack, 'Queue'); + const sqsDlq = new sources.SqsDlq(queue); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers, + topic: kafkaTopic, + secret, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: sqsDlq, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + SelfManagedEventSource: { + Endpoints: { + KafkaBootstrapServers: bootstrapServers, + }, + }, + DestinationConfig: { + OnFailure: { + Destination: { + 'Fn::GetAtt': ['Queue4A7E3555', 'Arn'], + }, + }, + }, + }); + }); + + test('CloudFormation template generation works correctly for all destination types', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + + const bucket = Bucket.fromBucketName(stack, 'BucketByName', 'my-bucket'); + const s3OnFailureDestination = new sources.S3OnFailureDestination(bucket); + const topic = new Topic(stack, 'Topic'); + const snsDlq = new sources.SnsDlq(topic); + const queue = new Queue(stack, 'Queue'); + const sqsDlq = new sources.SqsDlq(queue); + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN - Add multiple event sources with different destination types + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: 'topic-with-s3', + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: s3OnFailureDestination, + })); + + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: 'topic-with-sns', + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: snsDlq, + })); + + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: 'topic-with-sqs', + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: sqsDlq, + })); + + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: 'topic-with-kafka', + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + })); + + // THEN - Verify all destinations are correctly rendered + const template = Template.fromStack(stack); + + // Should have 4 event source mappings + template.resourceCountIs('AWS::Lambda::EventSourceMapping', 4); + + // Verify S3 destination format + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + Topics: ['topic-with-s3'], + DestinationConfig: { + OnFailure: { + Destination: { + 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':s3:::my-bucket']], + }, + }, + }, + }); + + // Verify SNS destination format + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + Topics: ['topic-with-sns'], + DestinationConfig: { + OnFailure: { + Destination: { + Ref: 'TopicBFC7AF6E', + }, + }, + }, + }); + + // Verify SQS destination format + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + Topics: ['topic-with-sqs'], + DestinationConfig: { + OnFailure: { + Destination: { + 'Fn::GetAtt': ['Queue4A7E3555', 'Arn'], + }, + }, + }, + }); + + // Verify Kafka destination format + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + Topics: ['topic-with-kafka'], + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('no breaking changes to existing API surface', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'some-arn'; + const kafkaTopic = 'some-topic'; + + // Test that all existing destination types are still accepted by the API + const bucket = Bucket.fromBucketName(stack, 'BucketByName', 'my-bucket'); + const s3OnFailureDestination = new sources.S3OnFailureDestination(bucket); + const topic = new Topic(stack, 'Topic'); + const snsDlq = new sources.SnsDlq(topic); + const queue = new Queue(stack, 'Queue'); + const sqsDlq = new sources.SqsDlq(queue); + + // WHEN - These should all compile and work without errors + expect(() => { + new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: s3OnFailureDestination, + }); + }).not.toThrow(); + + expect(() => { + new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: snsDlq, + }); + }).not.toThrow(); + + expect(() => { + new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: sqsDlq, + }); + }).not.toThrow(); + + expect(() => { + new sources.SelfManagedKafkaEventSource({ + bootstrapServers: ['kafka-broker:9092'], + topic: kafkaTopic, + secret: new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' }), + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: s3OnFailureDestination, + }); + }).not.toThrow(); + + expect(() => { + new sources.SelfManagedKafkaEventSource({ + bootstrapServers: ['kafka-broker:9092'], + topic: kafkaTopic, + secret: new Secret(stack, 'Secret2', { secretName: 'AmazonMSK_KafkaSecret2' }), + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: snsDlq, + }); + }).not.toThrow(); + + expect(() => { + new sources.SelfManagedKafkaEventSource({ + bootstrapServers: ['kafka-broker:9092'], + topic: kafkaTopic, + secret: new Secret(stack, 'Secret3', { secretName: 'AmazonMSK_KafkaSecret3' }), + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: sqsDlq, + }); + }).not.toThrow(); + + // THEN - No exceptions should be thrown, indicating API compatibility + }); + }); +}); +describe('KafkaDlq CloudFormation Template Generation', () => { + describe('destination property mapping', () => { + test('KafkaDlq maps correctly to DestinationConfig.OnFailure.Destination for ManagedKafka', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlq, + })); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + FunctionName: { + Ref: 'Fn9270CBC0', + }, + Topics: [kafkaTopic], + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('KafkaDlq maps correctly to DestinationConfig.OnFailure.Destination for SelfManagedKafka', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'test-topic'; + const bootstrapServers = ['kafka-broker:9092']; + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + const vpc = new Vpc(stack, 'TestVpc'); + const sg = SecurityGroup.fromSecurityGroupId(stack, 'TestSG', 'sg-12345'); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlq, + vpc, + vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS }, + securityGroup: sg, + })); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + SelfManagedEventSource: { + Endpoints: { + KafkaBootstrapServers: bootstrapServers, + }, + }, + FunctionName: { + Ref: 'Fn9270CBC0', + }, + Topics: [kafkaTopic], + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('kafka:// prefix is preserved in generated CloudFormation templates', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + + // Test with explicit kafka:// prefix + const kafkaDlqWithPrefix = new sources.KafkaDlq('kafka://explicit-failure-topic'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlqWithPrefix, + })); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + DestinationConfig: { + OnFailure: { + Destination: 'kafka://explicit-failure-topic', + }, + }, + }); + }); + + test('proper structure matches AWS Lambda EventSourceMapping schema', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlq, + batchSize: 50, + maxBatchingWindow: cdk.Duration.seconds(5), + })); + + // THEN - Verify complete EventSourceMapping structure + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + FunctionName: { + Ref: 'Fn9270CBC0', + }, + BatchSize: 50, + MaximumBatchingWindowInSeconds: 5, + StartingPosition: 'LATEST', + Topics: [kafkaTopic], + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('KafkaDlq works alongside other EventSourceMapping properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN - Add event source with multiple properties + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.TRIM_HORIZON, + onFailure: kafkaDlq, + batchSize: 100, + maxBatchingWindow: cdk.Duration.seconds(10), + parallelizationFactor: 2, + filters: [ + lambda.FilterCriteria.filter({ + stringEquals: lambda.FilterRule.isEqual('test'), + }), + ], + })); + + // THEN - Verify all properties coexist properly + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + FunctionName: { + Ref: 'Fn9270CBC0', + }, + BatchSize: 100, + MaximumBatchingWindowInSeconds: 10, + ParallelizationFactor: 2, + StartingPosition: 'TRIM_HORIZON', + Topics: [kafkaTopic], + FilterCriteria: { + Filters: [ + { + Pattern: '{"stringEquals":["test"]}', + }, + ], + }, + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + }); +}); + +describe('template synthesis with various configurations', () => { + test('CDK synthesis with topic name without kafka:// prefix', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + const kafkaDlq = new sources.KafkaDlq('simple-topic-name'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlq, + })); + + // THEN - Should synthesize without errors and add kafka:// prefix + expect(() => Template.fromStack(stack)).not.toThrow(); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + DestinationConfig: { + OnFailure: { + Destination: 'kafka://simple-topic-name', + }, + }, + }); + }); + + test('CDK synthesis with topic name with kafka:// prefix', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + const kafkaDlq = new sources.KafkaDlq('kafka://prefixed-topic-name'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlq, + })); + + // THEN - Should synthesize without errors and not duplicate prefix + expect(() => Template.fromStack(stack)).not.toThrow(); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + DestinationConfig: { + OnFailure: { + Destination: 'kafka://prefixed-topic-name', + }, + }, + }); + }); + + test('CDK synthesis with complex topic names', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + + // Test various valid Kafka topic name formats + const topicNames = [ + 'app.errors.v1', // with dots + 'app_errors_v1', // with underscores + 'app-errors-v1', // with hyphens + 'MyApp123', // alphanumeric + 'kafka://pre.fixed_topic', // with prefix and mixed characters + ]; + + topicNames.forEach((topicName, index) => { + const kafkaDlq = new sources.KafkaDlq(topicName); + const fnName = `Fn${index}`; + const testFn = new TestFunction(stack, fnName); + + // WHEN + testFn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlq, + })); + }); + + // THEN - Should synthesize without errors + expect(() => Template.fromStack(stack)).not.toThrow(); + const template = Template.fromStack(stack); + + // Verify each destination is properly formatted + const expectedDestinations = [ + 'kafka://app.errors.v1', + 'kafka://app_errors_v1', + 'kafka://app-errors-v1', + 'kafka://MyApp123', + 'kafka://pre.fixed_topic', // prefix not duplicated + ]; + + expectedDestinations.forEach((expectedDestination) => { + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + DestinationConfig: { + OnFailure: { + Destination: expectedDestination, + }, + }, + }); + }); + }); + + test('no syntax errors in generated CloudFormation', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + + // WHEN + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlq, + })); + + // THEN - Template should be valid JSON + const template = Template.fromStack(stack); + const templateJson = template.toJSON(); + + expect(templateJson).toBeDefined(); + expect(typeof templateJson).toBe('object'); + expect(templateJson.Resources).toBeDefined(); + + // Verify the EventSourceMapping resource exists and is properly structured + const eventSourceMappings = Object.values(templateJson.Resources).filter( + (resource: any) => resource.Type === 'AWS::Lambda::EventSourceMapping', + ); + expect(eventSourceMappings).toHaveLength(1); + + const mapping = eventSourceMappings[0] as any; + expect(mapping.Properties.DestinationConfig.OnFailure.Destination).toBe('kafka://failure-topic'); + }); + + test('compatibility with other event source mapping properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const clusterArn = 'arn:aws:kafka:us-east-1:123456789012:cluster/test-cluster'; + const kafkaTopic = 'test-topic'; + const kafkaDlq = new sources.KafkaDlq('failure-topic'); + const secret = new Secret(stack, 'Secret', { secretName: 'KafkaSecret' }); + + // WHEN - Configure with many properties + fn.addEventSource(new sources.ManagedKafkaEventSource({ + clusterArn, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.AT_TIMESTAMP, + startingPositionTimestamp: 1640995200, + onFailure: kafkaDlq, + batchSize: 200, + maxBatchingWindow: cdk.Duration.seconds(15), + parallelizationFactor: 5, + secret, + filters: [ + lambda.FilterCriteria.filter({ + stringEquals: lambda.FilterRule.isEqual('important'), + numericEquals: lambda.FilterRule.isEqual(42), + }), + ], + })); + + // THEN - Should synthesize without errors and include all properties + expect(() => Template.fromStack(stack)).not.toThrow(); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + EventSourceArn: clusterArn, + Topics: [kafkaTopic], + StartingPosition: 'AT_TIMESTAMP', + StartingPositionTimestamp: 1640995200, + BatchSize: 200, + MaximumBatchingWindowInSeconds: 15, + ParallelizationFactor: 5, + SourceAccessConfigurations: [ + { + Type: 'SASL_SCRAM_512_AUTH', + URI: { + Ref: 'SecretA720EF05', + }, + }, + ], + FilterCriteria: { + Filters: [ + { + Pattern: '{"stringEquals":["important"],"numericEquals":[{"numeric":["=",42]}]}', + }, + ], + }, + DestinationConfig: { + OnFailure: { + Destination: 'kafka://failure-topic', + }, + }, + }); + }); + + test('SelfManagedKafka with various configurations', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new TestFunction(stack, 'Fn'); + const kafkaTopic = 'test-topic'; + const bootstrapServers = ['broker1:9092', 'broker2:9092']; + const kafkaDlq = new sources.KafkaDlq('self-managed-failure-topic'); + const secret = new Secret(stack, 'Secret', { secretName: 'SelfManagedKafkaSecret' }); + const vpc = new Vpc(stack, 'TestVpc'); + const sg = SecurityGroup.fromSecurityGroupId(stack, 'TestSG', 'sg-12345'); + + // WHEN + fn.addEventSource(new sources.SelfManagedKafkaEventSource({ + bootstrapServers, + topic: kafkaTopic, + startingPosition: lambda.StartingPosition.LATEST, + onFailure: kafkaDlq, + batchSize: 150, + maxBatchingWindow: cdk.Duration.seconds(20), + secret, + vpc, + vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS }, + securityGroup: sg, + filters: [ + lambda.FilterCriteria.filter({ + stringEquals: lambda.FilterRule.isEqual('processed'), + }), + ], + })); + + // THEN - Should synthesize without errors + expect(() => Template.fromStack(stack)).not.toThrow(); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::EventSourceMapping', { + SelfManagedEventSource: { + Endpoints: { + KafkaBootstrapServers: bootstrapServers, + }, + }, + Topics: [kafkaTopic], + StartingPosition: 'LATEST', + BatchSize: 150, + MaximumBatchingWindowInSeconds: 20, + FilterCriteria: { + Filters: [ + { + Pattern: '{"stringEquals":["processed"]}', + }, + ], + }, + DestinationConfig: { + OnFailure: { + Destination: 'kafka://self-managed-failure-topic', + }, + }, + }); }); }); diff --git a/packages/aws-cdk-lib/aws-lambda/lib/event-source-mapping.ts b/packages/aws-cdk-lib/aws-lambda/lib/event-source-mapping.ts index b89a3693013d3..ebc4cf06746ad 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/event-source-mapping.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/event-source-mapping.ts @@ -105,6 +105,14 @@ export interface ProvisionedPollerConfig { * @default - 200 */ readonly maximumPollers?: number; + /** + * An optional identifier that groups multiple ESMs to share EPU capacity + * and reduce costs. ESMs with the same PollerGroupName share compute + * resources. + * + * @default - not set, dedicated compute resource per event source. + */ + readonly pollerGroupName?: string; } export interface EventSourceMappingOptions {