add monitor list api

This commit is contained in:
Simon Larsen
2023-05-05 12:55:51 +01:00
parent c961215677
commit bca11364a2
9 changed files with 194 additions and 103 deletions

View File

@@ -0,0 +1,9 @@
import CronParser from 'cron-parser';
export default class CronTab {
public static getNextExecutionTime(crontab: string): Date {
const interval = CronParser.parseExpression(crontab);
const nextExecutionTime = interval.next().toDate();
return nextExecutionTime;
}
}

View File

@@ -23,6 +23,7 @@
"bullmq": "^3.6.6",
"Common": "file:../Common",
"cors": "^2.8.5",
"cron-parser": "^4.8.1",
"dotenv": "^16.0.0",
"ejs": "^3.1.8",
"express": "^4.17.3",

View File

@@ -25,6 +25,7 @@
"bullmq": "^3.6.6",
"Common": "file:../Common",
"cors": "^2.8.5",
"cron-parser": "^4.8.1",
"dotenv": "^16.0.0",
"ejs": "^3.1.8",
"express": "^4.17.3",

View File

@@ -4,69 +4,23 @@ import Express, {
ExpressRouter,
NextFunction,
} from 'CommonServer/Utils/Express';
import ObjectID from 'Common/Types/ObjectID';
import Response from 'CommonServer/Utils/Response';
import BadDataException from 'Common/Types/Exception/BadDataException';
import ProbeService from 'CommonServer/Services/ProbeService';
import OneUptimeDate from 'Common/Types/Date';
import { JSONObject } from 'Common/Types/JSON';
import Probe from 'Model/Models/Probe';
import ProbeAuthorization from '../Middleware/ProbeAuthorization';
const router: ExpressRouter = Express.getRouter();
router.post(
'/alive',
ProbeAuthorization.isAuthorizedServiceMiddleware,
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = req.body;
if (!data['probeId'] || !data['probeKey']) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('ProbeId or ProbeKey is missing')
);
}
const probeId: ObjectID = new ObjectID(data['probeId'] as string);
const probeKey: string = data['probeKey'] as string;
const probe: Probe | null = await ProbeService.findOneBy({
query: {
_id: probeId.toString(),
key: probeKey,
},
select: {
_id: true,
},
props: {
isRoot: true,
},
});
if (!probe) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid Probe ID or Probe Key')
);
}
await ProbeService.updateOneById({
id: probeId,
data: {
lastAlive: OneUptimeDate.getCurrentDate(),
},
props: {
isRoot: true,
},
});
// middleware marks the probe as alive.
// so we dont need to do anything here.
return Response.sendEmptyResponse(req, res);
} catch (err) {
return next(err);

View File

@@ -4,70 +4,92 @@ import Express, {
ExpressRouter,
NextFunction,
} from 'CommonServer/Utils/Express';
import ObjectID from 'Common/Types/ObjectID';
import Response from 'CommonServer/Utils/Response';
import BadDataException from 'Common/Types/Exception/BadDataException';
import ProbeService from 'CommonServer/Services/ProbeService';
import ProbeAuthorization from '../Middleware/ProbeAuthorization';
import MonitorProbe from 'Model/Models/MonitorProbe';
import MonitorProbeService from 'CommonServer/Services/MonitorProbeService';
import QueryHelper from 'CommonServer/Types/Database/QueryHelper';
import OneUptimeDate from 'Common/Types/Date';
import { JSONObject } from 'Common/Types/JSON';
import Probe from 'Model/Models/Probe';
import { ProbeExpressRequest } from '../Types/Request';
import BadDataException from 'Common/Types/Exception/BadDataException';
import CronTab from "CommonServer/Utils/CronTab"
import Monitor from 'Model/Models/Monitor';
import PositiveNumber from 'Common/Types/PositiveNumber';
const router: ExpressRouter = Express.getRouter();
router.post(
'/monitor/list',
ProbeAuthorization.isAuthorizedServiceMiddleware,
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> => {
try {
const data: JSONObject = req.body;
const data = req.body;
const limit = data['limit'] as number || 100;
if (!data['probeId'] || !data['probeKey']) {
if(!(req as ProbeExpressRequest).probe || !(req as ProbeExpressRequest).probe?.id){
return Response.sendErrorResponse(
req,
res,
new BadDataException('ProbeId or ProbeKey is missing')
new BadDataException('Probe not found')
);
}
const probeId: ObjectID = new ObjectID(data['probeId'] as string);
const probeKey: string = data['probeKey'] as string;
const probe: Probe | null = await ProbeService.findOneBy({
//get list of monitors to be monitored
const monitorProbes: Array<MonitorProbe> = await MonitorProbeService.findBy({
query: {
_id: probeId.toString(),
key: probeKey,
probeId: ((req as ProbeExpressRequest).probe)!.id!,
isEnabled: true,
nextPingAt: QueryHelper.lessThanEqualTo(
OneUptimeDate.getCurrentDate()
)
},
skip: 0,
limit: limit,
select: {
_id: true,
probeId: true,
monitorId: true
},
populate: {
monitor: {
monitorSteps: true,
monitorType: true,
monitoringInterval: true,
}
},
props: {
isRoot: true,
},
isRoot: true
}
});
if (!probe) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid Probe ID or Probe Key')
);
// update the lastMonitoredAt field of the monitors
for(const monitorProbe of monitorProbes){
await MonitorProbeService.updateOneById({
id: monitorProbe.id!,
data: {
lastPingAt: OneUptimeDate.getCurrentDate(),
nextPingAt: CronTab.getNextExecutionTime(monitorProbe?.monitor?.monitoringInterval as string)
},
props: {
isRoot: true
}
});
}
await ProbeService.updateOneById({
id: probeId,
data: {
lastAlive: OneUptimeDate.getCurrentDate(),
},
props: {
isRoot: true,
},
const monitors: Array<Monitor> = monitorProbes.map((monitorProbe) => {
return monitorProbe.monitor!;
});
return Response.sendEmptyResponse(req, res);
// return the list of monitors to be monitored
return Response.sendEntityArrayResponse(req, res, monitors, new PositiveNumber(monitors.length), Monitor);
} catch (err) {
return next(err);
}

View File

@@ -0,0 +1,78 @@
import { ClusterKey as ONEUPTIME_SECRET } from 'CommonServer/Config';
import {
ExpressResponse,
NextFunction,
} from 'CommonServer/Utils/Express';
import Response from 'CommonServer/Utils/Response';
import BadDataException from 'Common/Types/Exception/BadDataException';
import ObjectID from 'Common/Types/ObjectID';
import Dictionary from 'Common/Types/Dictionary';
import { JSONObject } from 'Common/Types/JSON';
import Probe from 'Model/Models/Probe';
import ProbeService from 'CommonServer/Services/ProbeService';
import OneUptimeDate from 'Common/Types/Date';
import { ProbeExpressRequest } from '../Types/Request';
export default class ProbeAuthorization {
public static getClusterKeyHeaders(): Dictionary<string> {
return {
clusterkey: ONEUPTIME_SECRET.toString(),
};
}
public static async isAuthorizedServiceMiddleware(
req: ProbeExpressRequest,
res: ExpressResponse,
next: NextFunction
): Promise<void> {
const data: JSONObject = req.body;
if (!data['probeId'] || !data['probeKey']) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('ProbeId or ProbeKey is missing')
);
}
const probeId: ObjectID = new ObjectID(data['probeId'] as string);
const probeKey: string = data['probeKey'] as string;
const probe: Probe | null = await ProbeService.findOneBy({
query: {
_id: probeId.toString(),
key: probeKey,
},
select: {
_id: true,
},
props: {
isRoot: true,
},
});
if (!probe) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid Probe ID or Probe Key')
);
}
await ProbeService.updateOneById({
id: probeId,
data: {
lastAlive: OneUptimeDate.getCurrentDate(),
},
props: {
isRoot: true,
},
});
req.probe = probe;
return next();
}
}

View File

@@ -0,0 +1,6 @@
import { ExpressRequest } from "CommonServer/Utils/Express";
import Probe from "Model/Models/Probe";
export interface ProbeExpressRequest extends ExpressRequest {
probe?: Probe | undefined;
}

View File

@@ -11,6 +11,7 @@
"dependencies": {
"Common": "file:../Common",
"CommonServer": "file:../CommonServer",
"cron-parser": "^4.8.1",
"ejs": "^3.1.8",
"Model": "file:../Model",
"ts-node": "^10.9.1"
@@ -19141,6 +19142,17 @@
"version": "1.1.1",
"license": "MIT"
},
"node_modules/cron-parser": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.8.1.tgz",
"integrity": "sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==",
"dependencies": {
"luxon": "^3.2.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"dev": true,
@@ -20726,6 +20738,14 @@
"node": ">=10"
}
},
"node_modules/luxon": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz",
"integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==",
"engines": {
"node": ">=12"
}
},
"node_modules/make-dir": {
"version": "3.1.0",
"dev": true,

View File

@@ -4,28 +4,28 @@
"description": "",
"main": "index.js",
"scripts": {
"start": "node --require ts-node/register Index.ts",
"compile": "tsc",
"dev": "npx nodemon",
"audit": "npm audit --audit-level=low",
"dep-check": "depcheck ./ --skip-missing=true",
"test": "jest"
"start": "node --require ts-node/register Index.ts",
"compile": "tsc",
"dev": "npx nodemon",
"audit": "npm audit --audit-level=low",
"dep-check": "depcheck ./ --skip-missing=true",
"test": "jest"
},
"author": "",
"license": "ISC",
"dependencies": {
"Common": "file:../Common",
"CommonServer": "file:../CommonServer",
"ejs": "^3.1.8",
"Model": "file:../Model",
"ts-node": "^10.9.1"
"Common": "file:../Common",
"CommonServer": "file:../CommonServer",
"cron-parser": "^4.8.1",
"ejs": "^3.1.8",
"Model": "file:../Model",
"ts-node": "^10.9.1"
},
"devDependencies": {
"@types/jest": "^27.5.0",
"@types/node": "^17.0.31",
"jest": "^28.1.0",
"nodemon": "^2.0.20",
"ts-jest": "^28.0.2"
"@types/jest": "^27.5.0",
"@types/node": "^17.0.31",
"jest": "^28.1.0",
"nodemon": "^2.0.20",
"ts-jest": "^28.0.2"
}
}
}