From a64386db452fb1162a1ef5680f58425cceb15864 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Tue, 17 Mar 2026 09:31:06 -0400 Subject: [PATCH] =?UTF-8?q?4e=20vague=20de=20d=C3=A9mockage=20des=20sondes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- checks/check_life_noc_probe.py | 35 +++++++++ domains.yaml | 72 +++++++++++++++++++ icinga/services/energie.conf | 16 +++-- icinga/services/infrastructure-chezlepro.conf | 32 ++++++--- icinga/services/voiture.conf | 16 +++-- lib/life_noc_inputs.py | 26 +++++++ scripts/generate_services.py | 11 ++- scripts/life_noc_input_api.py | 18 +++++ 8 files changed, 208 insertions(+), 18 deletions(-) diff --git a/checks/check_life_noc_probe.py b/checks/check_life_noc_probe.py index a7bc0c7..fd08967 100755 --- a/checks/check_life_noc_probe.py +++ b/checks/check_life_noc_probe.py @@ -135,6 +135,41 @@ def main() -> int: exit_with(2, f"CRITICAL - {args.label}: seuils incohérents") + elif args.probe_type == "current_value": + if args.source_type != "manual_value": + exit_with(2, f"CRITICAL - source_type non supporté: {args.source_type}") + if args.unit not in {"%", "units", "litres", "volts", "watts"}: + exit_with(2, f"CRITICAL - unité non supportée: {args.unit}") + + if args.inputs_file and args.item_key: + item = load_input_item(args.inputs_file, args.item_key) + metric = float(str(item.get("value", "")).strip()) + elif args.source_value: + metric = float(str(args.source_value).strip()) + else: + raise ValueError("manual_value exige inputs-file/item-key ou source-value") + + unit_suffix = args.unit + + if args.critical_lt is not None and metric < args.critical_lt: + exit_with(2, f"CRITICAL - {args.label}: {metric:.1f} {unit_suffix}") + if args.critical_gte is not None and metric >= args.critical_gte: + exit_with(2, f"CRITICAL - {args.label}: {metric:.1f} {unit_suffix}") + if args.warning_lt is not None and metric < args.warning_lt: + exit_with(1, f"WARNING - {args.label}: {metric:.1f} {unit_suffix}") + if args.warning_gte is not None and metric >= args.warning_gte: + exit_with(1, f"WARNING - {args.label}: {metric:.1f} {unit_suffix}") + if args.ok_gte is not None and metric >= args.ok_gte: + exit_with(0, f"OK - {args.label}: {metric:.1f} {unit_suffix}") + if args.ok_lt is not None and metric < args.ok_lt: + exit_with(0, f"OK - {args.label}: {metric:.1f} {unit_suffix}") + if args.unknown_gte is not None and metric >= args.unknown_gte: + exit_with(3, f"UNKNOWN - {args.label}: {metric:.1f} {unit_suffix}") + if args.unknown_lt is not None and metric < args.unknown_lt: + exit_with(3, f"UNKNOWN - {args.label}: {metric:.1f} {unit_suffix}") + + exit_with(2, f"CRITICAL - {args.label}: seuils incohérents") + else: exit_with(2, f"CRITICAL - probe_type non supporté: {args.probe_type}") diff --git a/domains.yaml b/domains.yaml index cb23c21..27ff8c9 100644 --- a/domains.yaml +++ b/domains.yaml @@ -1014,6 +1014,24 @@ domains: - name: verification-tension-batteries date: 2026-03-15 notes: Vérification des tensions et cohérence des batteries + probe: + type: current_value + source: + type: manual_value + inputs_file: /opt/life-noc/data/inputs/energie.yaml + item_key: verification-tension-batteries + metric: + unit: volts + thresholds: + critical_lt: 50.0 + warning_lt: 51.2 + ok_gte: 51.2 + policy: + on_error: critical + ui: + form_mode: numeric_value + allow_complete: false + allow_manual_edit: true - name: verification-smartshunt date: 2026-03-15 notes: Vérification SmartShunt et cohérence du monitoring @@ -1650,6 +1668,24 @@ domains: - name: verification-batterie-voiture date: 2026-10-01 notes: Vérification de l'état de la batterie automobile + probe: + type: current_value + source: + type: manual_value + inputs_file: /opt/life-noc/data/inputs/voiture.yaml + item_key: verification-batterie-voiture + metric: + unit: volts + thresholds: + critical_lt: 12.2 + warning_lt: 12.5 + ok_gte: 12.5 + policy: + on_error: critical + ui: + form_mode: numeric_value + allow_complete: false + allow_manual_edit: true - name: verification-balais-essuie-glace date: 2026-05-01 notes: Vérification des essuie-glaces @@ -2244,9 +2280,45 @@ domains: - name: verification-ups-infrastructure date: 2026-04-15 notes: Vérification des UPS de l'infrastructure + probe: + type: current_value + source: + type: manual_value + inputs_file: /opt/life-noc/data/inputs/infrastructure-chezlepro.yaml + item_key: verification-ups-infrastructure + metric: + unit: '%' + thresholds: + critical_lt: 25 + warning_lt: 50 + ok_gte: 50 + policy: + on_error: critical + ui: + form_mode: numeric_value + allow_complete: false + allow_manual_edit: true - name: verification-capacite-stockage date: 2026-04-15 notes: Vérifier capacité et croissance du stockage + probe: + type: current_value + source: + type: manual_value + inputs_file: /opt/life-noc/data/inputs/infrastructure-chezlepro.yaml + item_key: verification-capacite-stockage + metric: + unit: '%' + thresholds: + critical_lt: 15 + warning_lt: 25 + ok_gte: 25 + policy: + on_error: critical + ui: + form_mode: numeric_value + allow_complete: false + allow_manual_edit: true - name: verification-apt-cacher-ng date: 2026-05-01 notes: Vérification du bon fonctionnement d'apt-cacher-ng diff --git a/icinga/services/energie.conf b/icinga/services/energie.conf index d99d3d9..ad50226 100644 --- a/icinga/services/energie.conf +++ b/icinga/services/energie.conf @@ -25,11 +25,19 @@ apply Service "energie-inspection-batteries-lifepo4" { } apply Service "energie-verification-tension-batteries" { - import "service_echeance" - vars.date_echeance = "2026-03-15" - vars.mock_state = "OK" - vars.mock_message = "Sous contrôle" + import "service_life_noc_probe" + vars.life_noc_probe_type = "current_value" + vars.life_noc_source_type = "manual_value" + vars.life_noc_source_value = "" + vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/energie.yaml" + vars.life_noc_item_key = "verification-tension-batteries" + vars.life_noc_metric_unit = "volts" + vars.life_noc_label = "verification-tension-batteries" groups = [ "ENERGIE" ] + vars.life_noc_threshold_ok_gte = "51.2" + vars.life_noc_threshold_warning_lt = "51.2" + vars.life_noc_threshold_critical_lt = "50.0" + vars.life_noc_on_error = "critical" notes = "Vérification des tensions et cohérence des batteries" vars.instructions_url = "/life-noc/item/energie/verification-tension-batteries" assign where host.name == "life-noc" diff --git a/icinga/services/infrastructure-chezlepro.conf b/icinga/services/infrastructure-chezlepro.conf index 331e057..d72bc5e 100644 --- a/icinga/services/infrastructure-chezlepro.conf +++ b/icinga/services/infrastructure-chezlepro.conf @@ -76,22 +76,38 @@ apply Service "infrastructure-chezlepro-verification-pbs-truenas" { } apply Service "infrastructure-chezlepro-verification-ups-infrastructure" { - import "service_echeance" - vars.date_echeance = "2026-04-15" - vars.mock_state = "OK" - vars.mock_message = "Sous contrôle" + import "service_life_noc_probe" + vars.life_noc_probe_type = "current_value" + vars.life_noc_source_type = "manual_value" + vars.life_noc_source_value = "" + vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/infrastructure-chezlepro.yaml" + vars.life_noc_item_key = "verification-ups-infrastructure" + vars.life_noc_metric_unit = "%" + vars.life_noc_label = "verification-ups-infrastructure" groups = [ "INFRASTRUCTURE-CHEZLEPRO" ] + vars.life_noc_threshold_ok_gte = "50" + vars.life_noc_threshold_warning_lt = "50" + vars.life_noc_threshold_critical_lt = "25" + vars.life_noc_on_error = "critical" notes = "Vérification des UPS de l'infrastructure" vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-ups-infrastructure" assign where host.name == "life-noc" } apply Service "infrastructure-chezlepro-verification-capacite-stockage" { - import "service_echeance" - vars.date_echeance = "2026-04-15" - vars.mock_state = "OK" - vars.mock_message = "Sous contrôle" + import "service_life_noc_probe" + vars.life_noc_probe_type = "current_value" + vars.life_noc_source_type = "manual_value" + vars.life_noc_source_value = "" + vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/infrastructure-chezlepro.yaml" + vars.life_noc_item_key = "verification-capacite-stockage" + vars.life_noc_metric_unit = "%" + vars.life_noc_label = "verification-capacite-stockage" groups = [ "INFRASTRUCTURE-CHEZLEPRO" ] + vars.life_noc_threshold_ok_gte = "25" + vars.life_noc_threshold_warning_lt = "25" + vars.life_noc_threshold_critical_lt = "15" + vars.life_noc_on_error = "critical" notes = "Vérifier capacité et croissance du stockage" vars.instructions_url = "/life-noc/item/infrastructure-chezlepro/verification-capacite-stockage" assign where host.name == "life-noc" diff --git a/icinga/services/voiture.conf b/icinga/services/voiture.conf index 23a9b75..031446f 100644 --- a/icinga/services/voiture.conf +++ b/icinga/services/voiture.conf @@ -96,11 +96,19 @@ apply Service "voiture-verification-timing-belt" { } apply Service "voiture-verification-batterie-voiture" { - import "service_echeance" - vars.date_echeance = "2026-10-01" - vars.mock_state = "OK" - vars.mock_message = "Sous contrôle" + import "service_life_noc_probe" + vars.life_noc_probe_type = "current_value" + vars.life_noc_source_type = "manual_value" + vars.life_noc_source_value = "" + vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/voiture.yaml" + vars.life_noc_item_key = "verification-batterie-voiture" + vars.life_noc_metric_unit = "volts" + vars.life_noc_label = "verification-batterie-voiture" groups = [ "VOITURE" ] + vars.life_noc_threshold_ok_gte = "12.5" + vars.life_noc_threshold_warning_lt = "12.5" + vars.life_noc_threshold_critical_lt = "12.2" + vars.life_noc_on_error = "critical" notes = "Vérification de l'état de la batterie automobile" vars.instructions_url = "/life-noc/item/voiture/verification-batterie-voiture" assign where host.name == "life-noc" diff --git a/lib/life_noc_inputs.py b/lib/life_noc_inputs.py index 4b5e96e..24c5437 100644 --- a/lib/life_noc_inputs.py +++ b/lib/life_noc_inputs.py @@ -194,4 +194,30 @@ def compute_state_for_item(domain: str, item_key: str) -> str: return "UNKNOWN" return "CRITICAL" + if probe_type == "current_value": + if source_type != "manual_value": + return "CRITICAL" + if metric_unit not in {"%", "units", "litres", "volts", "watts"}: + return "CRITICAL" + + value = float(str(item.get("value", "")).strip()) + + if "critical_lt" in thresholds and value < float(thresholds["critical_lt"]): + return "CRITICAL" + if "critical_gte" in thresholds and value >= float(thresholds["critical_gte"]): + return "CRITICAL" + if "warning_lt" in thresholds and value < float(thresholds["warning_lt"]): + return "WARNING" + if "warning_gte" in thresholds and value >= float(thresholds["warning_gte"]): + return "WARNING" + if "ok_gte" in thresholds and value >= float(thresholds["ok_gte"]): + return "OK" + if "ok_lt" in thresholds and value < float(thresholds["ok_lt"]): + return "OK" + if "unknown_gte" in thresholds and value >= float(thresholds["unknown_gte"]): + return "UNKNOWN" + if "unknown_lt" in thresholds and value < float(thresholds["unknown_lt"]): + return "UNKNOWN" + return "CRITICAL" + return "CRITICAL" diff --git a/scripts/generate_services.py b/scripts/generate_services.py index f59b27a..75ff87c 100644 --- a/scripts/generate_services.py +++ b/scripts/generate_services.py @@ -202,8 +202,8 @@ def validate_probe(item: dict) -> None: raise ValueError("probe doit être un objet") probe_type = str(probe.get("type", "")).strip() - if probe_type not in {"elapsed_time", "days_until_due", "elapsed_distance", "remaining_quantity"}: - raise ValueError("seuls probe.type=elapsed_time, days_until_due, elapsed_distance et remaining_quantity sont supportés") + if probe_type not in {"elapsed_time", "days_until_due", "elapsed_distance", "remaining_quantity", "current_value"}: + raise ValueError("seuls probe.type=elapsed_time, days_until_due, elapsed_distance, remaining_quantity et current_value sont supportés") source = probe.get("source") if not isinstance(source, dict): @@ -228,6 +228,11 @@ def validate_probe(item: dict) -> None: raise ValueError("seul probe.source.type=manual_value est supporté pour remaining_quantity") if not has_store_ref: raise ValueError("probe.source.inputs_file + item_key requis pour remaining_quantity") + elif probe_type == "current_value": + if source_type != "manual_value": + raise ValueError("seul probe.source.type=manual_value est supporté pour current_value") + if not has_store_ref: + raise ValueError("probe.source.inputs_file + item_key requis pour current_value") metric = probe.get("metric") if not isinstance(metric, dict): @@ -239,6 +244,8 @@ def validate_probe(item: dict) -> None: raise ValueError("seul probe.metric.unit=km est supporté pour elapsed_distance") if probe_type == "remaining_quantity" and metric_unit not in {"%", "units", "litres"}: raise ValueError("probe.metric.unit doit être %, units ou litres pour remaining_quantity") + if probe_type == "current_value" and metric_unit not in {"%", "units", "litres", "volts", "watts"}: + raise ValueError("probe.metric.unit doit être %, units, litres, volts ou watts pour current_value") thresholds = probe.get("thresholds") if not isinstance(thresholds, dict): diff --git a/scripts/life_noc_input_api.py b/scripts/life_noc_input_api.py index ae8bda8..d54b491 100644 --- a/scripts/life_noc_input_api.py +++ b/scripts/life_noc_input_api.py @@ -663,6 +663,24 @@ def page_item(domain: str, item_key: str) -> HTMLResponse: """ + elif allow_manual_edit and form_mode == "numeric_value": + unit = str(service.get("probe", {}).get("metric", {}).get("unit", "")).strip() + unit_hint = f" ({html_escape(unit)})" if unit else "" + manual_form_html = f""" +
+

Mettre à jour la valeur

+

Saisir la valeur observée{unit_hint}.

+
+ + +
+ +
+
+
+ """ complete_form_html = "" if allow_complete: