From 6799b64f2adad7daa6ef957fccbef8c34b37f294 Mon Sep 17 00:00:00 2001 From: samuel-p Date: Thu, 16 Jul 2020 22:08:02 +0200 Subject: [PATCH] added option to update multiple service states at once minor frontend improvements --- Dockerfile | 2 +- config.json | 14 +++---- src/app/_data/data.ts | 3 +- src/app/status/status.component.html | 11 +++--- src/app/status/status.component.scss | 5 +++ src/main.status.ts | 59 +++++++++++++--------------- 6 files changed, 48 insertions(+), 46 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2d4262b..93f7d8f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:alpine +FROM node:14.5.0-alpine COPY dist/universal-statuspage /universal-statuspage diff --git a/config.json b/config.json index a01e3b9..d988f5c 100644 --- a/config.json +++ b/config.json @@ -2,25 +2,23 @@ "authToken": "test", "title": "sp-status", "description": "Services hosted by sp-codes", + "servicesPath": "$.alerts.*", + "idPath": "$.labels.status_service", "statePath": "$.status", "stateValues": { - "operational": ["OK"], - "maintenance": ["PAUSED"] + "operational": ["ok", "resolved"], + "maintenance": ["paused"] }, "groups": [ { "id": "test", "name": "Test", + "url": "http://sp-codes.de", "services": [ { "id": "test", "name": "test", - "url": "http://sp-codes.de", - "statePath": "$.state", - "stateValues": { - "operational": ["ok"], - "maintenance": ["paused"] - } + "statePath": "$.state" } ] } diff --git a/src/app/_data/data.ts b/src/app/_data/data.ts index 355e0dc..478dd1a 100644 --- a/src/app/_data/data.ts +++ b/src/app/_data/data.ts @@ -8,6 +8,7 @@ export interface CurrentStatus { export interface Group { id: string; name: string; + url?: string; state: State; services: Service[]; } @@ -15,7 +16,7 @@ export interface Group { export interface Service { id: string; name: string; - url: string; + url?: string; state: State; } diff --git a/src/app/status/status.component.html b/src/app/status/status.component.html index 6ef500a..f0b5aa2 100644 --- a/src/app/status/status.component.html +++ b/src/app/status/status.component.html @@ -1,14 +1,15 @@ - {{group.name}} - - - + + + {{group.name}} + {{group.name}} + - +
{{service.name}} diff --git a/src/app/status/status.component.scss b/src/app/status/status.component.scss index 558a8af..310e4f4 100644 --- a/src/app/status/status.component.scss +++ b/src/app/status/status.component.scss @@ -13,6 +13,11 @@ a { text-decoration: none; outline: none; + color: #ffffff; + + &:hover.name, &:hover .name { + text-decoration: underline; + } } mat-panel-title { diff --git a/src/main.status.ts b/src/main.status.ts index 54e7f4d..8b466bd 100644 --- a/src/main.status.ts +++ b/src/main.status.ts @@ -12,7 +12,9 @@ interface Config { authToken: string; title: string; description: string; - statePath: string; + servicesPath?: string; + idPath?: string; + statePath?: string; stateValues: { operational: string[]; maintenance: string[]; @@ -20,42 +22,26 @@ interface Config { groups: { id: string; name: string; + url?: string; services: { id: string; name: string; - url: string; + url?: string; statePath?: string; - stateValues?: { - operational?: string[]; - maintenance?: string[]; - }; }[]; }[]; } -interface StateKey { - statePath: string; - stateValues: { - operational: string[]; - maintenance: string[]; - }; -} - const api = Router(); api.use(json()); const serviceStates = existsSync(join(process.cwd(), 'cache.json')) ? JSON.parse(readFileSync(join(process.cwd(), 'cache.json'), {encoding: 'utf-8'})) : {} as Cache; const config = JSON.parse(readFileSync(join(process.cwd(), 'config.json'), {encoding: 'utf-8'})) as Config; -const stateKeys: { [service: string]: StateKey } = config.groups +const serviceStatePaths: { [service: string]: string } = config.groups .map(g => g.services).reduce((x, y) => x.concat(y), []) + .filter(s => s.statePath) .reduce((services, service) => { - services[service.id] = { - statePath: service.statePath || config.statePath, - stateValues: { - operational: service.stateValues ? service.stateValues.operational || config.stateValues.operational : config.stateValues.operational, - maintenance: service.stateValues ? service.stateValues.maintenance || config.stateValues.maintenance : config.stateValues.maintenance, - } - }; + services[service.id] = service.statePath; return services; }, {}); @@ -68,17 +54,27 @@ api.post('/update/health', (req, res) => { return res.status(401).send('invalid token'); } const serviceId = req.query.service as string; - const keys = stateKeys[serviceId]; - const state = JSONPath({path: keys.statePath, json: req.body, wrap: false}); - - if (keys.stateValues.operational.includes(state)) { - serviceStates[serviceId] = 'operational'; - } else if (keys.stateValues.maintenance.includes(state)) { - serviceStates[serviceId] = 'maintenance'; - } else { - serviceStates[serviceId] = 'outage'; + let services: { id: string, state: string }[] = []; + if (serviceId) { + services = [{id: serviceId, state: JSONPath({path: serviceStatePaths[serviceId], json: req.body, wrap: false})}]; + } else if (config.servicesPath && config.idPath && config.statePath) { + services = JSONPath({path: config.servicesPath, json: req.body}) + .map(s => ({ + id: JSONPath({path: config.idPath, json: s, wrap: false}), + state: JSONPath({path: config.statePath, json: s, wrap: false}) + })); } + services.forEach(s => { + if (config.stateValues.operational.includes(s.state)) { + serviceStates[s.id] = 'operational'; + } else if (config.stateValues.maintenance.includes(s.state)) { + serviceStates[s.id] = 'maintenance'; + } else { + serviceStates[s.id] = 'outage'; + } + }); + updateCache(); writeFileSync('cache.json', JSON.stringify(serviceStates), {encoding: 'utf-8'}); @@ -110,6 +106,7 @@ function updateCache(): void { return { id: group.id, name: group.name, + url: group.url, state: calculateOverallState(services.map(s => s.state)), services: services };