Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 13 additions & 121 deletions src/app/api/instances/[name]/alarms/route.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import { EC2Client } from "@aws-sdk/client-ec2";
import { NextRequest, NextResponse } from "next/server";
import { fetchInstance } from "@/utils/AWS/EC2/fetchInstance";
import { Alarm } from "@/types/alarms";
import { startMetricsMonitoring } from "@/utils/RabbitMQ/monitorMetrics";
import { decrypt } from "@/utils/encrypt";
import { stopMetricsMonitoring } from "@/utils/RabbitMQ/monitorMetrics";
import {
appendAlarmsSettings,
deleteAlarmFromDynamoDB,
fetchFromDynamoDB,
} from "@/utils/dynamoDBUtils";
import getAlarms from "./utils/getAlarms";
import addAndStartAlarms from "./utils/addAndStartAlarms";
import deleteAlarms from "./utils/deleteAlarms";

export async function GET(
request: NextRequest,
Expand All @@ -26,30 +18,12 @@ export async function GET(
);
}

const client = new EC2Client({ region });
const instance = await fetchInstance(instanceName, client);

if (!instance || !instance.InstanceId) {
return NextResponse.json(
{ message: `No instance found with name: ${instanceName}` },
{ status: 404 }
);
}

try {
const response = await fetchFromDynamoDB("rabbitory-instances-metadata", {
instanceId: instance.InstanceId,
const alarms = await getAlarms({
region,
instanceName,
});

if (!response || !response.Item) {
return NextResponse.json({
memory: [],
storage: []
});
}

const alarms = response.Item.alarms;

return NextResponse.json(alarms);
} catch (error) {
console.error(error);
Expand All @@ -67,6 +41,7 @@ export async function POST(
const searchParams = request.nextUrl.searchParams;
const region = searchParams.get("region");
const { name: instanceName } = await params;
const alarmData = await request.json();

if (!region) {
return NextResponse.json(
Expand All @@ -75,56 +50,16 @@ export async function POST(
);
}

const client = new EC2Client({ region });
const instance = await fetchInstance(instanceName, client);

if (!instance || !instance.InstanceId) {
return NextResponse.json(
{ message: `No instance found with name: ${instanceName}` },
{ status: 404 }
);
}

const alarmData = await request.json();

try {
const response = await appendAlarmsSettings(instance.InstanceId, alarmData);

const metadata = await fetchFromDynamoDB("rabbitory-instances-metadata", {
instanceId: instance.InstanceId,
});

const encryptedUsername = metadata.Item?.encryptedUsername;
const encryptedPassword = metadata.Item?.encryptedPassword;
const publicDns = instance.PublicDnsName;
const type = alarmData.type;

if (!encryptedUsername || !encryptedPassword || !publicDns) {
return NextResponse.json(
{ message: "RabbitMQ credentials not found" },
{ status: 500 }
);
}

const username = decrypt(encryptedUsername);
const password = decrypt(encryptedPassword);
const alarms = response.Attributes?.alarms;
// we append the newest alarm, so order is maintained
const newAlarm: Alarm = alarms[type]?.slice(-1)[0];

await startMetricsMonitoring(
instance.InstanceId,
const alarms = await addAndStartAlarms({
region,
publicDns,
username,
password,
newAlarm,
alarmData.type,
);
alarmData,
instanceName,
});

return NextResponse.json({
message: "Alarm added and monitoring started",
alarms: response.Attributes?.alarms
alarms,
});
} catch (error) {
console.error(error);
Expand All @@ -135,39 +70,6 @@ export async function POST(
}
}

// import { startMetricsMonitoring } from '@/utils/RabbitMQ/monitorMetrics';
//
// export async function POST(
// request: NextRequest,
// { params }: { params: Promise<{ name: string }> }
// ) {
// // ... existing code ...
//
// try {
// const response = await axios.get(rabbitmqUrl, {
// auth: { username, password }
// });
//
// // Start the monitoring cron job
// await startMetricsMonitoring(
// publicDns,
// username,
// password,
// [alarms], // Pass the alarm settings
// type as 'memory' | 'storage'
// );
//
// return NextResponse.json({ message: "Monitoring started successfully" });
// } catch (error) {
// console.error("Error starting monitoring:", error);
// return NextResponse.json(
// { message: "Error starting monitoring" },
// { status: 500 }
// );
// }
// }
// }

export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ name: string }> }
Expand All @@ -182,18 +84,8 @@ export async function DELETE(
return NextResponse.json({ message: "Missing parameter" }, { status: 400 });
}

const client = new EC2Client({ region });
const instance = await fetchInstance(instanceName, client);

if (!instance || !instance.InstanceId) {
return NextResponse.json(
{ message: `No instance found with name: ${instanceName}` },
{ status: 404 }
);
}
try {
stopMetricsMonitoring(alarmId);
await deleteAlarmFromDynamoDB(instance.InstanceId, type, alarmId);
await deleteAlarms({ region, type, alarmId, instanceName });
return NextResponse.json({ message: "Alarm deleted successfully" });
} catch (error) {
console.error(error);
Expand Down
4 changes: 1 addition & 3 deletions src/app/api/instances/[name]/alarms/slack/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ export async function POST(request: NextRequest) {
const body = await request.json();
const webhookUrl = body.webhookUrl;

console.log("webhookUrl", webhookUrl);

if (!("webhookUrl" in body))
return new NextResponse("Must have a webhookUrl in the request body.", {
status: 400,
Expand All @@ -16,7 +14,7 @@ export async function POST(request: NextRequest) {
await saveWebhookUrl(webhookUrl);
return NextResponse.json({
success: true,
webhookUrl
webhookUrl,
});
} catch (error) {
return NextResponse.json(
Expand Down
47 changes: 9 additions & 38 deletions src/app/api/instances/[name]/alarms/trigger/route.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,32 @@
import { EC2Client } from "@aws-sdk/client-ec2";
import { NextRequest, NextResponse } from "next/server";
import { fetchInstance } from "@/utils/AWS/EC2/fetchInstance";
import { sendNotification } from "@/utils/RabbitMQ/monitorMetrics";

import triggerAlarms from "./utils/triggerAlarms";

export async function POST(
request: NextRequest,
{ params }: { params: Promise<{ name: string }> }
) {
const searchParams = request.nextUrl.searchParams;
const region = searchParams.get("region");
const type = searchParams.get("type");
const { name: instanceName } = await params;
const username = request.headers.get("x-rabbitmq-username");
const password = request.headers.get("x-rabbitmq-password");

if (!username || !password) {
return NextResponse.json(
{ message: "Username and password are required" },
{ status: 400 }
);
}

if (!region || !instanceName) {
return NextResponse.json(
{ message: "Missing parameters" },
{ status: 400 }
);
}

const ec2Client = new EC2Client({ region });

const instance = await fetchInstance(instanceName, ec2Client);
if (!instance || !instance.PublicDnsName) {
return NextResponse.json(
{ message: `Instance is not found!` },
{ status: 404 }
);
}
const publicDns = instance.PublicDnsName;

const alarms = await request.json();
console.log(alarms);

const type = searchParams.get("type");
if (!type) {
if (!region || !type || !instanceName || !username || !password) {
return NextResponse.json(
{ message: "Missing parameters" },
{ status: 400 }
);
}

try {
sendNotification({
alarmId: alarms.id,
type: type,
currentValue: 0,
threshold: alarms.data.storageThreshold,
instanceDns: publicDns,
await triggerAlarms({
region,
alarms,
type,
instanceName,
});
return NextResponse.json({ message: "Trigger successfully" });
} catch (error) {
Expand Down
39 changes: 39 additions & 0 deletions src/app/api/instances/[name]/alarms/trigger/utils/triggerAlarms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { EC2Client } from "@aws-sdk/client-ec2";

import { fetchInstance } from "@/utils/AWS/EC2/fetchInstance";
import { sendNotification } from "@/utils/RabbitMQ/monitorMetrics";

import { Alarm } from "../../types";

interface TriggerAlarmsParams {
region: string;
alarms: Alarm;
type: string;
instanceName: string;
}

export default async function triggerAlarms({
region,
alarms,
type,
instanceName,
}: TriggerAlarmsParams) {
const ec2Client = new EC2Client({ region });

const instance = await fetchInstance(instanceName, ec2Client);
if (!instance || !instance.PublicDnsName) {
throw new Error(`Instance not found: ${instanceName}`);
}
const publicDns = instance.PublicDnsName;
const threshold =
type === "storage"
? alarms.data.storageThreshold
: alarms.data.memoryThreshold;
sendNotification({
alarmId: alarms.id,
type: type,
currentValue: 0,
threshold,
instanceDns: publicDns,
});
}
34 changes: 34 additions & 0 deletions src/app/api/instances/[name]/alarms/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export interface Alarm {
id: string;
data: {
memoryThreshold?: number;
storageThreshold?: number;
reminderInterval: number;
};
}
export interface AlarmData {
type: "memory" | "storage";
data: {
memoryThreshold?: number;
storageThreshold?: number;
reminderInterval: number;
};
}

export interface GetAlarmsParams {
region: string;
instanceName: string;
}

export interface AddAndStartAlarmsParams {
region: string;
alarmData: AlarmData;
instanceName: string;
}

export interface DeleteAlarmsParams {
region: string;
type: string;
alarmId: string;
instanceName: string;
}
Loading