|
@@ -5,6 +5,7 @@ import (
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"io"
|
|
"io"
|
|
|
|
|
+ "net"
|
|
|
"net/http"
|
|
"net/http"
|
|
|
"os"
|
|
"os"
|
|
|
"strings"
|
|
"strings"
|
|
@@ -217,6 +218,7 @@ func (s *Server) handleValidate(w http.ResponseWriter, r *http.Request) {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
result := s.validatorSvc.Validate(input)
|
|
result := s.validatorSvc.Validate(input)
|
|
|
|
|
+ s.addManagementAddressWarning(&result, input)
|
|
|
if !result.Valid {
|
|
if !result.Valid {
|
|
|
writeJSON(w, http.StatusBadRequest, model.APIResponse{Code: 3001, Message: "配置校验失败", Data: result})
|
|
writeJSON(w, http.StatusBadRequest, model.APIResponse{Code: 3001, Message: "配置校验失败", Data: result})
|
|
|
return
|
|
return
|
|
@@ -503,6 +505,7 @@ func (s *Server) validateConfigs(inputs []model.InterfaceConfig) model.ValidateR
|
|
|
return result
|
|
return result
|
|
|
}
|
|
}
|
|
|
seen := make(map[string]struct{})
|
|
seen := make(map[string]struct{})
|
|
|
|
|
+ managementInterface := s.currentManagementInterface()
|
|
|
for _, input := range inputs {
|
|
for _, input := range inputs {
|
|
|
name := strings.TrimSpace(input.Interface)
|
|
name := strings.TrimSpace(input.Interface)
|
|
|
if name == "" {
|
|
if name == "" {
|
|
@@ -522,6 +525,9 @@ func (s *Server) validateConfigs(inputs []model.InterfaceConfig) model.ValidateR
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
item := s.validatorSvc.Validate(input)
|
|
item := s.validatorSvc.Validate(input)
|
|
|
|
|
+ if name == managementInterface {
|
|
|
|
|
+ addManagementAddressWarning(&item, input)
|
|
|
|
|
+ }
|
|
|
if !item.Valid {
|
|
if !item.Valid {
|
|
|
result.Valid = false
|
|
result.Valid = false
|
|
|
}
|
|
}
|
|
@@ -535,6 +541,39 @@ func (s *Server) validateConfigs(inputs []model.InterfaceConfig) model.ValidateR
|
|
|
return result
|
|
return result
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func (s *Server) addManagementAddressWarning(result *model.ValidateResponse, input model.InterfaceConfig) {
|
|
|
|
|
+ managementInterface := s.currentManagementInterface()
|
|
|
|
|
+ if managementInterface == "" || strings.TrimSpace(input.Interface) != managementInterface {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ addManagementAddressWarning(result, input)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func addManagementAddressWarning(result *model.ValidateResponse, input model.InterfaceConfig) {
|
|
|
|
|
+ if hasLinkLocalAddress(input) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ result.Warnings = append(result.Warnings, "直连接口未配置 169.254 链路本地地址,可能导致客户端无法通过维护链路发现或连接设备。")
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func hasLinkLocalAddress(input model.InterfaceConfig) bool {
|
|
|
|
|
+ addresses := input.Addresses
|
|
|
|
|
+ if len(addresses) == 0 && strings.TrimSpace(input.IP) != "" {
|
|
|
|
|
+ addresses = []model.InterfaceAddressConfig{{IP: strings.TrimSpace(input.IP), Prefix: input.Prefix}}
|
|
|
|
|
+ }
|
|
|
|
|
+ for _, address := range addresses {
|
|
|
|
|
+ ip := net.ParseIP(strings.TrimSpace(address.IP))
|
|
|
|
|
+ if ip == nil {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ ipv4 := ip.To4()
|
|
|
|
|
+ if ipv4 != nil && ipv4[0] == 169 && ipv4[1] == 254 {
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func (s *Server) rollbackAppliedConfig(taskID string, filePath string, backupPath string, reason string) {
|
|
func (s *Server) rollbackAppliedConfig(taskID string, filePath string, backupPath string, reason string) {
|
|
|
s.log.Warn("apply confirmation failed, restoring netplan file", "task_id", taskID, "file", filePath, "reason", reason)
|
|
s.log.Warn("apply confirmation failed, restoring netplan file", "task_id", taskID, "file", filePath, "reason", reason)
|
|
|
_ = s.netplanSvc.Restore(filePath, backupPath)
|
|
_ = s.netplanSvc.Restore(filePath, backupPath)
|