feat(monitoring): surveillance réseau active via blackbox_exporter

Sondes actives ICMP/HTTP/DNS qui complètent le monitoring passif
(node_exporter + up{}) : joignabilité hôtes/passerelle, accès internet,
santé DNS *.lab.local + forwarding, latence LAN, services de bout en
bout via Traefik.

- blackbox_exporter (chart 11.13.0, ArgoCD, ns monitoring) — ICMP via
  NET_RAW, DNS du pod = dnsmasq (chemin réel lab → Traefik)
- 3 jobs blackbox-icmp/-http/-dns (additionalScrapeConfigs)
- alerts-network.yaml : internet, DNS, passerelle, hôtes, services,
  latence, exporter (→ pipeline AlertManager existant)
- Asa : outil network_status + contexte présélectionnable reseau
- doc admin/infra/reseau.md + CLAUDE.md + progress

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rc3dLKfqEPHexvFCCx5ZEF
This commit is contained in:
Claude 2026-06-25 12:43:13 +00:00
parent ebb2eec184
commit 649c6fde8e
No known key found for this signature in database
11 changed files with 527 additions and 5 deletions

View file

@ -263,12 +263,43 @@ async def metrics_block(client: httpx.AsyncClient) -> str:
return "\n".join(lines) if lines else "Aucune métrique disponible."
async def network_block(client: httpx.AsyncClient) -> str:
"""Surveillance réseau active (sondes blackbox_exporter) : joignabilité,
internet, DNS, latence LAN, et liste des sondes en échec."""
try:
total = await _prom_query(client, 'count(probe_success{job=~"blackbox-.*"})')
up = await _prom_query(client, 'count(probe_success{job=~"blackbox-.*"} == 1)')
internet = await _prom_query(client, 'sum(probe_success{job="blackbox-icmp",scope="internet"})')
dns_lab = await _prom_query(client, 'probe_success{job="blackbox-dns",module="dns_lab"}')
rtt = await _prom_query(client, 'max(probe_icmp_duration_seconds{scope="lan",phase="rtt"})')
failing = await _prom_query(client, 'probe_success{job=~"blackbox-.*"} == 0')
except httpx.HTTPError:
return "Données indisponibles : Prometheus injoignable."
if not total:
return ("Aucune sonde réseau active (blackbox_exporter pas encore déployé "
"ou sans données).")
lines = [f"Sondes réseau OK : {int(up[0][1]) if up else 0}/{int(total[0][1])}."]
if internet:
lines.append("Internet : " + ("accessible" if internet[0][1] > 0 else "INACCESSIBLE") + ".")
if dns_lab:
lines.append("DNS *.lab.local : " + ("OK" if dns_lab[0][1] == 1 else "EN ÉCHEC") + ".")
if rtt:
lines.append(f"Latence LAN max : {round(rtt[0][1] * 1000)} ms.")
if failing:
names = ", ".join(m.get("instance", "?") for m, _ in failing[:8] if m.get("instance"))
lines.append(f"⚠️ Sondes en échec : {names}.")
else:
lines.append("Toutes les sondes répondent.")
return "\n".join(lines)
# Aiguillage source_id → fetcher
_FETCHERS = {
"ghostfolio": ghostfolio_block,
"alerts": alerts_block,
"cluster": cluster_block,
"metrics": metrics_block,
"network": network_block,
}