Skip to content

Commit c575dde

Browse files
authored
feat(lambda-event-sources): added filters support to kafka sources (#26366)
This change grants the possibility to [specify event filtering](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html#filtering-msk-smak) on the `ManagedKafkaEventSource` and `SelfManagedKafkaEventSource` constructs via the `filters` property. Closes #26348. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 2f8df43 commit c575dde

File tree

5 files changed

+126
-0
lines changed

5 files changed

+126
-0
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged.js.snapshot/lambda-event-source-kafka-self-managed.template.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@
8585
"FKafkaEventSource838c4d5ff3c99c1a617120adfca83e5bmytesttopic1E7A7798": {
8686
"Type": "AWS::Lambda::EventSourceMapping",
8787
"Properties": {
88+
"FilterCriteria": {
89+
"Filters": [{
90+
"Pattern":"{\"numericEquals\":[{\"numeric\":[\"=\",1]}]}"
91+
}]
92+
},
8893
"FunctionName": {
8994
"Ref": "FC4345940"
9095
},

packages/@aws-cdk-testing/framework-integ/test/aws-lambda-event-sources/test/integ.kafka-selfmanaged.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ zp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==
5353
authenticationMethod: AuthenticationMethod.CLIENT_CERTIFICATE_TLS_AUTH,
5454
rootCACertificate: rootCASecret,
5555
startingPosition: lambda.StartingPosition.TRIM_HORIZON,
56+
filters: [
57+
lambda.FilterCriteria.filter({
58+
numericEquals: lambda.FilterRule.isEqual(1),
59+
}),
60+
],
5661
}),
5762
);
5863
}

packages/aws-cdk-lib/aws-lambda-event-sources/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,30 @@ myFunction.addEventSource(new SelfManagedKafkaEventSource({
275275

276276
If your self managed Kafka cluster is only reachable via VPC also configure `vpc` `vpcSubnets` and `securityGroup`.
277277

278+
You can specify [event filtering](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html#filtering-msk-smak)
279+
for managed and self managed Kafka clusters using the `filters` property:
280+
```ts
281+
import { ManagedKafkaEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
282+
283+
// Your MSK cluster arn
284+
const clusterArn = 'arn:aws:kafka:us-east-1:0123456789019:cluster/SalesCluster/abcd1234-abcd-cafe-abab-9876543210ab-4';
285+
286+
// The Kafka topic you want to subscribe to
287+
const topic = 'some-cool-topic';
288+
289+
declare const myFunction: lambda.Function;
290+
myFunction.addEventSource(new ManagedKafkaEventSource({
291+
clusterArn,
292+
topic,
293+
startingPosition: lambda.StartingPosition.TRIM_HORIZON,
294+
filters: [
295+
lambda.FilterCriteria.filter({
296+
stringEquals: lambda.FilterRule.isEqual('test'),
297+
}),
298+
],
299+
}));
300+
```
301+
278302
## Roadmap
279303

280304
Eventually, this module will support all the event sources described under

packages/aws-cdk-lib/aws-lambda-event-sources/lib/kafka.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ export interface KafkaEventSourceProps extends BaseStreamEventSourceProps {
2929
* @default - none
3030
*/
3131
readonly consumerGroupId?: string;
32+
33+
/**
34+
* Add filter criteria to Event Source
35+
* @see https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html
36+
*
37+
* @default - none
38+
*/
39+
readonly filters?: Array<{[key: string]: any}>
3240
}
3341

3442
/**
@@ -130,6 +138,7 @@ export class ManagedKafkaEventSource extends StreamEventSource {
130138
`KafkaEventSource:${Names.nodeUniqueId(target.node)}${this.innerProps.topic}`,
131139
this.enrichMappingOptions({
132140
eventSourceArn: this.innerProps.clusterArn,
141+
filters: this.innerProps.filters,
133142
startingPosition: this.innerProps.startingPosition,
134143
sourceAccessConfigurations: this.sourceAccessConfigurations(),
135144
kafkaTopic: this.innerProps.topic,
@@ -217,6 +226,7 @@ export class SelfManagedKafkaEventSource extends StreamEventSource {
217226
target.addEventSourceMapping(
218227
this.mappingId(target),
219228
this.enrichMappingOptions({
229+
filters: this.innerProps.filters,
220230
kafkaBootstrapServers: this.innerProps.bootstrapServers,
221231
kafkaTopic: this.innerProps.topic,
222232
kafkaConsumerGroupId: this.innerProps.consumerGroupId,

packages/aws-cdk-lib/aws-lambda-event-sources/test/kafka.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,46 @@ describe('KafkaEventSource', () => {
132132
});
133133

134134
});
135+
136+
test('with filters', () => {
137+
// GIVEN
138+
const stack = new cdk.Stack();
139+
const fn = new TestFunction(stack, 'Fn');
140+
const clusterArn = 'some-arn';
141+
const kafkaTopic = 'some-topic';
142+
143+
// WHEN
144+
fn.addEventSource(new sources.ManagedKafkaEventSource(
145+
{
146+
clusterArn,
147+
topic: kafkaTopic,
148+
startingPosition: lambda.StartingPosition.TRIM_HORIZON,
149+
filters: [
150+
lambda.FilterCriteria.filter({
151+
orFilter: lambda.FilterRule.or('one', 'two'),
152+
stringEquals: lambda.FilterRule.isEqual('test'),
153+
}),
154+
lambda.FilterCriteria.filter({
155+
numericEquals: lambda.FilterRule.isEqual(1),
156+
}),
157+
],
158+
}));
159+
160+
// THEN
161+
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', {
162+
FilterCriteria: {
163+
Filters: [
164+
{
165+
Pattern: '{"orFilter":["one","two"],"stringEquals":["test"]}',
166+
},
167+
{
168+
Pattern: '{"numericEquals":[{"numeric":["=",1]}]}',
169+
},
170+
],
171+
},
172+
});
173+
});
174+
135175
});
136176

137177
describe('self-managed kafka', () => {
@@ -202,6 +242,48 @@ describe('KafkaEventSource', () => {
202242
});
203243

204244
});
245+
246+
test('with filters', () => {
247+
// GIVEN
248+
const stack = new cdk.Stack();
249+
const fn = new TestFunction(stack, 'Fn');
250+
const kafkaTopic = 'some-topic';
251+
const secret = new Secret(stack, 'Secret', { secretName: 'AmazonMSK_KafkaSecret' });
252+
const bootstrapServers = ['kafka-broker:9092'];
253+
254+
// WHEN
255+
fn.addEventSource(new sources.SelfManagedKafkaEventSource(
256+
{
257+
bootstrapServers: bootstrapServers,
258+
topic: kafkaTopic,
259+
secret: secret,
260+
startingPosition: lambda.StartingPosition.TRIM_HORIZON,
261+
filters: [
262+
lambda.FilterCriteria.filter({
263+
orFilter: lambda.FilterRule.or('one', 'two'),
264+
stringEquals: lambda.FilterRule.isEqual('test'),
265+
}),
266+
lambda.FilterCriteria.filter({
267+
numericEquals: lambda.FilterRule.isEqual(1),
268+
}),
269+
],
270+
}));
271+
272+
// THEN
273+
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', {
274+
FilterCriteria: {
275+
Filters: [
276+
{
277+
Pattern: '{"orFilter":["one","two"],"stringEquals":["test"]}',
278+
},
279+
{
280+
Pattern: '{"numericEquals":[{"numeric":["=",1]}]}',
281+
},
282+
],
283+
},
284+
});
285+
});
286+
205287
test('without vpc, secret must be set', () => {
206288
const stack = new cdk.Stack();
207289
const fn = new TestFunction(stack, 'Fn');

0 commit comments

Comments
 (0)