Merge pull request 'develop' (#19) from develop into master
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
Reviewed-on: #19
This commit is contained in:
commit
df91ab8548
8 changed files with 52 additions and 50 deletions
|
@ -1,4 +1,4 @@
|
||||||
FROM node:alpine
|
FROM node:14.5.0-alpine
|
||||||
|
|
||||||
COPY dist/universal-statuspage /universal-statuspage
|
COPY dist/universal-statuspage /universal-statuspage
|
||||||
|
|
||||||
|
|
14
config.json
14
config.json
|
@ -2,25 +2,23 @@
|
||||||
"authToken": "test",
|
"authToken": "test",
|
||||||
"title": "sp-status",
|
"title": "sp-status",
|
||||||
"description": "Services hosted by sp-codes",
|
"description": "Services hosted by sp-codes",
|
||||||
|
"servicesPath": "$.alerts.*",
|
||||||
|
"idPath": "$.labels.status_service",
|
||||||
"statePath": "$.status",
|
"statePath": "$.status",
|
||||||
"stateValues": {
|
"stateValues": {
|
||||||
"operational": ["OK"],
|
"operational": ["ok", "resolved"],
|
||||||
"maintenance": ["PAUSED"]
|
"maintenance": ["paused"]
|
||||||
},
|
},
|
||||||
"groups": [
|
"groups": [
|
||||||
{
|
{
|
||||||
"id": "test",
|
"id": "test",
|
||||||
"name": "Test",
|
"name": "Test",
|
||||||
|
"url": "http://sp-codes.de",
|
||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"id": "test",
|
"id": "test",
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"url": "http://sp-codes.de",
|
"statePath": "$.state"
|
||||||
"statePath": "$.state",
|
|
||||||
"stateValues": {
|
|
||||||
"operational": ["ok"],
|
|
||||||
"maintenance": ["paused"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
"@angular/platform-browser-dynamic": "~10.0.2",
|
"@angular/platform-browser-dynamic": "~10.0.2",
|
||||||
"@angular/platform-server": "~10.0.2",
|
"@angular/platform-server": "~10.0.2",
|
||||||
"@angular/router": "~10.0.2",
|
"@angular/router": "~10.0.2",
|
||||||
"@fortawesome/fontawesome-free": "^5.13.1",
|
"@fortawesome/fontawesome-free": "^5.14.0",
|
||||||
"@nguniversal/express-engine": "^10.0.1",
|
"@nguniversal/express-engine": "^10.0.1",
|
||||||
"bootstrap": "^4.5.0",
|
"bootstrap": "^4.5.0",
|
||||||
"express": "^4.15.2",
|
"express": "^4.17.1",
|
||||||
"jsonpath-plus": "^4.0.0",
|
"jsonpath-plus": "^4.0.0",
|
||||||
"roboto-fontface": "^0.10.0",
|
"roboto-fontface": "^0.10.0",
|
||||||
"rxjs": "~6.6.0",
|
"rxjs": "~6.6.0",
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
"@angular/compiler-cli": "~10.0.2",
|
"@angular/compiler-cli": "~10.0.2",
|
||||||
"@angular/language-service": "~10.0.2",
|
"@angular/language-service": "~10.0.2",
|
||||||
"@nguniversal/builders": "^10.0.1",
|
"@nguniversal/builders": "^10.0.1",
|
||||||
"@types/express": "^4.17.0",
|
"@types/express": "^4.17.7",
|
||||||
"@types/node": "^14.0.14",
|
"@types/node": "^14.0.14",
|
||||||
"@types/jasmine": "~3.5.11",
|
"@types/jasmine": "~3.5.11",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
"zone.js"
|
"zone.js"
|
||||||
],
|
],
|
||||||
"packagePatterns": [
|
"packagePatterns": [
|
||||||
"^angular",
|
"^@angular",
|
||||||
"^karma",
|
"^karma",
|
||||||
"^jasmine"
|
"^jasmine"
|
||||||
],
|
],
|
||||||
|
|
|
@ -8,6 +8,7 @@ export interface CurrentStatus {
|
||||||
export interface Group {
|
export interface Group {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
url?: string;
|
||||||
state: State;
|
state: State;
|
||||||
services: Service[];
|
services: Service[];
|
||||||
}
|
}
|
||||||
|
@ -15,7 +16,7 @@ export interface Group {
|
||||||
export interface Service {
|
export interface Service {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url?: string;
|
||||||
state: State;
|
state: State;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
<mat-accordion [multi]="true">
|
<mat-accordion [multi]="true">
|
||||||
<mat-expansion-panel *ngFor="let group of groups" [expanded]="true">
|
<mat-expansion-panel *ngFor="let group of groups" [expanded]="true">
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title><i [class]="stateClasses[group.state]"></i> {{group.name}}</mat-panel-title>
|
<mat-panel-title>
|
||||||
<!-- <mat-panel-description>-->
|
<i [class]="stateClasses[group.state]"></i>
|
||||||
<!-- <span class="text-capitalize">{{getGroupState(group.services)}}</span>-->
|
<a *ngIf="group.url" class="name" [href]="group.url" target="_blank" (click)="$event.stopPropagation()">{{group.name}}</a>
|
||||||
<!-- </mat-panel-description>-->
|
<span *ngIf="!group.url">{{group.name}}</span>
|
||||||
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
<mat-list>
|
<mat-list>
|
||||||
<a *ngFor="let service of group.services; last as last" mat-list-item [href]="service.url" target="_blank">
|
<a *ngFor="let service of group.services; last as last" mat-list-item [href]="service.url || group.url || '#'" target="_blank">
|
||||||
<div matLine class="d-flex">
|
<div matLine class="d-flex">
|
||||||
<i [class]="stateClasses[service.state]"></i>
|
<i [class]="stateClasses[service.state]"></i>
|
||||||
<span class="text-truncate">{{service.name}}</span>
|
<span class="text-truncate">{{service.name}}</span>
|
||||||
|
|
|
@ -13,6 +13,11 @@
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
&:hover.name, &:hover .name {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-panel-title {
|
mat-panel-title {
|
||||||
|
|
|
@ -12,7 +12,9 @@ interface Config {
|
||||||
authToken: string;
|
authToken: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
statePath: string;
|
servicesPath?: string;
|
||||||
|
idPath?: string;
|
||||||
|
statePath?: string;
|
||||||
stateValues: {
|
stateValues: {
|
||||||
operational: string[];
|
operational: string[];
|
||||||
maintenance: string[];
|
maintenance: string[];
|
||||||
|
@ -20,42 +22,26 @@ interface Config {
|
||||||
groups: {
|
groups: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
url?: string;
|
||||||
services: {
|
services: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url?: string;
|
||||||
statePath?: string;
|
statePath?: string;
|
||||||
stateValues?: {
|
|
||||||
operational?: string[];
|
|
||||||
maintenance?: string[];
|
|
||||||
};
|
|
||||||
}[];
|
}[];
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StateKey {
|
|
||||||
statePath: string;
|
|
||||||
stateValues: {
|
|
||||||
operational: string[];
|
|
||||||
maintenance: string[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const api = Router();
|
const api = Router();
|
||||||
api.use(json());
|
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 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 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), [])
|
.map(g => g.services).reduce((x, y) => x.concat(y), [])
|
||||||
|
.filter(s => s.statePath)
|
||||||
.reduce((services, service) => {
|
.reduce((services, service) => {
|
||||||
services[service.id] = {
|
services[service.id] = service.statePath;
|
||||||
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,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return services;
|
return services;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
@ -68,17 +54,27 @@ api.post('/update/health', (req, res) => {
|
||||||
return res.status(401).send('invalid token');
|
return res.status(401).send('invalid token');
|
||||||
}
|
}
|
||||||
const serviceId = req.query.service as string;
|
const serviceId = req.query.service as string;
|
||||||
const keys = stateKeys[serviceId];
|
let services: { id: string, state: string }[] = [];
|
||||||
const state = JSONPath({path: keys.statePath, json: req.body, wrap: false});
|
if (serviceId) {
|
||||||
|
services = [{id: serviceId, state: JSONPath({path: serviceStatePaths[serviceId], json: req.body, wrap: false})}];
|
||||||
if (keys.stateValues.operational.includes(state)) {
|
} else if (config.servicesPath && config.idPath && config.statePath) {
|
||||||
serviceStates[serviceId] = 'operational';
|
services = JSONPath({path: config.servicesPath, json: req.body})
|
||||||
} else if (keys.stateValues.maintenance.includes(state)) {
|
.map(s => ({
|
||||||
serviceStates[serviceId] = 'maintenance';
|
id: JSONPath({path: config.idPath, json: s, wrap: false}),
|
||||||
} else {
|
state: JSONPath({path: config.statePath, json: s, wrap: false})
|
||||||
serviceStates[serviceId] = 'outage';
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
updateCache();
|
||||||
|
|
||||||
writeFileSync('cache.json', JSON.stringify(serviceStates), {encoding: 'utf-8'});
|
writeFileSync('cache.json', JSON.stringify(serviceStates), {encoding: 'utf-8'});
|
||||||
|
@ -110,6 +106,7 @@ function updateCache(): void {
|
||||||
return {
|
return {
|
||||||
id: group.id,
|
id: group.id,
|
||||||
name: group.name,
|
name: group.name,
|
||||||
|
url: group.url,
|
||||||
state: calculateOverallState(services.map(s => s.state)),
|
state: calculateOverallState(services.map(s => s.state)),
|
||||||
services: services
|
services: services
|
||||||
};
|
};
|
||||||
|
|
Reference in a new issue