84 lines
3.5 KiB
JavaScript
84 lines
3.5 KiB
JavaScript
#!/usr/bin/env node
|
||||
|
|
'use strict';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Raise, clear or list ProdDash alerts from the command line — for trying a
|
|||
|
|
* dashboard's channels and the admin colours, or from a script on the
|
|||
|
|
* machine running ProdDash (anything that can POST JSON can raise one).
|
|||
|
|
*
|
|||
|
|
* node tools/alert.js "Service over by 5:00" # low, channel 1, 15 s
|
|||
|
|
* node tools/alert.js -c 2 -l critical -d 0 "LTC lost" # held until cleared
|
|||
|
|
* node tools/alert.js -c 2 --clear
|
|||
|
|
* node tools/alert.js --list
|
|||
|
|
*
|
|||
|
|
* Options: -c/--channel 1–6 (default 1), -l/--level low|medium|critical
|
|||
|
|
* (default low), -d/--duration seconds, 0 to hold until cleared (default the
|
|||
|
|
* server's 15), --url http://host:port (default http://127.0.0.1:24500, or
|
|||
|
|
* $PRODDASH_URL), --clear, --list. Node 18+, no dependencies.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const args = process.argv.slice(2);
|
|||
|
|
const opts = { channel: 1, level: 'low', duration: undefined, url: process.env.PRODDASH_URL || 'http://127.0.0.1:24500', clear: false, list: false };
|
|||
|
|
const words = [];
|
|||
|
|
for (let i = 0; i < args.length; i += 1) {
|
|||
|
|
const a = args[i];
|
|||
|
|
const next = () => args[++i];
|
|||
|
|
if (a === '-c' || a === '--channel') opts.channel = Number(next());
|
|||
|
|
else if (a === '-l' || a === '--level') opts.level = String(next() || '');
|
|||
|
|
else if (a === '-d' || a === '--duration') opts.duration = Number(next());
|
|||
|
|
else if (a === '--url') opts.url = String(next() || opts.url);
|
|||
|
|
else if (a === '--clear') opts.clear = true;
|
|||
|
|
else if (a === '--list') opts.list = true;
|
|||
|
|
else if (a === '-h' || a === '--help') {
|
|||
|
|
console.log('usage: node tools/alert.js [-c 1-6] [-l low|medium|critical] [-d seconds] [--url http://host:port] "text"\n'
|
|||
|
|
+ ' node tools/alert.js -c <n> --clear\n'
|
|||
|
|
+ ' node tools/alert.js --list');
|
|||
|
|
process.exit(0);
|
|||
|
|
} else words.push(a);
|
|||
|
|
}
|
|||
|
|
const base = opts.url.replace(/\/+$/, '');
|
|||
|
|
|
|||
|
|
async function call(path, init) {
|
|||
|
|
const res = await fetch(base + path, init);
|
|||
|
|
const body = await res.json().catch(() => ({}));
|
|||
|
|
if (!res.ok) throw new Error(body.error || `HTTP ${res.status}`);
|
|||
|
|
return body;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
(async () => {
|
|||
|
|
if (opts.list) {
|
|||
|
|
const body = await call('/api/alerts');
|
|||
|
|
const active = body.active || [];
|
|||
|
|
console.log(`${active.length} active alert${active.length === 1 ? '' : 's'}; colours:`,
|
|||
|
|
Object.entries(body.colors || {}).map(([k, v]) => `${k} ${v.join('→')}`).join(', '));
|
|||
|
|
for (const a of active) {
|
|||
|
|
console.log(` channel ${a.channel} ${a.level.padEnd(8)} "${a.text}" from ${a.source}`
|
|||
|
|
+ (a.remainingMs === null ? ' (until cleared)' : ` (${Math.ceil(a.remainingMs / 1000)} s left)`));
|
|||
|
|
}
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (opts.clear) {
|
|||
|
|
const body = await call(`/api/alerts/${opts.channel}`, { method: 'DELETE' });
|
|||
|
|
console.log(body.cleared ? `cleared channel ${opts.channel}` : `nothing was on channel ${opts.channel}`);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const text = words.join(' ').trim();
|
|||
|
|
if (!text) {
|
|||
|
|
console.error('say what happened: node tools/alert.js -c 1 -l critical "LTC lost"');
|
|||
|
|
process.exit(2);
|
|||
|
|
}
|
|||
|
|
const payload = { channel: opts.channel, level: opts.level, text, source: 'cli' };
|
|||
|
|
if (opts.duration !== undefined) payload.duration = opts.duration;
|
|||
|
|
const body = await call('/api/alerts', {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: { 'Content-Type': 'application/json' },
|
|||
|
|
body: JSON.stringify(payload),
|
|||
|
|
});
|
|||
|
|
const a = body.alert;
|
|||
|
|
console.log(`raised ${a.level} on channel ${a.channel}: "${a.text}"`
|
|||
|
|
+ (a.remainingMs === null ? ' (until cleared)' : ` (${a.duration} s)`));
|
|||
|
|
})().catch((err) => {
|
|||
|
|
console.error(err.message || String(err));
|
|||
|
|
process.exit(1);
|
|||
|
|
});
|