core/source/logic/master.ts

371 lines
7.6 KiB
TypeScript
Raw Normal View History

2023-08-03 08:34:33 +02:00
namespace _heimdall.master
{
/**
* @todo automated tests
*/
export function determine_due(
check : _heimdall.type_check,
old_item_state : (null | _heimdall.type_item_state),
2023-08-04 09:08:01 +02:00
options : {
timestamp ?: int;
} = {}
2023-08-03 08:34:33 +02:00
) : boolean
{
2023-08-04 09:08:01 +02:00
options = Object.assign(
{
"timestamp": _heimdall.get_current_timestamp(),
},
options
);
2023-08-03 08:34:33 +02:00
return (
2023-08-04 09:08:01 +02:00
check.active
&&
2023-08-03 08:34:33 +02:00
(
2023-08-04 09:08:01 +02:00
(old_item_state === null)
||
((options.timestamp - old_item_state.timestamp) >= check.schedule.regular_interval)
||
(
2023-08-31 19:15:40 +02:00
(old_item_state.count !== null)
&&
(old_item_state.condition !== _heimdall.enum_condition.ok)
2023-08-04 09:08:01 +02:00
&&
((options.timestamp - old_item_state.timestamp) >= check.schedule.attentive_interval)
)
2023-08-03 08:34:33 +02:00
)
);
}
/**
* @todo automated tests
*/
2023-08-31 19:15:40 +02:00
export function determine_shall_send_notification(
2023-08-03 08:34:33 +02:00
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))
&&
2023-08-03 09:46:10 +02:00
(count === check.threshold)
2023-08-03 08:34:33 +02:00
)
||
(
(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(
2023-08-31 16:00:36 +02:00
"misc.cleanup_info",
2023-08-03 08:34:33 +02:00
{
"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,
2023-08-31 19:15:40 +02:00
(check.threshold + 1)
2023-08-03 08:34:33 +02:00
);
if (rows.length <= 0) {
old_item_state = null;
}
else {
2023-08-31 19:15:40 +02:00
let index : int = 1;
while (index < rows.length) {
if (rows[index].condition === rows[0].condition) {
index += 1;
}
else {
break;
2023-08-03 08:34:33 +02:00
}
}
old_item_state = {
"timestamp": rows[0].timestamp,
"condition": rows[0].condition,
2023-08-31 19:15:40 +02:00
"count": ((index < check.threshold) ? index : null),
2023-08-03 08:34:33 +02:00
"last_notification_timestamp": last_notification_timestamp,
2023-08-31 19:15:40 +02:00
};
2023-08-31 16:00:36 +02:00
}
const timestamp : int = _heimdall.get_current_timestamp();
const due : boolean = determine_due(
check,
2023-08-31 19:15:40 +02:00
old_item_state,
{
"timestamp": timestamp,
}
2023-08-31 16:00:36 +02:00
);
if (! due) {
// do nothing
}
else {
process.stderr.write(
lib_plankton.string.coin(
"-- {{check_name}}\n",
{
"check_name": check.name,
}
)
);
2023-08-03 08:34:33 +02:00
2023-08-31 16:00:36 +02:00
// 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(
2023-08-03 08:34:33 +02:00
check,
2023-08-31 16:00:36 +02:00
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,
2023-08-03 08:34:33 +02:00
timestamp,
2023-08-31 16:00:36 +02:00
result.condition,
shall_send_notification,
result.info
2023-08-03 08:34:33 +02:00
);
2023-08-31 16:00:36 +02:00
// send notifications
if (! shall_send_notification) {
2023-08-03 08:34:33 +02:00
// do nothing
}
else {
2023-08-31 16:00:36 +02:00
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
)
2023-08-03 08:34:33 +02:00
)
2023-08-31 16:00:36 +02:00
}
2023-08-03 08:34:33 +02:00
);
}
}
}
}
}
}