From febdc502c4ff4e9f446045271c79dbec50a8ba76 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Sat, 14 Mar 2026 18:16:15 -0400 Subject: [PATCH] =?UTF-8?q?Ajoute=20un=20store=20d=E2=80=99intrants=20pour?= =?UTF-8?q?=20les=20sondes=20elapsed=5Ftime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- checks/check_life_noc_probe.py | 40 +++++++++++++++++++++-- data/inputs/revue.yaml | 9 +++++ domains.yaml | 8 +++-- icinga/commands/check_life_noc_probe.conf | 2 ++ icinga/services/revue.conf | 8 +++-- scripts/generate_services.py | 12 +++++-- 6 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 data/inputs/revue.yaml diff --git a/checks/check_life_noc_probe.py b/checks/check_life_noc_probe.py index 3302646..0c957e5 100644 --- a/checks/check_life_noc_probe.py +++ b/checks/check_life_noc_probe.py @@ -2,6 +2,9 @@ import argparse from datetime import datetime, timezone +from pathlib import Path +import sys +import yaml def exit_with(code: int, text: str) -> None: @@ -13,11 +16,35 @@ def parse_date(value: str) -> datetime: return datetime.strptime(value, "%Y-%m-%d").replace(tzinfo=timezone.utc) +def load_input_value(inputs_file: str, item_key: str) -> str: + path = Path(inputs_file) + if not path.exists(): + raise ValueError(f"inputs file introuvable: {inputs_file}") + + data = yaml.safe_load(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError(f"inputs file invalide: {inputs_file}") + + if item_key not in data: + raise ValueError(f"item_key introuvable dans le store: {item_key}") + + item = data[item_key] + if not isinstance(item, dict): + raise ValueError(f"entrée invalide pour item_key: {item_key}") + + if "value" not in item: + raise ValueError(f"champ 'value' absent pour item_key: {item_key}") + + return str(item["value"]).strip() + + def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--probe-type", required=True) ap.add_argument("--source-type", required=True) - ap.add_argument("--source-value", required=True) + ap.add_argument("--source-value") + ap.add_argument("--inputs-file") + ap.add_argument("--item-key") ap.add_argument("--unit", required=True) ap.add_argument("--unknown-lt", type=float) ap.add_argument("--ok-gte", type=float) @@ -37,7 +64,16 @@ def main() -> int: if args.unit != "days": exit_with(2, f"CRITICAL - unité non supportée: {args.unit}") - dt = parse_date(args.source_value) + source_value = None + + if args.inputs_file and args.item_key: + source_value = load_input_value(args.inputs_file, args.item_key) + elif args.source_value: + source_value = args.source_value + else: + raise ValueError("aucune source fournie: inputs-file/item-key ou source-value requis") + + dt = parse_date(source_value) now = datetime.now(timezone.utc) delta_days = (now - dt).total_seconds() / 86400.0 diff --git a/data/inputs/revue.yaml b/data/inputs/revue.yaml new file mode 100644 index 0000000..050778d --- /dev/null +++ b/data/inputs/revue.yaml @@ -0,0 +1,9 @@ +revue-quotidienne-life-noc: + value: "2026-03-14" + captured_at: "2026-03-14T08:00:00Z" + origin: manual + +revue-hebdomadaire-priorites: + value: "2026-03-10" + captured_at: "2026-03-14T08:00:00Z" + origin: manual diff --git a/domains.yaml b/domains.yaml index 2f422b9..61761f9 100644 --- a/domains.yaml +++ b/domains.yaml @@ -8,7 +8,8 @@ domains: type: elapsed_time source: type: manual_date - value: "2026-03-13" + inputs_file: "/opt/life-noc/data/inputs/revue.yaml" + item_key: "revue-quotidienne-life-noc" metric: unit: days thresholds: @@ -18,7 +19,7 @@ domains: critical_gte: 3 policy: on_error: critical - + - name: revue-hebdomadaire-priorites date: "2026-03-10" notes: Revoir les priorités de la semaine @@ -26,7 +27,8 @@ domains: type: elapsed_time source: type: manual_date - value: "2026-03-10" + inputs_file: "/opt/life-noc/data/inputs/revue.yaml" + item_key: "revue-hebdomadaire-priorites" metric: unit: days thresholds: diff --git a/icinga/commands/check_life_noc_probe.conf b/icinga/commands/check_life_noc_probe.conf index a319637..2c5b33b 100644 --- a/icinga/commands/check_life_noc_probe.conf +++ b/icinga/commands/check_life_noc_probe.conf @@ -5,6 +5,8 @@ object CheckCommand "check_life_noc_probe" { "--probe-type" = "$life_noc_probe_type$" "--source-type" = "$life_noc_source_type$" "--source-value" = "$life_noc_source_value$" + "--inputs-file" = "$life_noc_inputs_file$" + "--item-key" = "$life_noc_item_key$" "--unit" = "$life_noc_metric_unit$" "--unknown-lt" = "$life_noc_threshold_unknown_lt$" "--ok-gte" = "$life_noc_threshold_ok_gte$" diff --git a/icinga/services/revue.conf b/icinga/services/revue.conf index 84a0a09..c1119a5 100644 --- a/icinga/services/revue.conf +++ b/icinga/services/revue.conf @@ -8,7 +8,9 @@ apply Service "revue-revue-quotidienne-life-noc" { import "service_life_noc_probe" vars.life_noc_probe_type = "elapsed_time" vars.life_noc_source_type = "manual_date" - vars.life_noc_source_value = "2026-03-13" + vars.life_noc_source_value = "" + vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/revue.yaml" + vars.life_noc_item_key = "revue-quotidienne-life-noc" vars.life_noc_metric_unit = "days" vars.life_noc_label = "revue-quotidienne-life-noc" groups = [ "REVUE" ] @@ -25,7 +27,9 @@ apply Service "revue-revue-hebdomadaire-priorites" { import "service_life_noc_probe" vars.life_noc_probe_type = "elapsed_time" vars.life_noc_source_type = "manual_date" - vars.life_noc_source_value = "2026-03-10" + vars.life_noc_source_value = "" + vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/revue.yaml" + vars.life_noc_item_key = "revue-hebdomadaire-priorites" vars.life_noc_metric_unit = "days" vars.life_noc_label = "revue-hebdomadaire-priorites" groups = [ "REVUE" ] diff --git a/scripts/generate_services.py b/scripts/generate_services.py index 2aa09b9..e7373a9 100644 --- a/scripts/generate_services.py +++ b/scripts/generate_services.py @@ -128,7 +128,9 @@ def render_probe_service(domain: str, group_name: str, item: dict) -> str: f' import "{PROBE_TEMPLATE}"', f' vars.life_noc_probe_type = "{icinga_escape(probe_type)}"', f' vars.life_noc_source_type = "{icinga_escape(str(source["type"]).strip())}"', - f' vars.life_noc_source_value = "{icinga_escape(str(source["value"]).strip())}"', + f' vars.life_noc_source_value = "{icinga_escape(str(source.get("value", "")).strip())}"', + f' vars.life_noc_inputs_file = "{icinga_escape(str(source.get("inputs_file", "")).strip())}"', + f' vars.life_noc_item_key = "{icinga_escape(str(source.get("item_key", name)).strip())}"', f' vars.life_noc_metric_unit = "{icinga_escape(str(metric["unit"]).strip())}"', f' vars.life_noc_label = "{icinga_escape(name)}"', f' groups = [ "{icinga_escape(group_name)}" ]', @@ -173,8 +175,12 @@ def validate_probe(item: dict) -> None: raise ValueError("probe.source doit être un objet") if str(source.get("type", "")).strip() != "manual_date": raise ValueError("seul probe.source.type=manual_date est supporté en v1") - if "value" not in source: - raise ValueError("probe.source.value est requis") + + has_inline_value = "value" in source + has_store_ref = "inputs_file" in source and "item_key" in source + + if not has_inline_value and not has_store_ref: + raise ValueError("probe.source.value ou probe.source.inputs_file + item_key requis") metric = probe.get("metric") if not isinstance(metric, dict):