Last active
August 16, 2023 14:06
-
-
Save jagchat/f8cf70e877d14996a3dc66078e92d361 to your computer and use it in GitHub Desktop.
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
const lambdaHelpers = require('lambda-helpers'); | |
const eventHelpers = require('event-helpers'); | |
const utils = require('utils'); | |
class BaseLambdaImplementation { | |
constructor(event) { | |
this.event = event; | |
console.log("Event info---------"); | |
console.log(JSON.stringify(this.event)); | |
try { | |
if (this.event.hasOwnProperty('body')) { //api gateway lambda helper | |
this.reqId = utils.getNewId(); | |
this.payload = JSON.parse(this.event.body) || {}; | |
this.nextEventState = { ReqId: this.reqId }; | |
} | |
else if (this.event.hasOwnProperty('source')) {//event consumer lambda | |
this.inputEvent = this.event.source; //triggered event | |
this.inputEventBody = this.event.detail || {}; | |
this.inputEventState = this.inputEventBody.state; | |
this.payload = this.inputEventBody.payload; | |
this.nextEventState = this.inputEventState || {}; | |
this.reqId = this.inputEventState.ReqId; | |
} | |
this.msg = lambdaHelpers.getSuccessResult({ ReqId: this.reqId, payload: this.payload }); | |
} | |
catch (err) { | |
console.log("ERROR :: BaseLambdaImplementation.constructor Error ---"); | |
console.log(err); | |
} | |
} | |
async raiseEvent(eventParam) { | |
try { | |
eventParam = { | |
DetailType: 'schedule.info', | |
EventBusName: process.env.SchedulerOperationsBusName, | |
Detail: JSON.stringify({ | |
state: this.nextEventState, | |
payload: this.payload | |
}), | |
...eventParam | |
}; | |
let eventResult = await eventHelpers.raiseEvent(eventParam); | |
if (eventResult.isSuccess) { | |
//this.msg = lambdaHelpers.getSuccessResult({ ReqId: this.reqId, payload: this.payload }); | |
} | |
else { | |
this.msg = lambdaHelpers.getExceptionResult({ ReqId: this.reqId, Message: "Not able to raise event", ErrorObject: eventResult.err, Data: eventParam }); | |
} | |
} | |
catch (err) { | |
console.log("ERROR :: BaseLambdaImplementation.raiseEvent Error ---"); | |
console.log(err); | |
} | |
} | |
updateHandlerResultSuccessMsg(data) { | |
this.msg = lambdaHelpers.getSuccessResult({ ReqId: this.reqId, ...data }); | |
} | |
updateHandlerResultErrorMsg(data) { | |
this.msg = lambdaHelpers.getErrorResult({ ReqId: this.reqId, ...data }); | |
} | |
doCallback(callback) { | |
callback(null, this.msg); | |
} | |
} | |
//export { BaseLambdaImplementation } | |
module.exports = BaseLambdaImplementation; |
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
"use strict"; | |
import { serializeError } from 'serialize-error'; | |
import { SchedulerClient, GetScheduleCommand, CreateScheduleCommand, FlexibleTimeWindowMode } from "@aws-sdk/client-scheduler"; | |
import BaseLambdaImplementation from 'base-implementation'; | |
import moment from 'moment'; | |
class LambdaImplementation extends BaseLambdaImplementation { | |
constructor(event) { | |
super(event); | |
} | |
//https://docs.aws.amazon.com/scheduler/latest/UserGuide/schedule-types.html#cron-based | |
createSchedule = async (payload) => { | |
let schClient = new SchedulerClient({ region: payload.Detail.ScheduleHeader.RegionEndPoint }); | |
let params = { | |
Name: process.env.EnvironmentPrefix + "-" + payload.Detail?.ScheduleHeader?.TenantId + "-" + payload.Name, | |
//GroupName: "Test", //TODO | |
ScheduleExpression: payload.ScheduleExpression, | |
FlexibleTimeWindow: { Mode: FlexibleTimeWindowMode.OFF }, | |
Target: { | |
Arn: "arn:aws:scheduler:::aws-sdk:eventbridge:putEvents", | |
RoleArn: process.env.SchedulerRoleUrn, | |
Input: JSON.stringify({ | |
Entries: [{ | |
EventBusName: process.env.ScheduledEventsBusName, | |
Source: "p360.schedule.event", | |
DetailType: "schedule.event.info", | |
Detail: JSON.stringify(payload) | |
}] | |
}), | |
}, | |
}; | |
if (payload.StartDate && | |
moment(payload.StartDate, "YYYY-MM-DDTHH:mm:ssZ", true).isValid()) { | |
params.StartDate = new Date(payload.StartDate); | |
} | |
if (payload.EndDate && | |
moment(payload.EndDate, "YYYY-MM-DDTHH:mm:ssZ", true).isValid()) { | |
params.EndDate = new Date(payload.EndDate); | |
} | |
let result = await schClient.send(new CreateScheduleCommand(params)); | |
} | |
async handler(event, context, callback) { | |
console.log("Handler: Started..."); | |
let eventNext = ""; //for next event to trigger as part of execution workflow | |
try { | |
var response = await this.createSchedule(this.payload); | |
eventNext = 'p360.scheduler.CreateScheduleAPI.CreatedScheduleInEventBridge'; | |
} | |
catch (err) { | |
console.log("ERROR :: at create-schedule-in-eb ---"); | |
console.log(err); | |
eventNext = 'p360.scheduler.CreateScheduleAPI.ErrorCreatingScheduleInEventBridge'; | |
this.nextEventState.ErrorMsg = "Unable to create schedule in EventBridge"; | |
this.nextEventState.ErrorInfo = serializeError(err); | |
} | |
await super.raiseEvent({ | |
Source: eventNext | |
}); | |
console.log("Handler: Completed..."); | |
this.doCallback(callback); | |
} | |
} | |
export const handler = async (event, context, callback) => { | |
const impl = new LambdaImplementation(event); | |
return await impl.handler(event, context, callback); | |
}; | |
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
const { EventBridgeClient, PutEventsCommand } = require('@aws-sdk/client-eventbridge'); | |
const eventHelpers = { | |
raiseEvent: async function (eventParam) { | |
try { | |
const params = { | |
"Entries": [eventParam] | |
}; | |
const ebClient = new EventBridgeClient(); | |
const response = await ebClient.send(new PutEventsCommand(params)); | |
return { isSuccess: true }; | |
} | |
catch (err) { | |
console.log("ERROR :: eventHelpers.raiseEvent ---", err); | |
console.log(err); | |
return { isSuccess: false, err: err }; | |
} | |
} | |
}; | |
module.exports = eventHelpers; |
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
const serializeError = require('serialize-error'); | |
const lambdaHelpers = { | |
getSuccessResult: function (content) { | |
return { | |
isBase64Encoded: false, | |
body: JSON.stringify(content), | |
headers: { | |
'Access-Control-Allow-Origin': '*', | |
}, | |
statusCode: 200, | |
} | |
}, | |
getErrorResult: function (content) { | |
content.isError = true; | |
return { | |
isBase64Encoded: false, | |
body: JSON.stringify(content), | |
headers: { | |
'Access-Control-Allow-Origin': '*', | |
}, | |
//statusCode: 500, | |
statusCode: 200, | |
} | |
}, | |
getExceptionResult: function (content) { | |
let item = { | |
ReqId: content.ReqId || "", | |
isError: true, | |
Message: content.Message || "", | |
Data: content.Data || {}, | |
ErrorInfo: serializeError(content.ErrorObject) | |
}; | |
return { | |
isBase64Encoded: false, | |
body: JSON.stringify(item), | |
headers: { | |
'Access-Control-Allow-Origin': '*', | |
}, | |
//statusCode: 500, | |
statusCode: 200, | |
} | |
} | |
}; | |
module.exports = lambdaHelpers; |
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
locals { | |
computed_sch_operations_bus_name = "${var.namespace}-${var.scheduler_operations_bus_name}" | |
} | |
resource "aws_iam_role" "create_schedule_in_eb_lambda_role" { | |
name = "${var.namespace}-create_schedule_in_eb_lambda_role" | |
assume_role_policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Action": "sts:AssumeRole", | |
"Principal": { | |
"Service": [ | |
"lambda.amazonaws.com" | |
] | |
}, | |
"Effect": "Allow", | |
"Sid": "" | |
} | |
] | |
} | |
EOF | |
} | |
resource "aws_iam_policy" "create_schedule_in_eb_lambda_policy" { | |
name = "${var.namespace}-create_schedule_in_eb_lambda_policy" | |
path = "/" | |
description = "AWS IAM Policy for managing aws lambda role" | |
policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Action": [ | |
"logs:CreateLogGroup", | |
"logs:CreateLogStream", | |
"logs:PutLogEvents" | |
], | |
"Resource": "arn:aws:logs:*:*:*", | |
"Effect": "Allow" | |
}, | |
{ | |
"Effect": "Allow", | |
"Action": [ | |
"events:PutEvents" | |
], | |
"Resource": [ | |
"arn:aws:events:*:*" | |
] | |
}, | |
{ | |
"Effect": "Allow", | |
"Action": [ | |
"scheduler:CreateSchedule", | |
"scheduler:GetSchedule", | |
"scheduler:UpdateSchedule" | |
], | |
"Resource": "arn:aws:scheduler:*:*:schedule/*/*" | |
}, | |
{ | |
"Effect": "Allow", | |
"Action": "iam:PassRole", | |
"Resource": "arn:aws:iam::*:role/*", | |
"Condition": { | |
"StringLike": { | |
"iam:PassedToService": "scheduler.amazonaws.com" | |
} | |
} | |
} | |
] | |
} | |
EOF | |
} | |
resource "aws_iam_role_policy_attachment" "create_schedule_in_eb_lambda_attach_iam_policy_to_iam_role" { | |
role = aws_iam_role.create_schedule_in_eb_lambda_role.name | |
policy_arn = aws_iam_policy.create_schedule_in_eb_lambda_policy.arn | |
} | |
data "archive_file" "create_schedule_in_eb_lambda_app_zip" { | |
type = "zip" | |
source_dir = "${path.module}/app" | |
#source_file = "index.js" #if one file | |
output_path = "${path.module}/app.zip" | |
} | |
data "aws_iam_role" "scheduler_role" { | |
name = "${var.namespace}-scheduler_role" | |
} | |
data "aws_lambda_layer_version" "layer_default" { | |
layer_name = "${var.namespace}-layer-default" | |
} | |
data "aws_lambda_layer_version" "layer_base" { | |
layer_name = "${var.namespace}-layer-base" | |
} | |
resource "aws_lambda_function" "create_schedule_in_eb_lambda_function" { | |
filename = "${path.module}/app.zip" | |
function_name = "${var.namespace}-create_schedule_in_eb_lambda" | |
role = aws_iam_role.create_schedule_in_eb_lambda_role.arn | |
handler = "index.handler" | |
source_code_hash = data.archive_file.create_schedule_in_eb_lambda_app_zip.output_base64sha256 | |
runtime = "nodejs18.x" | |
environment { | |
variables = { | |
ScheduledEventsBusName = "${var.namespace}-${var.scheduled_events_bus_name}" | |
SchedulerOperationsBusName = local.computed_sch_operations_bus_name | |
SchedulerRoleUrn = "${data.aws_iam_role.scheduler_role.arn}" | |
EnvironmentPrefix = "${var.namespace}" | |
} | |
} | |
depends_on = [ | |
aws_iam_role_policy_attachment.create_schedule_in_eb_lambda_attach_iam_policy_to_iam_role | |
] | |
layers = [ | |
data.aws_lambda_layer_version.layer_default.arn, | |
data.aws_lambda_layer_version.layer_base.arn | |
] | |
} | |
resource "aws_cloudwatch_log_group" "create_schedule_in_eb_function_log_group" { | |
name = "/aws/lambda/${aws_lambda_function.create_schedule_in_eb_lambda_function.function_name}" | |
retention_in_days = var.lambda_logs_retention | |
lifecycle { | |
prevent_destroy = false | |
} | |
} | |
//subscribe to cloudwatch event rule | |
resource "aws_cloudwatch_event_rule" "create_schedule_in_eb_event_sub_rule" { | |
name = "${var.namespace}-create_schedule_in_eb_event_sub" | |
description = "Capture each AWS Console Sign In" | |
event_bus_name = local.computed_sch_operations_bus_name | |
event_pattern = <<EOF | |
{ | |
"source": ["p360.scheduler.CreateScheduleAPI.CreatedScheduleInS3"], | |
"detail-type": ["schedule.info"] | |
} | |
EOF | |
} | |
resource "aws_cloudwatch_event_target" "create_schedule_in_eb_event_sub_rule_lambda_target" { | |
arn = aws_lambda_function.create_schedule_in_eb_lambda_function.arn | |
rule = aws_cloudwatch_event_rule.create_schedule_in_eb_event_sub_rule.name | |
event_bus_name = local.computed_sch_operations_bus_name | |
} | |
//allow eventbridge to call lambda | |
resource "aws_lambda_permission" "allow_eventbridge_to_call_lambda" { | |
statement_id = "AllowExecutionFromCloudWatch" | |
action = "lambda:InvokeFunction" | |
function_name = aws_lambda_function.create_schedule_in_eb_lambda_function.function_name | |
principal = "events.amazonaws.com" | |
source_arn = aws_cloudwatch_event_rule.create_schedule_in_eb_event_sub_rule.arn | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment