118 lines
2.6 KiB
TypeScript
118 lines
2.6 KiB
TypeScript
|
import {json, Router} from 'express';
|
||
|
import {CurrentStatus, State} from "./app/_data/data";
|
||
|
import {existsSync, readFileSync, writeFileSync} from "fs";
|
||
|
|
||
|
interface Cache {
|
||
|
[id: string]: State
|
||
|
}
|
||
|
|
||
|
interface Config {
|
||
|
authToken: string;
|
||
|
title: string;
|
||
|
description: string;
|
||
|
groups: {
|
||
|
id: string;
|
||
|
name: string;
|
||
|
services: {
|
||
|
id: string;
|
||
|
name: string;
|
||
|
url: string;
|
||
|
}[];
|
||
|
}[];
|
||
|
}
|
||
|
|
||
|
interface GrafanaWebhookBody {
|
||
|
dashboardId: number;
|
||
|
evalMatches: {
|
||
|
value: number,
|
||
|
metric: string,
|
||
|
tags: any
|
||
|
}[];
|
||
|
imageUrl: string,
|
||
|
message: string,
|
||
|
orgId: number,
|
||
|
panelId: number,
|
||
|
ruleId: number,
|
||
|
ruleName: string,
|
||
|
ruleUrl: string,
|
||
|
state: "ok" | "paused" | "alerting" | "pending" | "no_data";
|
||
|
tags: { [key: string]: string },
|
||
|
title: string
|
||
|
}
|
||
|
|
||
|
const api = Router();
|
||
|
api.use(json());
|
||
|
|
||
|
const config = JSON.parse(readFileSync('config.json', {encoding: 'UTF-8'})) as Config;
|
||
|
const serviceStates = existsSync('cache.json') ? JSON.parse(readFileSync('cache.json', {encoding: 'UTF-8'})) : {} as Cache;
|
||
|
|
||
|
let cache: CurrentStatus;
|
||
|
updateCache();
|
||
|
|
||
|
api.post('/update/health', (req, res) => {
|
||
|
const token = req.query.token;
|
||
|
if (token !== config.authToken) {
|
||
|
return res.status(401).send('invalid token');
|
||
|
}
|
||
|
const serviceId = req.query.service as string;
|
||
|
const message = req.body as GrafanaWebhookBody;
|
||
|
|
||
|
switch (message.state) {
|
||
|
case "no_data":
|
||
|
case "alerting":
|
||
|
serviceStates[serviceId] = "outage";
|
||
|
break;
|
||
|
case "paused":
|
||
|
serviceStates[serviceId] = "maintenance";
|
||
|
break;
|
||
|
default:
|
||
|
serviceStates[serviceId] = "operational"
|
||
|
}
|
||
|
|
||
|
updateCache();
|
||
|
|
||
|
writeFileSync('cache.json', JSON.stringify(serviceStates), {encoding: 'UTF-8'});
|
||
|
|
||
|
return res.send('OK');
|
||
|
});
|
||
|
|
||
|
api.get('/status', (req, res) => {
|
||
|
return res.json(cache);
|
||
|
});
|
||
|
|
||
|
api.get('/info', (req, res) => {
|
||
|
return res.json({
|
||
|
title: config.title,
|
||
|
description: config.description
|
||
|
});
|
||
|
});
|
||
|
|
||
|
function updateCache(): void {
|
||
|
const groups = config.groups.map(group => {
|
||
|
const services = group.services.map(service => {
|
||
|
return {
|
||
|
id: service.id,
|
||
|
name: service.name,
|
||
|
url: service.url,
|
||
|
state: serviceStates[service.id] || "operational"
|
||
|
}
|
||
|
});
|
||
|
return {
|
||
|
id: group.id,
|
||
|
name: group.name,
|
||
|
state: calculateOverallState(services.map(s => s.state)),
|
||
|
services: services
|
||
|
}
|
||
|
});
|
||
|
cache = {
|
||
|
state: calculateOverallState(groups.map(g => g.state)),
|
||
|
groups: groups
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function calculateOverallState(states: State[]): State {
|
||
|
return states.includes("outage") ? "outage" : states.includes("maintenance") ? "maintenance" : "operational"
|
||
|
}
|
||
|
|
||
|
export {api};
|