| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- package network
- import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
- "time"
- )
- const (
- DebianInterfacesPath = "/etc/network/interfaces"
- DebianVlansCfgPath = "/etc/network/interfaces.d/vlans.cfg"
- )
- // PersistenceManager handles writing Debian network configuration files.
- type PersistenceManager struct {
- netMgr *Manager
- }
- func NewPersistenceManager(netMgr *Manager) *PersistenceManager {
- return &PersistenceManager{netMgr: netMgr}
- }
- // GenerateDebianConfig creates the contents of the /etc/network/interfaces.d/vlans.cfg file.
- func (p *PersistenceManager) GenerateDebianConfig() (string, error) {
- vlans, err := p.netMgr.ListVLANs()
- if err != nil {
- return "", err
- }
- var sb strings.Builder
- sb.WriteString(fmt.Sprintf("# ====================================================\n"))
- sb.WriteString(fmt.Sprintf("# Proxmox Router Appliance - VLANs Configuration\n"))
- sb.WriteString(fmt.Sprintf("# Generated: %s\n", time.Now().Format(time.RFC1123)))
- sb.WriteString(fmt.Sprintf("# DO NOT EDIT MANUALLY - Managed via Router Web UI\n"))
- sb.WriteString(fmt.Sprintf("# ====================================================\n\n"))
- if len(vlans) == 0 {
- sb.WriteString("# No VLAN sub-interfaces configured.\n")
- return sb.String(), nil
- }
- for _, v := range vlans {
- sb.WriteString(fmt.Sprintf("# --- VLAN ID %d (%s) ---\n", v.VlanID, v.Name))
- if v.Description != "" {
- sb.WriteString(fmt.Sprintf("# Description: %s\n", v.Description))
- }
- if v.Role != "" {
- sb.WriteString(fmt.Sprintf("# Role: %s\n", v.Role))
- }
- sb.WriteString(fmt.Sprintf("auto %s\n", v.Name))
- if len(v.IPv4) > 0 {
- sb.WriteString(fmt.Sprintf("iface %s inet static\n", v.Name))
- sb.WriteString(fmt.Sprintf(" address %s\n", v.IPv4[0]))
- if v.ParentName != "" {
- sb.WriteString(fmt.Sprintf(" vlan-raw-device %s\n", v.ParentName))
- }
- if v.MTU > 0 && v.MTU != 1500 {
- sb.WriteString(fmt.Sprintf(" mtu %d\n", v.MTU))
- }
- // additional secondary IPv4 addresses
- for i := 1; i < len(v.IPv4); i++ {
- sb.WriteString(fmt.Sprintf(" up ip addr add %s dev %s\n", v.IPv4[i], v.Name))
- sb.WriteString(fmt.Sprintf(" down ip addr del %s dev %s\n", v.IPv4[i], v.Name))
- }
- } else {
- sb.WriteString(fmt.Sprintf("iface %s inet manual\n", v.Name))
- if v.ParentName != "" {
- sb.WriteString(fmt.Sprintf(" vlan-raw-device %s\n", v.ParentName))
- }
- }
- sb.WriteString("\n")
- }
- return sb.String(), nil
- }
- // EnsureSourceInclude ensures that /etc/network/interfaces contains "source /etc/network/interfaces.d/*".
- func (p *PersistenceManager) EnsureSourceInclude() error {
- content, err := os.ReadFile(DebianInterfacesPath)
- if err != nil {
- if os.IsNotExist(err) {
- return nil
- }
- return err
- }
- str := string(content)
- if strings.Contains(str, "source /etc/network/interfaces.d/*") ||
- strings.Contains(str, "source-directory /etc/network/interfaces.d") {
- return nil
- }
- // Append source directive
- newContent := str + "\n# Include extra interface configurations\nsource /etc/network/interfaces.d/*\n"
- return os.WriteFile(DebianInterfacesPath, []byte(newContent), 0644)
- }
- // SaveDebianConfig writes the configuration to disk.
- func (p *PersistenceManager) SaveDebianConfig() (string, error) {
- cfg, err := p.GenerateDebianConfig()
- if err != nil {
- return "", err
- }
- dir := filepath.Dir(DebianVlansCfgPath)
- if err := os.MkdirAll(dir, 0755); err != nil {
- return "", fmt.Errorf("failed to create directory %s: %w", dir, err)
- }
- if err := os.WriteFile(DebianVlansCfgPath, []byte(cfg), 0644); err != nil {
- return "", fmt.Errorf("failed to write %s: %w", DebianVlansCfgPath, err)
- }
- _ = p.EnsureSourceInclude()
- return cfg, nil
- }
|