feat: add config hash comparison in unified customer page
Compare controller's config_hash from reports against Hub-generated YAML hash. Shows sync status (in sync / mismatch / unknown) on the unified customer detail page next to the Push Config button. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -180,6 +182,37 @@ func (s *Server) handleCustomerUnified(w http.ResponseWriter, r *http.Request, c
|
||||
}
|
||||
}
|
||||
|
||||
// Config hash comparison
|
||||
var controllerConfigHash string
|
||||
var hubConfigHash string
|
||||
var configSyncStatus string // "in_sync", "mismatch", "unknown"
|
||||
if customer != nil && cfg != nil {
|
||||
var rptHash struct {
|
||||
ConfigHash string `json:"config_hash"`
|
||||
}
|
||||
json.Unmarshal([]byte(customer.ReportJSON), &rptHash)
|
||||
controllerConfigHash = rptHash.ConfigHash
|
||||
|
||||
if controllerConfigHash != "" {
|
||||
// Generate Hub-side YAML and compute its hash
|
||||
templateYAML := defaultControllerTemplate
|
||||
if s.templateFetcher != nil {
|
||||
templateYAML = s.templateFetcher.Template()
|
||||
}
|
||||
if yamlOutput, err := configgen.Generate(templateYAML, cfg); err == nil {
|
||||
h := sha256.Sum256([]byte(yamlOutput))
|
||||
hubConfigHash = hex.EncodeToString(h[:])
|
||||
if hubConfigHash == controllerConfigHash {
|
||||
configSyncStatus = "in_sync"
|
||||
} else {
|
||||
configSyncStatus = "mismatch"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
configSyncStatus = "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Version check
|
||||
var latestVersion string
|
||||
var updateAvailable bool
|
||||
@@ -227,6 +260,10 @@ func (s *Server) handleCustomerUnified(w http.ResponseWriter, r *http.Request, c
|
||||
UpdateAvailable bool
|
||||
ControllerURL string
|
||||
|
||||
ConfigSyncStatus string // "in_sync", "mismatch", "unknown"
|
||||
ControllerConfigHash string
|
||||
HubConfigHash string
|
||||
|
||||
InfraBackup *store.InfraBackupMeta
|
||||
InfraBackupAge string
|
||||
NotifPrefs *store.NotificationPrefs
|
||||
@@ -257,6 +294,10 @@ func (s *Server) handleCustomerUnified(w http.ResponseWriter, r *http.Request, c
|
||||
UpdateAvailable: updateAvailable,
|
||||
ControllerURL: controllerURL,
|
||||
|
||||
ConfigSyncStatus: configSyncStatus,
|
||||
ControllerConfigHash: controllerConfigHash,
|
||||
HubConfigHash: hubConfigHash,
|
||||
|
||||
InfraBackup: infraMeta,
|
||||
InfraBackupAge: infraBackupAge,
|
||||
NotifPrefs: notifPrefs,
|
||||
|
||||
@@ -370,6 +370,17 @@
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if and .HasConfig .ConfigSyncStatus}}
|
||||
<div class="info-item" style="margin-top: 0.5rem;">
|
||||
<span class="label">Config Sync</span>
|
||||
<span class="value">
|
||||
{{if eq .ConfigSyncStatus "in_sync"}}<span style="color: #22c55e;">✓ In sync</span>
|
||||
{{else if eq .ConfigSyncStatus "mismatch"}}<span style="color: #f59e0b;">⚠ Config mismatch — Hub config differs from controller</span>
|
||||
{{else}}<span style="color: #94a3b8;">Unknown — controller not reporting config hash (update controller)</span>
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
<div style="margin-top: 0.75em; display: flex; gap: 0.5rem; flex-wrap: wrap;">
|
||||
{{if and .ControllerURL .UpdateAvailable}}
|
||||
<button class="btn btn-sm" id="btn-trigger-update" onclick="triggerControllerUpdate('{{.CustomerID}}')">
|
||||
|
||||
Reference in New Issue
Block a user