netplan.go 3.4 KB

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