build / build-push (push) Successful in 29s
Local zones were only editable as mounted files, so operators could not manage DNS entries from the console. Add a Local zones editor backed by a shared Kubernetes ConfigMap, validate master files before saving, scope the pod service account to that ConfigMap, and reload changed zones on every replica while flushing stale cache entries.
77 lines
1.7 KiB
Go
77 lines
1.7 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
// watchLocalZones reloads projected ConfigMap files on every replica. A
|
|
// Kubernetes ConfigMap volume swaps its ..data symlink atomically when the UI
|
|
// edits a zone; polling the contents keeps both pods in sync without routing
|
|
// DNS changes through a single pod.
|
|
func (a *App) watchLocalZones(ctx context.Context) {
|
|
if a.zones == nil {
|
|
return
|
|
}
|
|
last, _ := a.localZoneFingerprint()
|
|
ticker := time.NewTicker(2 * time.Second)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
next, err := a.localZoneFingerprint()
|
|
if err != nil {
|
|
a.log.Warn("local zone change check failed", "error", err)
|
|
continue
|
|
}
|
|
if next == last {
|
|
continue
|
|
}
|
|
a.reloadLocalZones()
|
|
if a.cache != nil {
|
|
a.cache.Flush()
|
|
}
|
|
last = next
|
|
}
|
|
}
|
|
}
|
|
|
|
func (a *App) localZoneFingerprint() (string, error) {
|
|
paths := make([]string, 0)
|
|
for _, configured := range a.cfg.Get().Block.LocalZones {
|
|
path := a.cfg.Get().AbsPath(configured)
|
|
if matches, err := filepath.Glob(path); err == nil && len(matches) > 0 {
|
|
paths = append(paths, matches...)
|
|
continue
|
|
}
|
|
if info, err := os.Stat(path); err == nil && info.IsDir() {
|
|
matches, err := filepath.Glob(filepath.Join(path, "*.zone"))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
paths = append(paths, matches...)
|
|
continue
|
|
}
|
|
}
|
|
sort.Strings(paths)
|
|
h := sha256.New()
|
|
for _, path := range paths {
|
|
b, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return "", fmt.Errorf("read %s: %w", path, err)
|
|
}
|
|
_, _ = h.Write([]byte(path))
|
|
_, _ = h.Write([]byte{0})
|
|
_, _ = h.Write(b)
|
|
_, _ = h.Write([]byte{0})
|
|
}
|
|
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
|
}
|