-
Notifications
You must be signed in to change notification settings - Fork 880
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds aws-ts-lambda-slack example (#1709)
Co-authored-by: diana esteves <[email protected]>
- Loading branch information
Showing
7 changed files
with
244 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/bin/ | ||
/node_modules/ | ||
Pulumi.dev.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
name: ${PROJECT} | ||
description: ${DESCRIPTION} | ||
runtime: nodejs | ||
|
||
template: | ||
description: Deploy a Slack webhook Lambda function. | ||
config: | ||
aws:region: | ||
description: AWS Region | ||
default: us-west-2 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# AWS Lambda for Slack Notification | ||
|
||
A Pulumi example to: | ||
|
||
- Creates an AWS Lambda function to post a message on Slack via a Webhook URL. | ||
- Adds an AWS API Gateway so the Lambda can be invoked externally, e.g, via GitHub Webhooks. | ||
- Uses a Pulumi ESC Environment to dynamically retrieve AWS OIDC Credentials and the Slack URL from AWS Secrets Manager. | ||
|
||
Last update: September 2024 | ||
|
||
## 📋 Pre-requisites | ||
|
||
- AWS OIDC configured in an Pulumi ESC Environment | ||
- AWS Secrets Manager with a Slack Webhook URL secret | ||
- A properly configured Slack Webhook URL | ||
- [Pulumi CLI](https://www.pulumi.com/docs/get-started/install/) | ||
- [Pulumi Cloud account](https://app.pulumi.com/signup) | ||
- [npm](https://www.npmjs.com/get-npm) | ||
|
||
## 👩🏫 Get started | ||
|
||
This Pulumi example is written as a template. It is meant to be copied via `pulumi new` | ||
|
||
```bash | ||
# login to your Pulumi Cloud if you haven't already | ||
$ pulumi login | ||
|
||
# create a new dir and cd to it | ||
$ mkdir my-slack-demo | ||
$ cd my-slack-demo | ||
|
||
# start your pulumi project | ||
$ pulumi new https://github.com/pulumi/examples/aws-ts-lambda-slack | ||
``` | ||
|
||
```bash | ||
# Add your Pulumi ESC Environment | ||
$ pulumi config env add YOUR_ESC_ENV --yes --non-interactive | ||
$ pulumi up | ||
# select 'yes' to confirm the expected changes | ||
# 🎉 Ta-Da! | ||
``` | ||
|
||
## 🧹 Clean up | ||
|
||
To clean up your infrastructure, run: | ||
|
||
```bash | ||
$ pulumi destroy | ||
# select 'yes' to confirm the expected changes | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
|
||
// Copyright 2024, Pulumi Corporation. All rights reserved. | ||
|
||
import * as aws from "@pulumi/aws"; | ||
import * as pulumi from "@pulumi/pulumi"; | ||
|
||
const config = new pulumi.Config(); | ||
const slackWebhookUrl = config.requireSecret("slackWebhookUrl"); | ||
|
||
// Create an IAM role for the Lambda function | ||
const lambdaRole = new aws.iam.Role("lambdaRole", { | ||
assumeRolePolicy: { | ||
Version: "2012-10-17", | ||
Statement: [{ | ||
Action: "sts:AssumeRole", | ||
Principal: { | ||
Service: "lambda.amazonaws.com", | ||
}, | ||
Effect: "Allow", | ||
}], | ||
}, | ||
}); | ||
|
||
// Attach a policy to the role to allow Lambda to log to CloudWatch | ||
const rpa = new aws.iam.RolePolicyAttachment("lambdaRolePolicy", { | ||
role: lambdaRole.name, | ||
policyArn: aws.iam.ManagedPolicies.AWSLambdaBasicExecutionRole, | ||
}); | ||
|
||
// Create the Lambda function | ||
const lambdaFunction = new aws.lambda.Function("myLambda", { | ||
// https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtimes-supported | ||
runtime: "nodejs20.x", | ||
role: lambdaRole.arn, | ||
handler: "index.handler", | ||
code: new pulumi.asset.AssetArchive({ | ||
".": new pulumi.asset.FileArchive("./lambda"), | ||
}), | ||
environment: { | ||
variables: { | ||
"SLACK_WEBHOOK_URL": slackWebhookUrl, | ||
}, | ||
}, | ||
memorySize: 128, | ||
timeout: 30, | ||
tags: { | ||
"Environment": "dev", | ||
}, | ||
}); | ||
|
||
// Export the Lambda function name | ||
// export const lambdaFunctionName = lambdaFunction.name; | ||
|
||
// Create an API Gateway | ||
const api = new aws.apigateway.RestApi("myApi", { | ||
description: "API Gateway for Lambda function", | ||
}); | ||
|
||
|
||
// Create a root resource | ||
const rootResource = api.rootResourceId; | ||
|
||
// Create a method for the root resource | ||
const rootMethod = new aws.apigateway.Method("rootMethod", { | ||
restApi: api.id, | ||
resourceId: rootResource, | ||
httpMethod: "ANY", | ||
authorization: "NONE", | ||
}); | ||
|
||
// Integrate the Lambda function with the root method | ||
const rootIntegration = new aws.apigateway.Integration("rootIntegration", { | ||
restApi: api.id, | ||
resourceId: rootResource, | ||
httpMethod: rootMethod.httpMethod, | ||
integrationHttpMethod: "POST", | ||
type: "AWS_PROXY", | ||
uri: lambdaFunction.invokeArn, | ||
}); | ||
|
||
// Grant API Gateway permission to invoke the Lambda function | ||
const lambdaPermission = new aws.lambda.Permission("apiGatewayPermission", { | ||
action: "lambda:InvokeFunction", | ||
function: lambdaFunction.arn, | ||
principal: "apigateway.amazonaws.com", | ||
sourceArn: pulumi.interpolate`${api.executionArn}/*/*`, | ||
}); | ||
|
||
// Deploy the API | ||
const deployment = new aws.apigateway.Deployment("myDeployment", { | ||
restApi: api.id, | ||
stageName: "dev", | ||
}, { dependsOn: [rootIntegration] }); | ||
|
||
// Export the URL of the API | ||
export const url = pulumi.interpolate`${deployment.invokeUrl}`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
const https = require('https'); | ||
|
||
exports.handler = async (event) => { | ||
// Get the Slack webhook URL from environment variables | ||
const slackWebhookUrl = process.env.SLACK_WEBHOOK_URL; | ||
|
||
// Define the message payload | ||
const slackMessage = JSON.stringify({ | ||
text: event.body | ||
}); | ||
|
||
// Slack Webhook URL parsed | ||
const url = new URL(slackWebhookUrl); | ||
|
||
const options = { | ||
hostname: url.hostname, | ||
path: url.pathname, | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'Content-Length': slackMessage.length | ||
} | ||
}; | ||
|
||
// Create a promise to post the message | ||
return new Promise((resolve, reject) => { | ||
const req = https.request(options, (res) => { | ||
let response = ''; | ||
|
||
res.on('data', (chunk) => { | ||
response += chunk; | ||
}); | ||
|
||
res.on('end', () => { | ||
resolve({ | ||
statusCode: res.statusCode, | ||
body: response | ||
}); | ||
}); | ||
}); | ||
|
||
req.on('error', (error) => { | ||
reject({ | ||
statusCode: 500, | ||
body: JSON.stringify(error) | ||
}); | ||
}); | ||
|
||
// Send the Slack message | ||
req.write(slackMessage); | ||
req.end(); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"name": "aws-ts-lambda-slack", | ||
"main": "index.ts", | ||
"devDependencies": { | ||
"@types/node": "^22", | ||
"typescript": "^5.6.2" | ||
}, | ||
"dependencies": { | ||
"@pulumi/aws": "^6.52.0", | ||
"@pulumi/pulumi": "^3.133.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"compilerOptions": { | ||
"strict": true, | ||
"outDir": "bin", | ||
"target": "es2020", | ||
"module": "commonjs", | ||
"moduleResolution": "node", | ||
"sourceMap": true, | ||
"experimentalDecorators": true, | ||
"pretty": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noImplicitReturns": true, | ||
"forceConsistentCasingInFileNames": true | ||
}, | ||
"files": [ | ||
"index.ts" | ||
] | ||
} |