internal/restoretest wiederholt BAK-03s eigene Pruefdiskt als Produktcode: echter Restore der neuesten Sicherung, echter Kurzstart einer isolierten Postgres-Instanz, echte SELECT-1-Abfrage; Objekt-Seite echter restic-Restore + Inhaltspruefung. JSONL-Historie (append-only), sichtbare Warnung ueber denselben OPS-05-Pull-Weg wie BAK-08, eigenes /metrics-Modul (archive-restoretest). Zwei reale Defekte gefunden und behoben: Unix-Socket-Pfadlaenge unter tief verschachtelten Testpfaden, restic-stderr-Vermischung beim JSON-Parsen unter dem Dienstnutzer. Real auf 131 verdrahtet und ausgeloest (beide Testarten erfolgreich, End-zu-Ende ueber OPS-03 bestaetigt).
71 lines
2.5 KiB
Go
71 lines
2.5 KiB
Go
// restoretest-metrics stellt BAK-06s Testlauf-Historie unter /metrics
|
|
// bereit - dauerhafter Prozess getrennt vom Oneshot-restoretest-cli
|
|
// (Pull-Modell, Core OPS-03 scrapt, kein Push - dieselbe Begruendung wie
|
|
// BAK-08s scrub-metrics).
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
|
|
"gitea.perlbach24.de/scripte/nexarch/archive/internal/restoretest"
|
|
)
|
|
|
|
func main() {
|
|
logPath := os.Getenv("NEXARCH_RESTORETEST_LOG")
|
|
if logPath == "" {
|
|
log.Fatal("NEXARCH_RESTORETEST_LOG muss gesetzt sein")
|
|
}
|
|
addr := os.Getenv("NEXARCH_RESTORETEST_METRICS_LISTEN_ADDR")
|
|
if addr == "" {
|
|
addr = ":8091"
|
|
}
|
|
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
|
|
history, err := restoretest.ReadHistory(logPath)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Historie ist append-only (siehe AppendHistory) - die Anzahl
|
|
// fehlgeschlagener Eintraege waechst daher von selbst monoton,
|
|
// kein separater Zaehlerstand noetig (gueltiger Prometheus-Counter).
|
|
var failuresTotal int
|
|
lastSuccess := map[restoretest.Kind]float64{restoretest.KindDatabase: -1, restoretest.KindObjects: -1}
|
|
for _, res := range history {
|
|
if !res.Success {
|
|
failuresTotal++
|
|
}
|
|
if res.Success {
|
|
lastSuccess[res.Kind] = 1
|
|
} else {
|
|
lastSuccess[res.Kind] = 0
|
|
}
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/plain; version=0.0.4")
|
|
body := fmt.Sprintf(
|
|
"# HELP nexarch_archive_restore_test_failures_total Anzahl seit Einrichtung fehlgeschlagener Restore-Testlaeufe (BAK-06).\n"+
|
|
"# TYPE nexarch_archive_restore_test_failures_total counter\n"+
|
|
"nexarch_archive_restore_test_failures_total %d\n"+
|
|
"# HELP nexarch_archive_restore_test_last_success Letzter Testlauf erfolgreich (1) oder fehlgeschlagen (0), -1 wenn noch kein Lauf, je Art.\n"+
|
|
"# TYPE nexarch_archive_restore_test_last_success gauge\n"+
|
|
"nexarch_archive_restore_test_last_success{kind=\"database\"} %g\n"+
|
|
"nexarch_archive_restore_test_last_success{kind=\"objects\"} %g\n",
|
|
failuresTotal, lastSuccess[restoretest.KindDatabase], lastSuccess[restoretest.KindObjects])
|
|
if _, err := w.Write([]byte(body)); err != nil {
|
|
log.Printf("restoretest-metrics: antwort schreiben: %v", err)
|
|
}
|
|
})
|
|
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) })
|
|
|
|
log.Printf("restoretest-metrics: listening on %s", addr)
|
|
if err := http.ListenAndServe(addr, mux); err != nil {
|
|
log.Fatalf("http server: %v", err)
|
|
}
|
|
}
|