[add] check_kind:file_state

This commit is contained in:
Christian Fraß 2023-07-06 15:09:34 +02:00
parent a2cc43dffb
commit c27b23d98b
7 changed files with 217 additions and 32 deletions

View file

@ -16,6 +16,7 @@
"help.args.show_schema": "nur das hmdl-JSON-Schema zur Standard-Ausgabe schreiben und beenden",
"help.args.expose_full_order": "nur den Pfad zur Datenbank-Datei zur Standard-Ausgabe schreiben und beenden (nützlich für Fehlersuche)",
"help.args.show_version": "nur die Version zur Standard-Ausgabe schreiben und beenden",
"help.args.verbosity": "Schwellwert für Log-Ausgaben",
"checks.file_state.exists": "Datei existiert (soll aber nicht)",
"checks.file_state.missing": "Datei existiert nicht (soll aber)",
"checks.file_state.timestamp_implausible": "Datei ist scheinbar aus der Zukunft",

View file

@ -16,6 +16,7 @@
"help.args.show_schema": "print the hmdl JSON schema to stdout and exit",
"help.args.expose_full_order": "only print the extended order to stdout and exit (useful for debugging)",
"help.args.show_version": "only print the version to stdout and exit",
"help.args.verbosity": "threshold for log outputs",
"checks.file_state.exists": "file exists (but shall not)",
"checks.file_state.missing": "file does not exist (but shall)",
"checks.file_state.timestamp_implausible": "file is apparently from the future",

View file

@ -102,6 +102,15 @@ namespace _heimdall
};
/**
*/
export function get_current_timestamp(
) : int
{
return Math.floor(Date.now() / 1000);
}
/**
* converts a condition to a human readable string
*/

View file

@ -90,7 +90,7 @@ namespace _heimdall.check_kinds.file_state
) : any
{
const version : string = (
(! ("exist_mode" in node)
(! ("exist_mode" in node))
? "v1"
: "v2"
);
@ -115,6 +115,7 @@ namespace _heimdall.check_kinds.file_state
node
);
return {
"path": node["path"],
"exist_mode": node_["exist"],
"exist_critical": node_["strict"],
"age_threshold_concerning": (
@ -171,7 +172,153 @@ namespace _heimdall.check_kinds.file_state
parameters
) : Promise<_heimdall.type_result>
{
return Promise.reject<_heimdall.type_result>(new Error("not implemented"));
const nm_fs = require("fs");
let condition : _heimdall.enum_condition = _heimdall.enum_condition.ok;
let faults : Array<string> = [];
let data : Record<string, any> = {};
let exists : boolean;
let stats : {
ctime : float;
size : int;
};
await new Promise<void>(
(resolve, reject) => {
nm_fs.stat(
parameters["path"],
{
"bigint": false,
},
(err, stats_) => {
if (err) {
exists = false;
stats = null;
resolve(undefined);
}
else {
exists = true;
stats = stats_;
resolve(undefined);
}
}
);
}
);
if (! parameters["exist_mode"]) {
if (exists) {
condition = (
parameters["exist_critical"]
? _heimdall.enum_condition.concerning
: _heimdall.enum_condition.critical
);
faults.push(lib_plankton.translate.get("checks.file_state.exists"));
}
else {
// do nothing
}
}
else {
if (! exists) {
condition = (
parameters["exist_critical"]
? _heimdall.enum_condition.concerning
: _heimdall.enum_condition.critical
);
faults.push(lib_plankton.translate.get("checks.file_state.missing"));
}
else {
// age
{
const timestamp_this : int = _heimdall.get_current_timestamp();
const timestamp_that : int = Math.floor(stats.ctime);
const age : int = (timestamp_this - timestamp_that);
if (age < 0) {
condition = _heimdall.enum_condition.critical;
faults.push(lib_plankton.translate.get("checks.file_state.timestamp_implausible"));
}
else {
if (
(parameters["age_threshold_critical"] !== null)
&&
(age > parameters["age_threshold_critical"])
) {
condition = _heimdall.enum_condition.critical;
faults.push(lib_plankton.translate.get("checks.file_state.too_old"));
}
else {
if (
(parameters["age_threshold_concerning"] !== null)
&&
(age > parameters["age_threshold_concerning"])
) {
condition = _heimdall.enum_condition.critical;
faults.push(lib_plankton.translate.get("checks.file_state.too_old"));
}
else {
// do nothing
}
}
}
data = Object.assign(
data,
{
"timestamp_of_checking_instance": timestamp_this,
"timestamp_of_file": timestamp_that,
"age_value_in_seconds": age,
"age_threshold_in_seconds_concerning": parameters["age_threshold_concerning"],
"age_threshold_in_seconds_critical": parameters["age_threshold_critical"],
}
);
}
// size
{
const size : int = stats.size;
if (size < 0) {
condition = _heimdall.enum_condition.critical;
faults.push(lib_plankton.translate.get("checks.file_state.size_implausible"));
}
else {
if (
(parameters["size_threshold_critical"] !== null)
&&
(size > parameters["size_threshold_critical"])
) {
condition = _heimdall.enum_condition.critical;
faults.push(lib_plankton.translate.get("checks.file_state.too_big"));
}
else {
if (
(parameters["size_threshold_concerning"] !== null)
&&
(size > parameters["size_threshold_concerning"])
) {
condition = _heimdall.enum_condition.critical;
faults.push(lib_plankton.translate.get("checks.file_state.too_big"));
}
else {
// do nothing
}
}
}
data = Object.assign(
data,
{
"size_value_in_bytes": size,
"size_threshold_in_bytes": parameters["size_threshold"],
}
);
}
}
}
return {
"condition": condition,
"info": {
"path": parameters["path"],
"faults": faults,
"data": data,
}
};
}

View file

@ -151,7 +151,12 @@ async function main(
"indicators_long": ["send-ok-notifications"],
"indicators_short": ["y"],
},
"info": lib_plankton.translate.get("help.args.send_ok_notifications"),
"info": lib_plankton.translate.get(
"help.args.send_ok_notifications",
{
"condition_name": lib_plankton.translate.get("conditions.ok"),
}
),
}
),
"language": new lib_plankton.args.class_argument(
@ -182,6 +187,20 @@ async function main(
"info": lib_plankton.translate.get("help.args.time_to_live"),
}
),
"verbosity": new lib_plankton.args.class_argument(
{
"name": "verbosity",
"type": lib_plankton.args.enum_type.integer,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": 1,
"parameters": {
"indicators_long": ["verbosity"],
"indicators_short": ["v"],
},
"info": lib_plankton.translate.get("help.args.verbosity"),
}
),
}
);
const args : Record<string, any> = arg_handler.read(
@ -189,6 +208,22 @@ async function main(
process.argv.slice(2).join(" ")
);
// setup logging
lib_plankton.log.conf_push(
[
new lib_plankton.log.class_channel_minlevel(
new lib_plankton.log.class_channel_stdout(),
[
lib_plankton.log.enum_level.debug,
lib_plankton.log.enum_level.info,
lib_plankton.log.enum_level.notice,
lib_plankton.log.enum_level.warning,
lib_plankton.log.enum_level.error,
][Math.min(4, args["verbosity"])]
),
]
);
// exec
if (args.show_help) {
process.stdout.write(
@ -211,6 +246,7 @@ async function main(
};
const check_kind_implementations : Record<string, _heimdall.check_kinds.type_check_kind> = {
"http_request": _heimdall.check_kinds.http_request.check_kind_implementation(),
"file_state": _heimdall.check_kinds.file_state.check_kind_implementation(),
};
if (args["show_schema"]) {
process.stdout.write(
@ -308,6 +344,13 @@ async function main(
// 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(
database_path,
check.name
);
const rows : Array<
{
timestamp : int;
@ -319,29 +362,19 @@ async function main(
check.name,
(check.threshold + 1),
);
// TODO: type
let old_item_state : (null | _heimdall.type_item_state);
const last_notification_timestamp : (null | int) = await _heimdall.state_repository.get_last_notification_timestamp(
database_path,
check.name
);
if (rows.length <= 0) {
old_item_state = null;
}
else {
last_notification_timestamp = null;
let count : int = 1;
rows.slice(1).some(
(row) => {
if (row.condition === rows[0].condition) {
count += 1;
return false;
return true;
}
else {
return true;
return false;
}
}
);
@ -351,17 +384,6 @@ async function main(
else {
// do nothing
}
rows.some(
(row) => {
if (row.notification_sent) {
last_notification_timestamp = row.timestamp;
return true;
}
else {
return false;
}
}
);
old_item_state = {
"timestamp": rows[0].timestamp,
"condition": rows[0].condition,
@ -369,7 +391,7 @@ async function main(
"last_notification_timestamp": last_notification_timestamp,
}
const timestamp : int = Math.floor(Date.now() / 1000);
const timestamp : int = _heimdall.get_current_timestamp();
const due : boolean = (
(old_item_state === null)
||

View file

@ -519,10 +519,13 @@ namespace _heimdall.order
throw new Error("circular dependency detected")
}
else {
const order_raw = lib_plankton.json.decode(await lib_plankton.file.read(path));
const order_raw : {
includes ?: Array<string>;
checks ?: Array<any>;
} = lib_plankton.json.decode(await lib_plankton.file.read(path));
let includes : Array<string> = (
("includes" in order_raw)
? order_raw["includes"]
? order_raw.includes
: []
);
for (let index = 0; index < includes.length; index += 1) {
@ -541,9 +544,9 @@ namespace _heimdall.order
}
)
if (! ("checks" in order_raw)) {
order_raw["checks"] = [];
order_raw.checks = [];
}
order_raw["checks"].extend(
order_raw.checks = order_raw.checks.concat(
sub_order.checks
.map(
check => Object.assign(
@ -561,7 +564,7 @@ namespace _heimdall.order
sub_order.checks
)
);
order_raw["includes"] = [];
order_raw.includes = [];
}
return normalize_root(
check_kind_implementations,

View file

@ -26,6 +26,7 @@
"source/logic/notification_kinds/console.ts",
"source/logic/check_kinds/_abstract.ts",
"source/logic/check_kinds/http_request.ts",
"source/logic/check_kinds/file_state.ts",
"source/logic/state_repository.ts",
"source/logic/order.ts",
"source/logic/main.ts"
@ -60,6 +61,7 @@
}
},
{
"active": false,
"name": "node_modules",
"type": "copy",
"parameters": {