netplan.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package netplan
  2. import (
  3. "bytes"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "networktool/internal/model"
  8. "gopkg.in/yaml.v3"
  9. )
  10. type Service struct{}
  11. type fileConfig struct {
  12. Network map[string]any `yaml:"network"`
  13. }
  14. func New() *Service { return &Service{} }
  15. func (s *Service) FindSingleFile() (string, error) {
  16. files, err := filepath.Glob("/etc/netplan/*.yaml")
  17. if err != nil {
  18. return "", err
  19. }
  20. if len(files) == 0 {
  21. return "", fmt.Errorf("未找到 netplan 配置文件")
  22. }
  23. if len(files) > 1 {
  24. return "", fmt.Errorf("检测到多个 netplan 配置文件,首版暂不支持自动处理")
  25. }
  26. return files[0], nil
  27. }
  28. func (s *Service) Backup(path string) (string, error) {
  29. backupPath := path + ".networktool.bak"
  30. data, err := os.ReadFile(path)
  31. if err != nil {
  32. return "", err
  33. }
  34. if err := os.WriteFile(backupPath, data, 0600); err != nil {
  35. return "", err
  36. }
  37. return backupPath, nil
  38. }
  39. func (s *Service) Restore(path string, backupPath string) error {
  40. data, err := os.ReadFile(backupPath)
  41. if err != nil {
  42. return err
  43. }
  44. if err := os.WriteFile(path, data, 0600); err != nil {
  45. return err
  46. }
  47. _ = os.Remove(backupPath)
  48. return nil
  49. }
  50. func (s *Service) Write(path string, targetInterface string, input model.InterfaceConfig, managementInterface string, maintenanceCIDR string) error {
  51. data, err := os.ReadFile(path)
  52. if err != nil {
  53. return err
  54. }
  55. var cfg fileConfig
  56. if err := yaml.Unmarshal(data, &cfg); err != nil {
  57. return err
  58. }
  59. if cfg.Network == nil {
  60. cfg.Network = make(map[string]any)
  61. }
  62. if _, ok := cfg.Network["version"]; !ok {
  63. cfg.Network["version"] = 2
  64. }
  65. ethernets := ensureMap(cfg.Network, "ethernets")
  66. target := ensureMap(ethernets, targetInterface)
  67. if input.Dhcp4 {
  68. target["dhcp4"] = true
  69. delete(target, "addresses")
  70. delete(target, "gateway4")
  71. delete(target, "routes")
  72. delete(target, "nameservers")
  73. output, err := marshalYAML(&cfg)
  74. if err != nil {
  75. return err
  76. }
  77. return os.WriteFile(path, output, 0600)
  78. }
  79. target["dhcp4"] = false
  80. target["addresses"] = []string{fmt.Sprintf("%s/%d", input.IP, input.Prefix)}
  81. delete(target, "gateway4")
  82. if input.Gateway != "" {
  83. target["routes"] = []map[string]string{{"to": "default", "via": input.Gateway}}
  84. } else {
  85. delete(target, "routes")
  86. }
  87. if len(input.DNS) > 0 {
  88. nameservers := ensureMap(target, "nameservers")
  89. nameservers["addresses"] = input.DNS
  90. } else {
  91. delete(target, "nameservers")
  92. }
  93. output, err := marshalYAML(&cfg)
  94. if err != nil {
  95. return err
  96. }
  97. return os.WriteFile(path, output, 0600)
  98. }
  99. func marshalYAML(value any) ([]byte, error) {
  100. var output bytes.Buffer
  101. encoder := yaml.NewEncoder(&output)
  102. encoder.SetIndent(2)
  103. if err := encoder.Encode(value); err != nil {
  104. _ = encoder.Close()
  105. return nil, err
  106. }
  107. if err := encoder.Close(); err != nil {
  108. return nil, err
  109. }
  110. return output.Bytes(), nil
  111. }
  112. func ensureMap(parent map[string]any, key string) map[string]any {
  113. if existing, ok := parent[key].(map[string]any); ok {
  114. return existing
  115. }
  116. child := make(map[string]any)
  117. parent[key] = child
  118. return child
  119. }
  120. func anyToStringSlice(value any) []string {
  121. switch typed := value.(type) {
  122. case []string:
  123. return append([]string(nil), typed...)
  124. case []any:
  125. result := make([]string, 0, len(typed))
  126. for _, item := range typed {
  127. text, ok := item.(string)
  128. if ok {
  129. result = append(result, text)
  130. }
  131. }
  132. return result
  133. default:
  134. return nil
  135. }
  136. }
  137. func contains(items []string, target string) bool {
  138. for _, item := range items {
  139. if item == target {
  140. return true
  141. }
  142. }
  143. return false
  144. }
  145. func uniqueNonEmpty(items []string) []string {
  146. seen := make(map[string]struct{})
  147. result := make([]string, 0, len(items))
  148. for _, item := range items {
  149. if item == "" {
  150. continue
  151. }
  152. if _, ok := seen[item]; ok {
  153. continue
  154. }
  155. seen[item] = struct{}{}
  156. result = append(result, item)
  157. }
  158. return result
  159. }