Skip to content

Commit 48d536b

Browse files
author
Elad Ben-Israel
authored
feat(events-targets): LambdaFunction (#2350)
The `LambdaFunction` class can be used to bind an AWS Lambda function as an event rule target. Related #1663 BREAKING CHANGE: `lambda.Function` no longer implements `IEventRuleTarget`. Instead, use `@aws-cdk/aws-events-targets.LambdaFunction`.
1 parent 1069938 commit 48d536b

File tree

9 files changed

+117
-79
lines changed

9 files changed

+117
-79
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './sns';
2-
export * from './codebuild';
2+
export * from './codebuild';
3+
export * from './lambda';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import events = require('@aws-cdk/aws-events');
2+
import iam = require('@aws-cdk/aws-iam');
3+
import lambda = require('@aws-cdk/aws-lambda');
4+
5+
/**
6+
* Use an AWS Lambda function as an event rule target.
7+
*/
8+
export class LambdaFunction implements events.IEventRuleTarget {
9+
10+
/**
11+
* @param handler The lambda function
12+
*/
13+
constructor(private readonly handler: lambda.IFunction) {
14+
15+
}
16+
17+
/**
18+
* Returns a RuleTarget that can be used to trigger this Lambda as a
19+
* result from a CloudWatch event.
20+
*/
21+
public asEventRuleTarget(ruleArn: string, ruleId: string): events.EventRuleTargetProps {
22+
const permissionId = `AllowEventRule${ruleId}`;
23+
if (!this.handler.node.tryFindChild(permissionId)) {
24+
this.handler.addPermission(permissionId, {
25+
action: 'lambda:InvokeFunction',
26+
principal: new iam.ServicePrincipal('events.amazonaws.com'),
27+
sourceArn: ruleArn
28+
});
29+
}
30+
31+
return {
32+
id: this.handler.node.id,
33+
arn: this.handler.functionArn,
34+
};
35+
}
36+
}
File renamed without changes.

packages/@aws-cdk/aws-lambda/test/integ.events.ts renamed to packages/@aws-cdk/aws-events-targets/test/lambda/integ.events.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import events = require('@aws-cdk/aws-events');
2+
import lambda = require('@aws-cdk/aws-lambda');
23
import cdk = require('@aws-cdk/cdk');
3-
import lambda = require('../lib');
4+
import targets = require('../../lib');
45

56
const app = new cdk.App();
67

@@ -13,10 +14,10 @@ const fn = new lambda.Function(stack, 'MyFunc', {
1314
});
1415

1516
const timer = new events.EventRule(stack, 'Timer', { scheduleExpression: 'rate(1 minute)' });
16-
timer.addTarget(fn);
17+
timer.addTarget(new targets.LambdaFunction(fn));
1718

1819
const timer2 = new events.EventRule(stack, 'Timer2', { scheduleExpression: 'rate(2 minutes)' });
19-
timer2.addTarget(fn);
20+
timer2.addTarget(new targets.LambdaFunction(fn));
2021

2122
app.run();
2223

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { countResources, expect, haveResource } from '@aws-cdk/assert';
2+
import events = require('@aws-cdk/aws-events');
3+
import lambda = require('@aws-cdk/aws-lambda');
4+
import cdk = require('@aws-cdk/cdk');
5+
import targets = require('../../lib');
6+
7+
test('use lambda as an event rule target', () => {
8+
// GIVEN
9+
const stack = new cdk.Stack();
10+
const fn = newTestLambda(stack);
11+
const rule1 = new events.EventRule(stack, 'Rule', { scheduleExpression: 'rate(1 minute)' });
12+
const rule2 = new events.EventRule(stack, 'Rule2', { scheduleExpression: 'rate(5 minutes)' });
13+
14+
// WHEN
15+
rule1.addTarget(new targets.LambdaFunction(fn));
16+
rule2.addTarget(new targets.LambdaFunction(fn));
17+
18+
// THEN
19+
const lambdaId = "MyLambdaCCE802FB";
20+
21+
expect(stack).to(haveResource('AWS::Lambda::Permission', {
22+
Action: "lambda:InvokeFunction",
23+
FunctionName: {
24+
"Fn::GetAtt": [
25+
lambdaId,
26+
"Arn"
27+
]
28+
},
29+
Principal: "events.amazonaws.com",
30+
SourceArn: { "Fn::GetAtt": ["Rule4C995B7F", "Arn"] }
31+
}));
32+
33+
expect(stack).to(haveResource('AWS::Lambda::Permission', {
34+
Action: "lambda:InvokeFunction",
35+
FunctionName: {
36+
"Fn::GetAtt": [
37+
lambdaId,
38+
"Arn"
39+
]
40+
},
41+
Principal: "events.amazonaws.com",
42+
SourceArn: { "Fn::GetAtt": ["Rule270732244", "Arn"] }
43+
}));
44+
45+
expect(stack).to(countResources('AWS::Events::Rule', 2));
46+
expect(stack).to(haveResource('AWS::Events::Rule', {
47+
Targets: [
48+
{
49+
Arn: { "Fn::GetAtt": [lambdaId, "Arn"] },
50+
Id: "MyLambda"
51+
}
52+
]
53+
}));
54+
});
55+
56+
function newTestLambda(scope: cdk.Construct) {
57+
return new lambda.Function(scope, 'MyLambda', {
58+
code: new lambda.InlineCode('foo'),
59+
handler: 'bar',
60+
runtime: lambda.Runtime.Python27
61+
});
62+
}

packages/@aws-cdk/aws-events/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,5 @@ The following targets are supported:
7272

7373
* `targets.SnsTopic`: publish into an SNS topic when an event rule is triggered.
7474
* `targets.CodeBuildProject`: start a CodeBuild project when an event rule is triggered.
75+
* `targets.LambdaFunction`: invoke an AWS Lambda function when an event rule is triggered.
7576

packages/@aws-cdk/aws-lambda/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ granting permissions to other AWS accounts or organizations.
4040

4141
[Example of Lambda Layer usage](test/integ.layer-version.lit.ts)
4242

43+
## Event Rule Target
44+
45+
You can use an AWS Lambda function as a target for an Amazon CloudWatch event
46+
rule:
47+
48+
```ts
49+
import targets = require('@aws-cdk/aws-events-targets');
50+
rule.addTarget(new targets.LambdaFunction(myFunction));
51+
```
52+
4353
### Event Sources
4454

4555
AWS Lambda supports a [variety of event sources](https://docs.aws.amazon.com/lambda/latest/dg/invoking-lambda-function.html).

packages/@aws-cdk/aws-lambda/lib/function-base.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import cloudwatch = require('@aws-cdk/aws-cloudwatch');
22
import ec2 = require('@aws-cdk/aws-ec2');
3-
import events = require('@aws-cdk/aws-events');
43
import iam = require('@aws-cdk/aws-iam');
54
import logs = require('@aws-cdk/aws-logs');
65
import s3n = require('@aws-cdk/aws-s3-notifications');
@@ -11,7 +10,7 @@ import { IEventSource } from './event-source';
1110
import { CfnPermission } from './lambda.generated';
1211
import { Permission } from './permission';
1312

14-
export interface IFunction extends IResource, events.IEventRuleTarget, logs.ILogSubscriptionDestination,
13+
export interface IFunction extends IResource, logs.ILogSubscriptionDestination,
1514
s3n.IBucketNotificationDestination, ec2.IConnectable, stepfunctions.IStepFunctionsTaskResource, iam.IGrantable {
1615

1716
/**
@@ -215,26 +214,6 @@ export abstract class FunctionBase extends Resource implements IFunction {
215214
return !!this._connections;
216215
}
217216

218-
/**
219-
* Returns a RuleTarget that can be used to trigger this Lambda as a
220-
* result from a CloudWatch event.
221-
*/
222-
public asEventRuleTarget(ruleArn: string, ruleId: string): events.EventRuleTargetProps {
223-
const permissionId = `AllowEventRule${ruleId}`;
224-
if (!this.node.tryFindChild(permissionId)) {
225-
this.addPermission(permissionId, {
226-
action: 'lambda:InvokeFunction',
227-
principal: new iam.ServicePrincipal('events.amazonaws.com'),
228-
sourceArn: ruleArn
229-
});
230-
}
231-
232-
return {
233-
id: this.node.id,
234-
arn: this.functionArn,
235-
};
236-
}
237-
238217
/**
239218
* Grant the given identity permissions to invoke this Lambda
240219
*/

packages/@aws-cdk/aws-lambda/test/test.lambda.ts

Lines changed: 1 addition & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { countResources, expect, haveResource, MatchStyle, ResourcePart } from '@aws-cdk/assert';
2-
import events = require('@aws-cdk/aws-events');
1+
import { expect, haveResource, MatchStyle, ResourcePart } from '@aws-cdk/assert';
32
import iam = require('@aws-cdk/aws-iam');
43
import logs = require('@aws-cdk/aws-logs');
54
import sqs = require('@aws-cdk/aws-sqs');
@@ -257,57 +256,6 @@ export = {
257256
},
258257
},
259258

260-
'Lambda can serve as EventRule target, permission gets added'(test: Test) {
261-
// GIVEN
262-
const stack = new cdk.Stack();
263-
const fn = newTestLambda(stack);
264-
const rule1 = new events.EventRule(stack, 'Rule', { scheduleExpression: 'rate(1 minute)' });
265-
const rule2 = new events.EventRule(stack, 'Rule2', { scheduleExpression: 'rate(5 minutes)' });
266-
267-
// WHEN
268-
rule1.addTarget(fn);
269-
rule2.addTarget(fn);
270-
271-
// THEN
272-
const lambdaId = "MyLambdaCCE802FB";
273-
274-
expect(stack).to(haveResource('AWS::Lambda::Permission', {
275-
"Action": "lambda:InvokeFunction",
276-
"FunctionName": {
277-
"Fn::GetAtt": [
278-
lambdaId,
279-
"Arn"
280-
]
281-
},
282-
"Principal": "events.amazonaws.com",
283-
"SourceArn": { "Fn::GetAtt": [ "Rule4C995B7F", "Arn" ] }
284-
}));
285-
286-
expect(stack).to(haveResource('AWS::Lambda::Permission', {
287-
"Action": "lambda:InvokeFunction",
288-
"FunctionName": {
289-
"Fn::GetAtt": [
290-
lambdaId,
291-
"Arn"
292-
]
293-
},
294-
"Principal": "events.amazonaws.com",
295-
"SourceArn": { "Fn::GetAtt": [ "Rule270732244", "Arn" ] }
296-
}));
297-
298-
expect(stack).to(countResources('AWS::Events::Rule', 2));
299-
expect(stack).to(haveResource('AWS::Events::Rule', {
300-
"Targets": [
301-
{
302-
"Arn": { "Fn::GetAtt": [ lambdaId, "Arn" ] },
303-
"Id": "MyLambda"
304-
}
305-
]
306-
}));
307-
308-
test.done();
309-
},
310-
311259
'Lambda code can be read from a local directory via an asset'(test: Test) {
312260
// GIVEN
313261
const stack = new cdk.Stack();

0 commit comments

Comments
 (0)