Add resiliency primitives: atomic writes, reconcile mutex, state backup
- Add storage.WriteFileAtomic (temp + rename) and storage.CopyFile helpers - Convert all 8 production config writers to atomic writes: config/state.yaml, dnsmasq, nftables, domains, wireguard (config + secrets + peers + wg0.conf), tunnel/cloudflared - Add sync.Mutex to Reconciler to serialize concurrent Reconcile() calls triggered by domain registration goroutines - Add state.yaml backup (.bak) before every write; LoadState falls back to backup if primary is corrupted - Reconciler refuses to use empty config on corruption (only on first run when no state file exists yet)
This commit is contained in:
@@ -11,6 +11,8 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/wild-cloud/wild-central/internal/storage"
|
||||
)
|
||||
|
||||
// Config holds the WireGuard server interface configuration.
|
||||
@@ -110,7 +112,7 @@ func (m *Manager) SaveConfig(cfg *Config) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal vpn config: %w", err)
|
||||
}
|
||||
return os.WriteFile(m.configFilePath(), data, 0644)
|
||||
return storage.WriteFileAtomic(m.configFilePath(), data, 0644)
|
||||
}
|
||||
|
||||
// --- Keys ---
|
||||
@@ -133,7 +135,7 @@ func (m *Manager) GenerateKeypair() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(m.secretsFilePath(), data, 0600)
|
||||
return storage.WriteFileAtomic(m.secretsFilePath(), data, 0600)
|
||||
}
|
||||
|
||||
// GetPublicKey returns the server public key, or empty string if not yet generated.
|
||||
@@ -261,7 +263,7 @@ func (m *Manager) savePeer(p *Peer) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(filepath.Join(m.peersDir(), p.ID+".yaml"), data, 0600)
|
||||
return storage.WriteFileAtomic(filepath.Join(m.peersDir(), p.ID+".yaml"), data, 0600)
|
||||
}
|
||||
|
||||
// nextAvailableIP finds the next unused host IP in the given CIDR (skipping the network
|
||||
@@ -409,7 +411,7 @@ func (m *Manager) Apply() error {
|
||||
if err := os.MkdirAll(filepath.Dir(m.configPath), 0755); err != nil {
|
||||
return fmt.Errorf("create wireguard config dir: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(m.configPath, []byte(content), 0600); err != nil {
|
||||
if err := storage.WriteFileAtomic(m.configPath, []byte(content), 0600); err != nil {
|
||||
return fmt.Errorf("write wireguard config: %w", err)
|
||||
}
|
||||
upCmd := exec.Command("sudo", "wg-quick", "up", "wg0")
|
||||
|
||||
Reference in New Issue
Block a user