sonde tableaux : la sante de chaque source de donnees de Grafana
Elle etait verte pendant que les tableaux etaient vides. Eprouvee avec une source recreant le defaut du jour, puis retiree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
8f699eb3ce
commit
b938897e17
3 changed files with 65 additions and 4 deletions
14
CHANGELOG.md
14
CHANGELOG.md
|
|
@ -1,5 +1,19 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 2026-09-28 (24) — La sonde « tableaux » vérifie aussi les sources de données
|
||||||
|
|
||||||
|
Elle était verte pendant que les tableaux des locataires n'affichaient rien : elle
|
||||||
|
demandait si Grafana répond et si sa base tient — pas s'il peut montrer quelque chose.
|
||||||
|
Elle interroge désormais la santé de CHAQUE source de données (`/api/datasources/uid/…/health`)
|
||||||
|
et passe CRITIQUE en nommant celle qui est en défaut. Le mot de passe d'administration est
|
||||||
|
lu là où il est, dans le drop-in systemd de Grafana (0600 root), pas recopié ; illisible, la
|
||||||
|
sonde le dit (avertissement « sources non vérifiées ») au lieu de se taire.
|
||||||
|
|
||||||
|
Éprouvée sur `obs-01` de Technolibre : saine ; puis une source Loki temporaire recréant le
|
||||||
|
défaut du jour (`http://localhost:3100` face à un Loki en HTTPS) → CRITIQUE, source nommée ;
|
||||||
|
source retirée → saine. Déployée sur les trois Grafana : `tableaux` au vert, « sources
|
||||||
|
saines (Loki, Prometheus) ».
|
||||||
|
|
||||||
## 2026-09-28 (23) — Grafana des locataires : aucune donnée, parce que l'URL de Loki ne suivait pas son TLS
|
## 2026-09-28 (23) — Grafana des locataires : aucune donnée, parce que l'URL de Loki ne suivait pas son TLS
|
||||||
|
|
||||||
**Signalé par l'exploitant** : une erreur de plugin et aucun panneau rempli sur les Grafana
|
**Signalé par l'exploitant** : une erreur de plugin et aucun panneau rempli sur les Grafana
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,6 @@
|
||||||
sondes:
|
sondes:
|
||||||
- nom: tableaux
|
- nom: tableaux
|
||||||
ttl: 5400
|
ttl: 5400
|
||||||
raison: 'Grafana repond-il, et sa base tient-elle ? Un Grafana dont la base est tombee sert encore
|
raison: 'Grafana repond-il, sa base tient-elle, et ses SOURCES DE DONNEES aussi ? Un Grafana
|
||||||
sa page de connexion : il a l''air en ligne et ne peut plus rien montrer.'
|
dont la base est tombee sert encore sa page de connexion ; un Grafana dont la source Loki
|
||||||
|
parle en clair a un Loki en HTTPS repond aussi — et n''affiche rien (2026-09-28).'
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,63 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GENERE par Set-OPS (role serveur_grafana). Ne pas editer a la main.
|
# GENERE par Set-OPS (role serveur_grafana). Ne pas editer a la main.
|
||||||
#
|
#
|
||||||
# SONDE « tableaux » — Grafana repond et sa base tient
|
# SONDE « tableaux » — Grafana repond, sa base tient, et ses SOURCES DE DONNEES aussi.
|
||||||
#
|
#
|
||||||
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||||
# Mise en defaut PAR PARAMETRE : `serveur_grafana_sonde_url` (port ferme).
|
# Mise en defaut PAR PARAMETRE : `serveur_grafana_sonde_url` (port ferme).
|
||||||
|
#
|
||||||
|
# LES SOURCES, DEPUIS LE 2026-09-28. Cette sonde etait verte pendant que les tableaux des
|
||||||
|
# locataires n'affichaient RIEN : Grafana repondait, sa base tenait — mais sa source Loki
|
||||||
|
# parlait en clair a un Loki qui servait en HTTPS. Les tableaux tirent leur liste d'hotes de
|
||||||
|
# Loki : vide, aucun panneau ne se remplissait. « Grafana repond » n'etait pas la question ;
|
||||||
|
# « Grafana peut-il montrer quelque chose » l'est.
|
||||||
|
#
|
||||||
|
# LE MOT DE PASSE EST LU LA OU IL EST, pas recopie : dans le drop-in systemd de Grafana,
|
||||||
|
# en 0600 root. La sonde tourne en root ; rien d'autre ne le voit, et il n'est pas affiche.
|
||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
URL={{ serveur_grafana_sonde_url }}
|
URL={{ serveur_grafana_sonde_url }}
|
||||||
|
DROPIN=/etc/systemd/system/grafana-server.service.d/setops.conf
|
||||||
|
|
||||||
s=$(curl -s --max-time 10 "${URL}/api/health" 2>/dev/null)
|
s=$(curl -s --max-time 10 "${URL}/api/health" 2>/dev/null)
|
||||||
[[ -n "${s}" ]] || { echo "Grafana ne repond pas sur ${URL}."; exit 2; }
|
[[ -n "${s}" ]] || { echo "Grafana ne repond pas sur ${URL}."; exit 2; }
|
||||||
base=$(printf '%s' "${s}" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("database","?"))' 2>/dev/null)
|
base=$(printf '%s' "${s}" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("database","?"))' 2>/dev/null)
|
||||||
ver=$(printf '%s' "${s}" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("version","?"))' 2>/dev/null)
|
ver=$(printf '%s' "${s}" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("version","?"))' 2>/dev/null)
|
||||||
[[ "${base}" == "ok" ]] || { echo "Grafana repond mais sa base est en defaut (${base:-illisible})."; exit 2; }
|
[[ "${base}" == "ok" ]] || { echo "Grafana repond mais sa base est en defaut (${base:-illisible})."; exit 2; }
|
||||||
echo "Grafana ${ver} : base ok."
|
|
||||||
|
MDP=$(grep -hoP 'GF_SECURITY_ADMIN_PASSWORD=\K\S+' "${DROPIN}" 2>/dev/null | head -1)
|
||||||
|
if [[ -z "${MDP}" ]]; then
|
||||||
|
echo "Grafana ${ver} : base ok, mais sources NON verifiees (mot de passe illisible dans ${DROPIN})."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
GRAFANA_MDP="${MDP}" python3 - "${URL}" "${ver}" <<'EOF'
|
||||||
|
import base64, json, os, sys, urllib.request
|
||||||
|
url, ver = sys.argv[1], sys.argv[2]
|
||||||
|
auth = "Basic " + base64.b64encode(f"admin:{os.environ['GRAFANA_MDP']}".encode()).decode()
|
||||||
|
def lire(chemin):
|
||||||
|
req = urllib.request.Request(url + chemin, headers={"Authorization": auth})
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=8) as r:
|
||||||
|
return json.loads(r.read())
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
try:
|
||||||
|
return json.loads(e.read())
|
||||||
|
except ValueError:
|
||||||
|
return {"status": "ERROR", "message": f"HTTP {e.code}"}
|
||||||
|
except OSError as e:
|
||||||
|
return {"status": "ERROR", "message": str(e)[:80]}
|
||||||
|
sources = lire("/api/datasources")
|
||||||
|
if not isinstance(sources, list):
|
||||||
|
print(f"Grafana {ver} : base ok, mais la liste des sources est illisible ({str(sources)[:80]}).")
|
||||||
|
sys.exit(1)
|
||||||
|
ko, ok = [], []
|
||||||
|
for d in sources:
|
||||||
|
h = lire(f"/api/datasources/uid/{d['uid']}/health")
|
||||||
|
(ok if h.get("status") == "OK" else ko).append(f"{d['name']} ({str(h.get('message'))[:70]})" if h.get("status") != "OK" else d["name"])
|
||||||
|
perf = f"| sources_ok={len(ok)} sources_ko={len(ko)}"
|
||||||
|
if ko:
|
||||||
|
print(f"Grafana {ver} repond, mais source(s) EN DEFAUT : {'; '.join(ko)} — les tableaux restent vides. {perf}")
|
||||||
|
sys.exit(2)
|
||||||
|
print(f"Grafana {ver} : base ok, sources saines ({', '.join(ok) or 'aucune'}). {perf}")
|
||||||
|
EOF
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue