chrony honoriert nur EINE bindaddress pro Adressfamilie. Der Generator emittierte aber eine bindaddress PRO Listen-IP (mehrere VLAN-/Cluster-VIPs) → chrony band nur die letzte (10.0.50.1), alle anderen Clients (z. B. auf 10.0.5.1) erreichten den NTP-Server NICHT. Ein Restart hilft nicht (Config-Bug, nicht stale binding). Fix: chrony.cfg.tpl emittiert KEIN bindaddress mehr → bind-all; WER bedient wird, regeln die allow-ACL + die nftables-Regeln (UDP/123 nur auf den Listen-IPs/VIPs offen, nicht öffentlich). Zugleich failover-robust: chrony bedient automatisch jede VIP, die der Node gerade hält, ohne Restart bei Master-Wechsel. Test: internal/chrony/chrony_test.go (kein bindaddress, allow vorhanden; port 0 bei serve_clients=false). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
54 lines
1.8 KiB
Go
54 lines
1.8 KiB
Go
package chrony
|
|
|
|
import (
|
|
"bytes"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/models"
|
|
)
|
|
|
|
func render(t *testing.T, v View) string {
|
|
t.Helper()
|
|
var b bytes.Buffer
|
|
if err := tpl.Execute(&b, v); err != nil {
|
|
t.Fatalf("execute: %v", err)
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
// Mehrere Listen-IPs (VLAN-/Cluster-VIPs): chrony honoriert nur EINE
|
|
// bindaddress pro Adressfamilie → wir dürfen GAR KEINE bindaddress emittieren,
|
|
// sondern bind-all + allow-ACL. Sonst würde nur eine VIP gebunden und alle
|
|
// anderen NTP-Clients liefen ins Leere (Regressions-Schutz).
|
|
func TestRender_NoBindaddress_ServesAllVIPs(t *testing.T) {
|
|
v := View{
|
|
Settings: &models.NTPSettings{ServeClients: true, MakestepSecs: 1, MakestepLimit: 3},
|
|
AllowACLs: []string{"10.0.0.0/8", "192.168.0.0/16"},
|
|
ListenAddresses: []string{"10.0.5.1", "10.0.20.1", "10.10.20.1", "10.0.50.1"},
|
|
}
|
|
out := render(t, v)
|
|
// Auf die DIREKTIVE prüfen (Zeilenanfang), nicht aufs Wort — der
|
|
// erklärende Kommentar im Template enthält „bindaddress" absichtlich.
|
|
if strings.Contains(out, "\nbindaddress ") {
|
|
t.Fatalf("chrony darf KEIN bindaddress emittieren (nur eine pro Familie wird gebunden):\n%s", out)
|
|
}
|
|
for _, acl := range []string{"allow 10.0.0.0/8", "allow 192.168.0.0/16"} {
|
|
if !strings.Contains(out, acl) {
|
|
t.Fatalf("erwarte %q im Output:\n%s", acl, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
// serve_clients=false → reiner Client: port 0, kein Listen-Socket, kein allow.
|
|
func TestRender_NoServeClients_Port0(t *testing.T) {
|
|
v := View{Settings: &models.NTPSettings{ServeClients: false, MakestepSecs: 1, MakestepLimit: 3}}
|
|
out := render(t, v)
|
|
if !strings.Contains(out, "port 0") {
|
|
t.Fatalf("erwarte 'port 0' bei serve_clients=false:\n%s", out)
|
|
}
|
|
if strings.Contains(out, "\nallow ") {
|
|
t.Fatalf("kein allow bei serve_clients=false:\n%s", out)
|
|
}
|
|
}
|