Files
alpine-router/network/apply.go
2026-04-13 12:40:49 +03:00

94 lines
2.2 KiB
Go

package network
import (
"fmt"
"os/exec"
"strings"
)
// IfDown brings an interface down via ifdown (or ip link set down as fallback).
func IfDown(name string) error {
out, err := exec.Command("ifdown", "--force", name).CombinedOutput()
if err != nil {
// fallback: ip link set down
out2, err2 := exec.Command("ip", "link", "set", name, "down").CombinedOutput()
if err2 != nil {
return fmt.Errorf("ifdown %s: %s\nip fallback: %s", name, strings.TrimSpace(string(out)), strings.TrimSpace(string(out2)))
}
}
return nil
}
// IfUp brings an interface up via ifup (or ip link set up as fallback).
func IfUp(name string) error {
out, err := exec.Command("ifup", name).CombinedOutput()
if err != nil {
out2, err2 := exec.Command("ip", "link", "set", name, "up").CombinedOutput()
if err2 != nil {
return fmt.Errorf("ifup %s: %s\nip fallback: %s", name, strings.TrimSpace(string(out)), strings.TrimSpace(string(out2)))
}
}
return nil
}
// IfRestart brings an interface down then up.
func IfRestart(name string) error {
_ = IfDown(name) // ignore "already down" errors
return IfUp(name)
}
// ApplyPending merges pending configs into /etc/network/interfaces,
// writes the file, and restarts affected interfaces.
// Returns a per-interface error map (nil key = write error).
func ApplyPending() map[string]error {
errs := map[string]error{}
pending := GetAllPending()
if len(pending) == 0 {
return errs
}
// Read current file config
configs, err := ParseConfig()
if err != nil {
errs["__parse__"] = err
return errs
}
// Merge
for name, cfg := range pending {
configs[name] = cfg
}
// Write file
if err := WriteConfig(configs); err != nil {
errs["__write__"] = err
return errs
}
// Restart each changed interface
for name := range pending {
if name == "lo" {
ClearPendingConfig(name)
continue
}
// For VLAN interfaces ensure the kernel interface exists before ifup.
if IsVLAN(name) {
if err := EnsureVLANExists(name); err != nil {
errs[name] = err
continue
}
}
_ = IfDown(name)
if cfg := configs[name]; cfg != nil && cfg.Auto {
if err := IfUp(name); err != nil {
errs[name] = err
continue
}
}
ClearPendingConfig(name)
}
return errs
}