Skip to content

Commit

Permalink
Add more test resource coverage (#182)
Browse files Browse the repository at this point in the history
This PR adds some additional examples taken from [cdk
patterns](https://cdkpatterns.com/).

It adds coverage for these additional resources.
```
aws-native:sns:Topic
aws-native:sns:Subscription
aws-native:lambda:EventSourceMapping
aws:lambda:Permission
aws-native:iam:Role
aws-native:apigateway:Model
aws-native:apigateway:RestApi
aws-native:apigateway:Deployment
aws-native:apigateway:Stage
aws-native:apigateway:Method
aws-native:apigateway:Resource
aws-native:sqs:Queue
aws:sqs:QueuePolicy
aws-native:events:Rule
aws-native:dynamodb:GlobalTable
```

I am also introducing a workaround for #173 for a couple of the
ApiGateway resources since those are top 20 library resources. We can
easily remove this workaround once the complete fix done.
  • Loading branch information
corymhall authored Oct 29, 2024
1 parent 456439c commit c36cb89
Show file tree
Hide file tree
Showing 41 changed files with 1,007 additions and 2 deletions.
3 changes: 3 additions & 0 deletions examples/eventbridge-atm/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: pulumi-aws-eventbridge-atm
runtime: nodejs
description: Eventbridge ATM example for CDK
32 changes: 32 additions & 0 deletions examples/eventbridge-atm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# The EventBridge ATM

> NOTE: converted from https://github.com/cdk-patterns/serverless/blob/main/the-eventbridge-atm/typescript/README.md
This is an example CDK stack to deploy the code from this blogpost by [James
Beswick](https://twitter.com/jbesw)-
https://aws.amazon.com/blogs/compute/integrating-amazon-eventbridge-into-your-serverless-applications/

In this example, a banking application for automated teller machine (ATM)
produces events about transactions. It sends the events to EventBridge, which
then uses rules defined by the application to route accordingly. There are
three downstream services consuming a subset of these events.

![Architecture](img/amazon-eventbridge-custom-application-2.png)

## When You Would Use This Pattern

EventBridge is an awesome centralised service for routing events between
various consumers based on rules. You could set up an EventBridge within your
domain and then accessing events within that domain is as easy as a rule in
EventBridge, this significantly cuts down on the number of coupled interactions
you have between your various services.

## How to test pattern

After deployment you will have an api gateway where hitting any endpoint
triggers the events to be sent to EventBridge defined in
lambdas/atmProducer/events.js

* All Approved transactions go to consumer 1 NY Transactions go to consumer 2
* Declined transactions go to consumer 3

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/eventbridge-atm/img/arch-small.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 118 additions & 0 deletions examples/eventbridge-atm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import * as path from 'path';
import * as pulumicdk from '@pulumi/cdk';
import {
aws_apigateway as apigw,
aws_events as events,
aws_iam as iam,
aws_events_targets as events_targets,
aws_lambda as lambda,
aws_lambda_nodejs as lambda_nodejs,
} from 'aws-cdk-lib';

class EventbridgeAtmStack extends pulumicdk.Stack {
constructor(id: string) {
super(id);
this.node.setContext('@aws-cdk/aws-apigateway:disableCloudWatchRole', 'true');

/**
* Producer Lambda
*/
const atmProducerLambda = new lambda_nodejs.NodejsFunction(this, 'atmProducerLambda', {
runtime: lambda.Runtime.NODEJS_LATEST,
entry: path.join(__dirname, 'lambda-fns/atmProducer/handler.ts'),
handler: 'handler.handler',
});

const eventPolicy = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: ['*'],
actions: ['events:PutEvents'],
});

atmProducerLambda.addToRolePolicy(eventPolicy);

/**
* Approved Transaction Consumer
*/
const atmConsumer1Lambda = new lambda.Function(this, 'atmConsumer1Lambda', {
runtime: lambda.Runtime.NODEJS_LATEST,
code: lambda.Code.fromAsset('lambda-fns/atmConsumer'),
handler: 'handler.case1Handler',
});

const atmConsumer1LambdaRule = new events.Rule(this, 'atmConsumer1LambdaRule', {
description: 'Approved transactions',
eventPattern: {
source: ['custom.myATMapp'],
detailType: ['transaction'],
detail: {
result: ['approved'],
},
},
});

atmConsumer1LambdaRule.addTarget(new events_targets.LambdaFunction(atmConsumer1Lambda));

/**
* NY Prefix Consumer
*/
const atmConsumer2Lambda = new lambda.Function(this, 'atmConsumer2Lambda', {
runtime: lambda.Runtime.NODEJS_LATEST,
code: lambda.Code.fromAsset('lambda-fns/atmConsumer'),
handler: 'handler.case2Handler',
});

const atmConsumer2LambdaRule = new events.Rule(this, 'atmConsumer2LambdaRule', {
eventPattern: {
source: ['custom.myATMapp'],
detailType: ['transaction'],
detail: {
location: [
{
prefix: 'NY-',
},
],
},
},
});

atmConsumer2LambdaRule.addTarget(new events_targets.LambdaFunction(atmConsumer2Lambda));

/**
* Not Approved Consumer
*/
const atmConsumer3Lambda = new lambda.Function(this, 'atmConsumer3Lambda', {
runtime: lambda.Runtime.NODEJS_LATEST,
code: lambda.Code.fromAsset('lambda-fns/atmConsumer'),
handler: 'handler.case3Handler',
});

const atmConsumer3LambdaRule = new events.Rule(this, 'atmConsumer3LambdaRule', {
eventPattern: {
source: ['custom.myATMapp'],
detailType: ['transaction'],
detail: {
result: [
{
'anything-but': 'approved',
},
],
},
},
});

atmConsumer3LambdaRule.addTarget(new events_targets.LambdaFunction(atmConsumer3Lambda));

/**
* API Gateway proxy integration
*/
// defines an API Gateway REST API resource backed by our "atmProducerLambda" function.
new apigw.LambdaRestApi(this, 'Endpoint', {
handler: atmProducerLambda,
});

this.synth();
}
}

new EventbridgeAtmStack('eventbridge-sns-stack');
31 changes: 31 additions & 0 deletions examples/eventbridge-atm/lambda-fns/atmConsumer/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// The consuming service (target) Lambda functions

exports.case1Handler = async (event) => {
console.log('--- Approved transactions ---')
console.log(JSON.stringify(event, null, 2))
}

exports.case2Handler = async (event) => {
console.log('--- NY location transactions ---')
console.log(JSON.stringify(event, null, 2))
}

exports.case3Handler = async (event) => {
console.log('--- Unapproved transactions ---')
console.log(JSON.stringify(event, null, 2))
}
77 changes: 77 additions & 0 deletions examples/eventbridge-atm/lambda-fns/atmProducer/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// You can send up to 10 events to Amazon EventBridge simulataneously.

export const params = {
Entries: [
{
// Event envelope fields
Source: 'custom.myATMapp',
EventBusName: 'default',
DetailType: 'transaction',
Time: new Date(),

// Main event body
Detail: JSON.stringify({
action: 'withdrawal',
location: 'MA-BOS-01',
amount: 300,
result: 'approved',
transactionId: '123456',
cardPresent: true,
partnerBank: 'Example Bank',
remainingFunds: 722.34,
}),
},
{
// Event envelope fields
Source: 'custom.myATMapp',
EventBusName: 'default',
DetailType: 'transaction',
Time: new Date(),

// Main event body
Detail: JSON.stringify({
action: 'withdrawal',
location: 'NY-NYC-001',
amount: 20,
result: 'approved',
transactionId: '123457',
cardPresent: true,
partnerBank: 'Example Bank',
remainingFunds: 212.52,
}),
},
{
// Event envelope fields
Source: 'custom.myATMapp',
EventBusName: 'default',
DetailType: 'transaction',
Time: new Date(),

// Main event body
Detail: JSON.stringify({
action: 'withdrawal',
location: 'NY-NYC-002',
amount: 60,
result: 'denied',
transactionId: '123458',
cardPresent: true,
remainingFunds: 5.77,
}),
},
],
};
44 changes: 44 additions & 0 deletions examples/eventbridge-atm/lambda-fns/atmProducer/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { EventBridgeClient, PutEventsCommand } from '@aws-sdk/client-eventbridge';
import { params } from './events';
import { APIGatewayProxyHandler } from '@types/aws-lambda';
const client = new EventBridgeClient();

export const handler: APIGatewayProxyHandler = async function (event, context) {
// Do some work...
// And now create the event...

console.log('--- Params ---');
console.log(params);
const result = await client.send(new PutEventsCommand(params));

console.log('--- Response ---');
console.log(result);

return sendRes(200, 'You have sent the events to EventBridge!');
};

const sendRes = (status: number, body: string) => {
const response = {
statusCode: status,
headers: {
'Content-Type': 'text/html',
},
body: body,
};
return response;
};
16 changes: 16 additions & 0 deletions examples/eventbridge-atm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "pulumi-aws-cdk",
"devDependencies": {
"@types/node": "^20.0.0"
},
"dependencies": {
"@aws-sdk/client-eventbridge": "^3.678.0",
"@pulumi/aws-native": "^1.0.0",
"@pulumi/cdk": "^0.5.0",
"@pulumi/pulumi": "^3.0.0",
"@types/aws-lambda": "^8.10.145",
"aws-cdk-lib": "2.149.0",
"constructs": "10.3.0",
"esbuild": "^0.24.0"
}
}
27 changes: 27 additions & 0 deletions examples/examples_nodejs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,33 @@ func TestEventBridgeSNS(t *testing.T) {
integration.ProgramTest(t, &test)
}

func TestEventBridgeAtm(t *testing.T) {
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: filepath.Join(getCwd(t), "eventbridge-atm"),
})

integration.ProgramTest(t, &test)
}

func TestScalableWebhook(t *testing.T) {
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: filepath.Join(getCwd(t), "scalable-webhook"),
})

integration.ProgramTest(t, &test)
}

func TestTheBigFan(t *testing.T) {
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: filepath.Join(getCwd(t), "the-big-fan"),
})

integration.ProgramTest(t, &test)
}

func TestAPIWebsocketLambdaDynamoDB(t *testing.T) {
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Expand Down
3 changes: 3 additions & 0 deletions examples/scalable-webhook/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: pulumi-aws-eventbridge-atm
runtime: nodejs
description: Eventbridge ATM example for CDK
Loading

0 comments on commit c36cb89

Please sign in to comment.