v0.25.0 — Debug page: operator testing & diagnostics dashboard
Debug-mode-only dashboard (/debug) with 8 collapsible sections: system diagnostics, notification testing, backup triggers, storage simulation, hub & connectivity, self-update dry-run, DR/setup wizard, and in-memory log viewer. Migrates debug dump from API router to web server. Adds ring buffer log capture, storage disconnect simulation, event history tracking, and cross-drive/self-update test methods. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -64,7 +65,7 @@ func main() {
|
||||
log.Printf("[WARN] Config load failed (%s), using defaults: %v", *configPath, err)
|
||||
}
|
||||
|
||||
logger := setupLogger(cfg)
|
||||
logger, logBuffer := setupLogger(cfg)
|
||||
|
||||
// --- Setup mode: if no customer ID configured, run setup wizard ---
|
||||
if setup.NeedsSetup(cfg) {
|
||||
@@ -583,8 +584,6 @@ func main() {
|
||||
if assetsSyncer != nil {
|
||||
apiRouter.SetAssetsSyncer(assetsSyncer)
|
||||
}
|
||||
apiRouter.SetDebugDumpDeps(sched, hubPusher, alertMgr, Version, startTime)
|
||||
|
||||
// --- Initialize web server ---
|
||||
webServer := web.NewServer(cfg, stackMgr, cpuCollector, backupMgr, crossDriveRunner, sched, sett, alertMgr, notifier, updater, logger, Version)
|
||||
webServer.SetStorageWatchdog(storageWatchdog)
|
||||
@@ -602,6 +601,53 @@ func main() {
|
||||
}
|
||||
})
|
||||
}
|
||||
if logBuffer != nil {
|
||||
webServer.SetLogBuffer(logBuffer)
|
||||
}
|
||||
webServer.SetStartTime(startTime)
|
||||
|
||||
// Wire debug callbacks (only in debug mode)
|
||||
if cfg.Logging.Level == "debug" {
|
||||
dc := &web.DebugCallbacks{}
|
||||
if hubPusher != nil {
|
||||
dc.TriggerHubReportPush = func() error {
|
||||
r := report.BuildReport(cfg, *configPath, stackMgr, backupMgr, cpuCollector, metricsStore, Version, sett.GetStoragePaths(), logger)
|
||||
return hubPusher.Push(r)
|
||||
}
|
||||
dc.TriggerHubInfraPush = func() error {
|
||||
pushInfraBackup(cfg, sett, stackProv, hubPusher, logger)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
dc.TriggerLocalInfraWrite = func() error {
|
||||
writeLocalInfraBackup(cfg, sett, stackProv, logger)
|
||||
return nil
|
||||
}
|
||||
dc.HubConnectivityTest = func() (int, int64, error) {
|
||||
start := time.Now()
|
||||
resp, err := http.Get(cfg.Hub.URL + "/healthz")
|
||||
latency := time.Since(start).Milliseconds()
|
||||
if err != nil {
|
||||
return 0, latency, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return resp.StatusCode, latency, nil
|
||||
}
|
||||
if cfg.Git.RepoURL != "" {
|
||||
dc.GiteaConnectivityTest = func() (int, int64, error) {
|
||||
start := time.Now()
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := client.Head(cfg.Git.RepoURL)
|
||||
latency := time.Since(start).Milliseconds()
|
||||
if err != nil {
|
||||
return 0, latency, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return resp.StatusCode, latency, nil
|
||||
}
|
||||
}
|
||||
webServer.SetDebugCallbacks(dc)
|
||||
}
|
||||
|
||||
// --- Initialize drive migrator ---
|
||||
driveMigrator := &storage.DriveMigrator{
|
||||
@@ -652,6 +698,8 @@ func main() {
|
||||
mux.HandleFunc("/api/health", apiRouter.HealthHandler)
|
||||
// Storage API routes handled by web server (longer prefix takes precedence over /api/)
|
||||
mux.Handle("/api/storage/", webServer.RequireAuth(webServer.CsrfProtect(http.HandlerFunc(webServer.ServeStorageAPI))))
|
||||
// Debug API routes handled by web server (debug-mode gating inside handler)
|
||||
mux.Handle("/api/debug/", webServer.RequireAuth(webServer.CsrfProtect(http.HandlerFunc(webServer.ServeDebugAPI))))
|
||||
// Self-update API — accepts session auth OR hub API key (for external triggering)
|
||||
// CsrfProtect exempts Bearer-token requests automatically.
|
||||
mux.Handle("/api/selfupdate/", selfUpdateAuthMiddleware(cfg, webServer, webServer.CsrfProtect(http.HandlerFunc(apiRouter.ServeHTTP))))
|
||||
@@ -711,15 +759,13 @@ func selfUpdateAuthMiddleware(cfg *config.Config, webServer *web.Server, next ht
|
||||
})
|
||||
}
|
||||
|
||||
func setupLogger(cfg *config.Config) *log.Logger {
|
||||
// For now, log to stdout. File logging will be added later.
|
||||
logger := log.New(os.Stdout, "", log.LstdFlags)
|
||||
|
||||
func setupLogger(cfg *config.Config) (*log.Logger, *web.LogBuffer) {
|
||||
if cfg.Logging.Level == "debug" {
|
||||
logger.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
logBuffer := web.NewLogBuffer(1000)
|
||||
logger := log.New(io.MultiWriter(os.Stdout, logBuffer), "", log.LstdFlags|log.Lshortfile)
|
||||
return logger, logBuffer
|
||||
}
|
||||
|
||||
return logger
|
||||
return log.New(os.Stdout, "", log.LstdFlags), nil
|
||||
}
|
||||
|
||||
// stackAdapter implements backup.StackDataProvider using stacks.Manager.
|
||||
|
||||
Reference in New Issue
Block a user