371 lines
7.6 KiB
TypeScript
371 lines
7.6 KiB
TypeScript
namespace _heimdall.master
|
|
{
|
|
|
|
/**
|
|
* @todo automated tests
|
|
*/
|
|
export function determine_due(
|
|
check : _heimdall.type_check,
|
|
old_item_state : (null | _heimdall.type_item_state),
|
|
options : {
|
|
timestamp ?: int;
|
|
} = {}
|
|
) : boolean
|
|
{
|
|
options = Object.assign(
|
|
{
|
|
"timestamp": _heimdall.get_current_timestamp(),
|
|
},
|
|
options
|
|
);
|
|
|
|
return (
|
|
check.active
|
|
&&
|
|
(
|
|
(old_item_state === null)
|
|
||
|
|
((options.timestamp - old_item_state.timestamp) >= check.schedule.regular_interval)
|
|
||
|
|
(
|
|
(old_item_state.count !== null)
|
|
&&
|
|
(old_item_state.condition !== _heimdall.enum_condition.ok)
|
|
&&
|
|
((options.timestamp - old_item_state.timestamp) >= check.schedule.attentive_interval)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* @todo automated tests
|
|
*/
|
|
export function determine_shall_send_notification(
|
|
check : _heimdall.type_check,
|
|
send_ok_notifications : boolean,
|
|
count : (null | int),
|
|
timestamp : int,
|
|
old_item_state : (null | _heimdall.type_item_state),
|
|
result : _heimdall.type_result
|
|
) : boolean
|
|
{
|
|
return (
|
|
(
|
|
(
|
|
(! (count === null))
|
|
&&
|
|
(count === check.threshold)
|
|
)
|
|
||
|
|
(
|
|
(count === null)
|
|
&&
|
|
check.annoy
|
|
)
|
|
||
|
|
(
|
|
(count === null)
|
|
&&
|
|
(
|
|
(! (old_item_state === null))
|
|
&&
|
|
(! (old_item_state.last_notification_timestamp === null))
|
|
&&
|
|
(! (check.schedule.reminding_interval === null))
|
|
&&
|
|
(
|
|
(timestamp - old_item_state.last_notification_timestamp)
|
|
>=
|
|
check.schedule.reminding_interval
|
|
)
|
|
)
|
|
)
|
|
)
|
|
&&
|
|
(
|
|
(result.condition !== _heimdall.enum_condition.ok)
|
|
||
|
|
send_ok_notifications
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
export async function clean(
|
|
options : {
|
|
time_to_live ?: int;
|
|
erase_state ?: boolean;
|
|
} = {}
|
|
) : Promise<void>
|
|
{
|
|
options = Object.assign(
|
|
{
|
|
"time_to_live": (7 * 24 * 60 * 60),
|
|
"erase_state": false,
|
|
},
|
|
options
|
|
);
|
|
|
|
const count : int = await _heimdall.state_repository.clean(
|
|
options.time_to_live,
|
|
options.erase_state
|
|
);
|
|
lib_plankton.log.info(
|
|
lib_plankton.translate.get(
|
|
"misc.cleanup_info",
|
|
{
|
|
"count": count.toFixed(0),
|
|
}
|
|
),
|
|
{
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
*/
|
|
export async function wrap_database(
|
|
database_path_raw : (null | string),
|
|
order_path : string,
|
|
procedure : (() => Promise<void>)
|
|
) : Promise<void>
|
|
{
|
|
const nm_path = require("path");
|
|
const database_path : string = (
|
|
(database_path_raw !== null)
|
|
? database_path_raw
|
|
: nm_path.join(
|
|
// TODO get path from fs or path module?
|
|
"/tmp",
|
|
lib_plankton.string.coin(
|
|
"monitoring-state-{{id}}.sqlite",
|
|
{
|
|
"id": lib_plankton.call.convey(
|
|
order_path,
|
|
[
|
|
nm_path.normalize,
|
|
// encode(ascii),
|
|
x => lib_plankton.sha256.get(x),
|
|
x => x.slice(0, 8),
|
|
]
|
|
),
|
|
}
|
|
)
|
|
)
|
|
);
|
|
lib_plankton.log.info(
|
|
lib_plankton.translate.get("misc.state_file_path"),
|
|
{
|
|
"database_path": database_path,
|
|
}
|
|
);
|
|
await _heimdall.state_repository.init(database_path);
|
|
await procedure();
|
|
await _heimdall.state_repository.kill();
|
|
}
|
|
|
|
|
|
/**
|
|
* @todo outsource?
|
|
*/
|
|
export async function wrap_mutex(
|
|
mutex_path : string,
|
|
procedure : (() => Promise<void>)
|
|
) : Promise<void>
|
|
{
|
|
const nm_fs = require("fs");
|
|
if (nm_fs.existsSync(mutex_path)) {
|
|
lib_plankton.log.error(
|
|
lib_plankton.translate.get("misc.still_running"),
|
|
{
|
|
"mutex_path": mutex_path,
|
|
}
|
|
);
|
|
return Promise.reject();
|
|
}
|
|
else {
|
|
await lib_plankton.file.write(mutex_path, "");
|
|
await procedure();
|
|
await lib_plankton.file.delete_(mutex_path);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* central processing procedure
|
|
*/
|
|
export async function run(
|
|
order : _heimdall.type_order,
|
|
options : {
|
|
send_ok_notifications ?: boolean;
|
|
} = {}
|
|
) : Promise<void>
|
|
{
|
|
options = Object.assign(
|
|
{
|
|
"send_ok_notifications": false
|
|
},
|
|
options
|
|
);
|
|
|
|
const notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind> = _heimdall.notification_kinds.get_implementations();
|
|
const check_kind_implementations : Record<string, _heimdall.check_kinds.type_check_kind> = _heimdall.check_kinds.get_implementations();
|
|
for await (const check of order.checks) {
|
|
if (! check.active) {
|
|
// do nothing
|
|
}
|
|
else {
|
|
let old_item_state : (null | _heimdall.type_item_state);
|
|
|
|
const last_notification_timestamp : (null | int) = await _heimdall.state_repository.get_last_notification_timestamp(
|
|
check.name
|
|
);
|
|
|
|
const rows : Array<
|
|
{
|
|
timestamp : int;
|
|
condition : _heimdall.enum_condition;
|
|
notification_sent : boolean;
|
|
}
|
|
> = await _heimdall.state_repository.probe(
|
|
check.name,
|
|
(check.threshold + 1)
|
|
);
|
|
if (rows.length <= 0) {
|
|
old_item_state = null;
|
|
}
|
|
else {
|
|
let index : int = 1;
|
|
while (index < rows.length) {
|
|
if (rows[index].condition === rows[0].condition) {
|
|
index += 1;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
old_item_state = {
|
|
"timestamp": rows[0].timestamp,
|
|
"condition": rows[0].condition,
|
|
"count": ((index < check.threshold) ? index : null),
|
|
"last_notification_timestamp": last_notification_timestamp,
|
|
};
|
|
}
|
|
const timestamp : int = _heimdall.get_current_timestamp();
|
|
const due : boolean = determine_due(
|
|
check,
|
|
old_item_state,
|
|
{
|
|
"timestamp": timestamp,
|
|
}
|
|
);
|
|
if (! due) {
|
|
// do nothing
|
|
}
|
|
else {
|
|
process.stderr.write(
|
|
lib_plankton.string.coin(
|
|
"-- {{check_name}}\n",
|
|
{
|
|
"check_name": check.name,
|
|
}
|
|
)
|
|
);
|
|
|
|
// execute check and set new state
|
|
let result : _heimdall.type_result;
|
|
try {
|
|
result = await check_kind_implementations[check.kind].run(check.parameters);
|
|
}
|
|
catch (error) {
|
|
result = {
|
|
"condition": _heimdall.enum_condition.unknown,
|
|
"info": {
|
|
"cause": lib_plankton.translate.get("misc.check_procedure_failed"),
|
|
"error": error.toString(),
|
|
},
|
|
};
|
|
}
|
|
const count : (null | int) = (
|
|
(
|
|
(old_item_state === null)
|
|
||
|
|
(old_item_state.condition !== result.condition)
|
|
)
|
|
? 1
|
|
: (
|
|
(
|
|
(! (old_item_state.count === null))
|
|
&&
|
|
((old_item_state.count + 1) <= check.threshold)
|
|
)
|
|
? (old_item_state.count + 1)
|
|
: null
|
|
)
|
|
);
|
|
const shall_send_notification : boolean = determine_shall_send_notification(
|
|
check,
|
|
options.send_ok_notifications,
|
|
count,
|
|
timestamp,
|
|
old_item_state,
|
|
result
|
|
);
|
|
const new_item_state : _heimdall.type_item_state = {
|
|
"timestamp": timestamp,
|
|
"condition": result.condition,
|
|
"count": count,
|
|
"last_notification_timestamp": (
|
|
shall_send_notification
|
|
? timestamp
|
|
: (
|
|
(old_item_state === null)
|
|
? null
|
|
: old_item_state.last_notification_timestamp
|
|
)
|
|
),
|
|
}
|
|
await _heimdall.state_repository.feed(
|
|
check.name,
|
|
timestamp,
|
|
result.condition,
|
|
shall_send_notification,
|
|
result.info
|
|
);
|
|
|
|
// send notifications
|
|
if (! shall_send_notification) {
|
|
// do nothing
|
|
}
|
|
else {
|
|
check.notifications.forEach(
|
|
notification => {
|
|
notification_kind_implementations[notification.kind].notify(
|
|
notification.parameters,
|
|
check.name,
|
|
check,
|
|
new_item_state,
|
|
Object.assign(
|
|
(
|
|
(check.custom === null)
|
|
? {}
|
|
: {"custom": check.custom}
|
|
),
|
|
result.info
|
|
)
|
|
)
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|