| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- package netplan
- import (
- "fmt"
- "os"
- "path/filepath"
- "quickip/internal/model"
- "gopkg.in/yaml.v3"
- )
- type Service struct{}
- type fileConfig struct {
- Network networkConfig `yaml:"network"`
- }
- type networkConfig struct {
- Version int `yaml:"version,omitempty"`
- Ethernets map[string]*ethernetEntry `yaml:"ethernets,omitempty"`
- }
- type ethernetEntry struct {
- DHCP4 *bool `yaml:"dhcp4,omitempty"`
- Addresses []string `yaml:"addresses,omitempty"`
- Gateway4 string `yaml:"gateway4,omitempty"`
- Nameservers *nameserverConfig `yaml:"nameservers,omitempty"`
- Optional *bool `yaml:"optional,omitempty"`
- MTU int `yaml:"mtu,omitempty"`
- WakeOnLAN *bool `yaml:"wakeonlan,omitempty"`
- }
- type nameserverConfig struct {
- Addresses []string `yaml:"addresses,omitempty"`
- }
- func New() *Service { return &Service{} }
- func (s *Service) FindSingleFile() (string, error) {
- files, err := filepath.Glob("/etc/netplan/*.yaml")
- if err != nil {
- return "", err
- }
- if len(files) == 0 {
- return "", fmt.Errorf("未找到 netplan 配置文件")
- }
- if len(files) > 1 {
- return "", fmt.Errorf("检测到多个 netplan 配置文件,首版暂不支持自动处理")
- }
- return files[0], nil
- }
- func (s *Service) Backup(path string) (string, error) {
- backupPath := path + ".quickip.bak"
- if _, err := os.Stat(backupPath); err == nil {
- return backupPath, nil
- }
- data, err := os.ReadFile(path)
- if err != nil {
- return "", err
- }
- if err := os.WriteFile(backupPath, data, 0600); err != nil {
- return "", err
- }
- return backupPath, nil
- }
- func (s *Service) Restore(path string, backupPath string) error {
- data, err := os.ReadFile(backupPath)
- if err != nil {
- return err
- }
- if err := os.WriteFile(path, data, 0600); err != nil {
- return err
- }
- _ = os.Remove(backupPath)
- return nil
- }
- func (s *Service) Write(path string, targetInterface string, input model.InterfaceConfig, managementInterface string, maintenanceCIDR string) error {
- data, err := os.ReadFile(path)
- if err != nil {
- return err
- }
- var cfg fileConfig
- if err := yaml.Unmarshal(data, &cfg); err != nil {
- return err
- }
- if cfg.Network.Version == 0 {
- cfg.Network.Version = 2
- }
- if cfg.Network.Ethernets == nil {
- cfg.Network.Ethernets = make(map[string]*ethernetEntry)
- }
- target := cfg.Network.Ethernets[targetInterface]
- if target == nil {
- target = ðernetEntry{}
- cfg.Network.Ethernets[targetInterface] = target
- }
- dhcpFalse := false
- target.DHCP4 = &dhcpFalse
- target.Addresses = []string{fmt.Sprintf("%s/%d", input.IP, input.Prefix)}
- if input.Gateway != "" {
- target.Gateway4 = input.Gateway
- } else {
- target.Gateway4 = ""
- }
- if len(input.DNS) > 0 {
- target.Nameservers = &nameserverConfig{Addresses: input.DNS}
- } else {
- target.Nameservers = nil
- }
- mgmt := cfg.Network.Ethernets[managementInterface]
- if mgmt == nil {
- mgmt = ðernetEntry{}
- cfg.Network.Ethernets[managementInterface] = mgmt
- }
- dhcpTrue := true
- mgmt.DHCP4 = &dhcpTrue
- if !contains(mgmt.Addresses, maintenanceCIDR) {
- mgmt.Addresses = append(uniqueNonEmpty(mgmt.Addresses), maintenanceCIDR)
- }
- output, err := yaml.Marshal(&cfg)
- if err != nil {
- return err
- }
- return os.WriteFile(path, output, 0600)
- }
- func contains(items []string, target string) bool {
- for _, item := range items {
- if item == target {
- return true
- }
- }
- return false
- }
- func uniqueNonEmpty(items []string) []string {
- seen := make(map[string]struct{})
- result := make([]string, 0, len(items))
- for _, item := range items {
- if item == "" {
- continue
- }
- if _, ok := seen[item]; ok {
- continue
- }
- seen[item] = struct{}{}
- result = append(result, item)
- }
- return result
- }
|