condition check lambda
This commit is contained in:
225
infrastructure/cdk/lib/condition-check-lambda-stack.ts
Normal file
225
infrastructure/cdk/lib/condition-check-lambda-stack.ts
Normal file
@@ -0,0 +1,225 @@
|
||||
import * as cdk from "aws-cdk-lib";
|
||||
import * as lambda from "aws-cdk-lib/aws-lambda";
|
||||
import * as iam from "aws-cdk-lib/aws-iam";
|
||||
import * as scheduler from "aws-cdk-lib/aws-scheduler";
|
||||
import * as sqs from "aws-cdk-lib/aws-sqs";
|
||||
import { Construct } from "constructs";
|
||||
import * as path from "path";
|
||||
|
||||
interface ConditionCheckLambdaStackProps extends cdk.StackProps {
|
||||
/**
|
||||
* Environment name (staging, prod)
|
||||
*/
|
||||
environment: string;
|
||||
|
||||
/**
|
||||
* Database URL for the Lambda
|
||||
*/
|
||||
databaseUrl: string;
|
||||
|
||||
/**
|
||||
* Frontend URL for email links
|
||||
*/
|
||||
frontendUrl: string;
|
||||
|
||||
/**
|
||||
* SES sender email
|
||||
*/
|
||||
sesFromEmail: string;
|
||||
|
||||
/**
|
||||
* SES sender name
|
||||
*/
|
||||
sesFromName?: string;
|
||||
|
||||
/**
|
||||
* Whether emails are enabled
|
||||
*/
|
||||
emailEnabled?: boolean;
|
||||
}
|
||||
|
||||
export class ConditionCheckLambdaStack extends cdk.Stack {
|
||||
/**
|
||||
* The Lambda function for condition check reminders
|
||||
*/
|
||||
public readonly lambdaFunction: lambda.Function;
|
||||
|
||||
/**
|
||||
* The EventBridge Scheduler group for condition check schedules
|
||||
*/
|
||||
public readonly scheduleGroup: scheduler.CfnScheduleGroup;
|
||||
|
||||
/**
|
||||
* Dead letter queue for failed Lambda invocations
|
||||
*/
|
||||
public readonly deadLetterQueue: sqs.Queue;
|
||||
|
||||
/**
|
||||
* IAM role for EventBridge Scheduler to invoke Lambda
|
||||
*/
|
||||
public readonly schedulerRole: iam.Role;
|
||||
|
||||
constructor(
|
||||
scope: Construct,
|
||||
id: string,
|
||||
props: ConditionCheckLambdaStackProps
|
||||
) {
|
||||
super(scope, id, props);
|
||||
|
||||
const {
|
||||
environment,
|
||||
databaseUrl,
|
||||
frontendUrl,
|
||||
sesFromEmail,
|
||||
sesFromName = "Village Share",
|
||||
emailEnabled = true,
|
||||
} = props;
|
||||
|
||||
// Dead Letter Queue for failed Lambda invocations
|
||||
this.deadLetterQueue = new sqs.Queue(this, "ConditionCheckDLQ", {
|
||||
queueName: `condition-check-reminder-dlq-${environment}`,
|
||||
retentionPeriod: cdk.Duration.days(14),
|
||||
});
|
||||
|
||||
// Lambda execution role
|
||||
const lambdaRole = new iam.Role(this, "ConditionCheckLambdaRole", {
|
||||
roleName: `condition-check-lambda-role-${environment}`,
|
||||
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
|
||||
description: "Execution role for Condition Check Reminder Lambda",
|
||||
});
|
||||
|
||||
// CloudWatch Logs permissions
|
||||
lambdaRole.addToPolicy(
|
||||
new iam.PolicyStatement({
|
||||
effect: iam.Effect.ALLOW,
|
||||
actions: [
|
||||
"logs:CreateLogGroup",
|
||||
"logs:CreateLogStream",
|
||||
"logs:PutLogEvents",
|
||||
],
|
||||
resources: ["*"],
|
||||
})
|
||||
);
|
||||
|
||||
// SES permissions for sending emails
|
||||
lambdaRole.addToPolicy(
|
||||
new iam.PolicyStatement({
|
||||
effect: iam.Effect.ALLOW,
|
||||
actions: ["ses:SendEmail", "ses:SendRawEmail"],
|
||||
resources: ["*"],
|
||||
})
|
||||
);
|
||||
|
||||
// EventBridge Scheduler permissions (for self-cleanup)
|
||||
lambdaRole.addToPolicy(
|
||||
new iam.PolicyStatement({
|
||||
effect: iam.Effect.ALLOW,
|
||||
actions: ["scheduler:DeleteSchedule"],
|
||||
resources: [
|
||||
`arn:aws:scheduler:${this.region}:${this.account}:schedule/condition-check-reminders-${environment}/*`,
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
// Lambda function
|
||||
this.lambdaFunction = new lambda.Function(
|
||||
this,
|
||||
"ConditionCheckReminderLambda",
|
||||
{
|
||||
functionName: `condition-check-reminder-${environment}`,
|
||||
runtime: lambda.Runtime.NODEJS_20_X,
|
||||
handler: "index.handler",
|
||||
code: lambda.Code.fromAsset(
|
||||
path.join(__dirname, "../../../lambdas/conditionCheckReminder"),
|
||||
{
|
||||
bundling: {
|
||||
image: lambda.Runtime.NODEJS_20_X.bundlingImage,
|
||||
command: [
|
||||
"bash",
|
||||
"-c",
|
||||
[
|
||||
"cp -r /asset-input/* /asset-output/",
|
||||
"cd /asset-output",
|
||||
"npm install --omit=dev",
|
||||
// Copy shared modules
|
||||
"mkdir -p shared",
|
||||
"cp -r /asset-input/../shared/* shared/",
|
||||
"cd shared && npm install --omit=dev",
|
||||
].join(" && "),
|
||||
],
|
||||
},
|
||||
}
|
||||
),
|
||||
role: lambdaRole,
|
||||
timeout: cdk.Duration.seconds(30),
|
||||
memorySize: 256,
|
||||
environment: {
|
||||
NODE_ENV: environment,
|
||||
DATABASE_URL: databaseUrl,
|
||||
FRONTEND_URL: frontendUrl,
|
||||
SES_FROM_EMAIL: sesFromEmail,
|
||||
SES_FROM_NAME: sesFromName,
|
||||
EMAIL_ENABLED: emailEnabled ? "true" : "false",
|
||||
SCHEDULE_GROUP_NAME: `condition-check-reminders-${environment}`,
|
||||
AWS_REGION: this.region,
|
||||
},
|
||||
deadLetterQueue: this.deadLetterQueue,
|
||||
retryAttempts: 2,
|
||||
description: "Sends condition check reminder emails for rentals",
|
||||
}
|
||||
);
|
||||
|
||||
// EventBridge Scheduler group
|
||||
this.scheduleGroup = new scheduler.CfnScheduleGroup(
|
||||
this,
|
||||
"ConditionCheckScheduleGroup",
|
||||
{
|
||||
name: `condition-check-reminders-${environment}`,
|
||||
}
|
||||
);
|
||||
|
||||
// IAM role for EventBridge Scheduler to invoke Lambda
|
||||
this.schedulerRole = new iam.Role(this, "SchedulerRole", {
|
||||
roleName: `condition-check-scheduler-role-${environment}`,
|
||||
assumedBy: new iam.ServicePrincipal("scheduler.amazonaws.com"),
|
||||
description: "Role for EventBridge Scheduler to invoke Lambda",
|
||||
});
|
||||
|
||||
// Allow scheduler to invoke the Lambda
|
||||
this.schedulerRole.addToPolicy(
|
||||
new iam.PolicyStatement({
|
||||
effect: iam.Effect.ALLOW,
|
||||
actions: ["lambda:InvokeFunction"],
|
||||
resources: [
|
||||
this.lambdaFunction.functionArn,
|
||||
`${this.lambdaFunction.functionArn}:*`,
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
// Outputs
|
||||
new cdk.CfnOutput(this, "LambdaFunctionArn", {
|
||||
value: this.lambdaFunction.functionArn,
|
||||
description: "ARN of the Condition Check Reminder Lambda",
|
||||
exportName: `ConditionCheckLambdaArn-${environment}`,
|
||||
});
|
||||
|
||||
new cdk.CfnOutput(this, "ScheduleGroupName", {
|
||||
value: this.scheduleGroup.name!,
|
||||
description: "Name of the EventBridge Scheduler group",
|
||||
exportName: `ConditionCheckScheduleGroup-${environment}`,
|
||||
});
|
||||
|
||||
new cdk.CfnOutput(this, "SchedulerRoleArn", {
|
||||
value: this.schedulerRole.roleArn,
|
||||
description: "ARN of the EventBridge Scheduler IAM role",
|
||||
exportName: `ConditionCheckSchedulerRoleArn-${environment}`,
|
||||
});
|
||||
|
||||
new cdk.CfnOutput(this, "DLQUrl", {
|
||||
value: this.deadLetterQueue.queueUrl,
|
||||
description: "URL of the Dead Letter Queue",
|
||||
exportName: `ConditionCheckDLQUrl-${environment}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user