netplan.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package netplan
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "quickip/internal/model"
  7. "gopkg.in/yaml.v3"
  8. )
  9. type Service struct{}
  10. type fileConfig struct {
  11. Network networkConfig `yaml:"network"`
  12. }
  13. type networkConfig struct {
  14. Version int `yaml:"version,omitempty"`
  15. Ethernets map[string]*ethernetEntry `yaml:"ethernets,omitempty"`
  16. }
  17. type ethernetEntry struct {
  18. DHCP4 *bool `yaml:"dhcp4,omitempty"`
  19. Addresses []string `yaml:"addresses,omitempty"`
  20. Gateway4 string `yaml:"gateway4,omitempty"`
  21. Nameservers *nameserverConfig `yaml:"nameservers,omitempty"`
  22. Optional *bool `yaml:"optional,omitempty"`
  23. MTU int `yaml:"mtu,omitempty"`
  24. WakeOnLAN *bool `yaml:"wakeonlan,omitempty"`
  25. }
  26. type nameserverConfig struct {
  27. Addresses []string `yaml:"addresses,omitempty"`
  28. }
  29. func New() *Service { return &Service{} }
  30. func (s *Service) FindSingleFile() (string, error) {
  31. files, err := filepath.Glob("/etc/netplan/*.yaml")
  32. if err != nil {
  33. return "", err
  34. }
  35. if len(files) == 0 {
  36. return "", fmt.Errorf("未找到 netplan 配置文件")
  37. }
  38. if len(files) > 1 {
  39. return "", fmt.Errorf("检测到多个 netplan 配置文件,首版暂不支持自动处理")
  40. }
  41. return files[0], nil
  42. }
  43. func (s *Service) Backup(path string) (string, error) {
  44. backupPath := path + ".quickip.bak"
  45. if _, err := os.Stat(backupPath); err == nil {
  46. return backupPath, nil
  47. }
  48. data, err := os.ReadFile(path)
  49. if err != nil {
  50. return "", err
  51. }
  52. if err := os.WriteFile(backupPath, data, 0600); err != nil {
  53. return "", err
  54. }
  55. return backupPath, nil
  56. }
  57. func (s *Service) Restore(path string, backupPath string) error {
  58. data, err := os.ReadFile(backupPath)
  59. if err != nil {
  60. return err
  61. }
  62. if err := os.WriteFile(path, data, 0600); err != nil {
  63. return err
  64. }
  65. _ = os.Remove(backupPath)
  66. return nil
  67. }
  68. func (s *Service) Write(path string, targetInterface string, input model.InterfaceConfig, managementInterface string, maintenanceCIDR string) error {
  69. data, err := os.ReadFile(path)
  70. if err != nil {
  71. return err
  72. }
  73. var cfg fileConfig
  74. if err := yaml.Unmarshal(data, &cfg); err != nil {
  75. return err
  76. }
  77. if cfg.Network.Version == 0 {
  78. cfg.Network.Version = 2
  79. }
  80. if cfg.Network.Ethernets == nil {
  81. cfg.Network.Ethernets = make(map[string]*ethernetEntry)
  82. }
  83. target := cfg.Network.Ethernets[targetInterface]
  84. if target == nil {
  85. target = &ethernetEntry{}
  86. cfg.Network.Ethernets[targetInterface] = target
  87. }
  88. dhcpFalse := false
  89. target.DHCP4 = &dhcpFalse
  90. target.Addresses = []string{fmt.Sprintf("%s/%d", input.IP, input.Prefix)}
  91. if input.Gateway != "" {
  92. target.Gateway4 = input.Gateway
  93. } else {
  94. target.Gateway4 = ""
  95. }
  96. if len(input.DNS) > 0 {
  97. target.Nameservers = &nameserverConfig{Addresses: input.DNS}
  98. } else {
  99. target.Nameservers = nil
  100. }
  101. mgmt := cfg.Network.Ethernets[managementInterface]
  102. if mgmt == nil {
  103. mgmt = &ethernetEntry{}
  104. cfg.Network.Ethernets[managementInterface] = mgmt
  105. }
  106. dhcpTrue := true
  107. mgmt.DHCP4 = &dhcpTrue
  108. if !contains(mgmt.Addresses, maintenanceCIDR) {
  109. mgmt.Addresses = append(uniqueNonEmpty(mgmt.Addresses), maintenanceCIDR)
  110. }
  111. output, err := yaml.Marshal(&cfg)
  112. if err != nil {
  113. return err
  114. }
  115. return os.WriteFile(path, output, 0600)
  116. }
  117. func contains(items []string, target string) bool {
  118. for _, item := range items {
  119. if item == target {
  120. return true
  121. }
  122. }
  123. return false
  124. }
  125. func uniqueNonEmpty(items []string) []string {
  126. seen := make(map[string]struct{})
  127. result := make([]string, 0, len(items))
  128. for _, item := range items {
  129. if item == "" {
  130. continue
  131. }
  132. if _, ok := seen[item]; ok {
  133. continue
  134. }
  135. seen[item] = struct{}{}
  136. result = append(result, item)
  137. }
  138. return result
  139. }