package eth import ( "encoding/json" "fmt" "gopkg.in/yaml.v3" "io" "log" "net" "net/http" "network_configurator/models" "os" "os/exec" ) const netplanFilePath = "/etc/netplan/eth.yaml" func NetplanHandler(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: getNetplanConfig(w, r) case http.MethodPut: updateNetplanConfig(w, r) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } func getNetplanConfig(w http.ResponseWriter, r *http.Request) { config, err := readNetplanConfig() if err != nil { http.Error(w, fmt.Sprintf("Failed to read config: %v", err), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(config) } func updateNetplanConfig(w http.ResponseWriter, r *http.Request) { var updatedConfig models.NetplanConfig err := json.NewDecoder(r.Body).Decode(&updatedConfig) if err != nil { http.Error(w, fmt.Sprintf("Failed to decode request body: %v", err), http.StatusBadRequest) return } err = writeNetplanConfig(updatedConfig) if err != nil { http.Error(w, fmt.Sprintf("Failed to write config: %v", err), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) w.Write([]byte("Netplan configuration updated successfully")) } func readNetplanConfig() (*models.NetplanConfig, error) { yamlFile, err := os.ReadFile(netplanFilePath) if err != nil { return nil, fmt.Errorf("failed to read netplan file: %w", err) } var config models.NetplanConfig err = yaml.Unmarshal(yamlFile, &config) if err != nil { return nil, fmt.Errorf("failed to unmarshal yaml: %w", err) } return &config, nil } func writeNetplanConfig(config models.NetplanConfig) error { savedConfig, err := readNetplanConfig() if err != nil { return fmt.Errorf("failed to read eth yaml: %w", err) } yamlData, err := yaml.Marshal(config) if err != nil { return fmt.Errorf("failed to marshal yaml: %w", err) } err = os.WriteFile(netplanFilePath, yamlData, 0644) if err != nil { return fmt.Errorf("failed to write netplan file: %w", err) } cmd := exec.Command("netplan", "apply") output, err := cmd.CombinedOutput() if err != nil { yamlData, err := yaml.Marshal(*savedConfig) if err != nil { return fmt.Errorf("failed to marshal yaml: %w", err) } err = os.WriteFile(netplanFilePath, yamlData, 0644) if err != nil { return fmt.Errorf("failed to write netplan file: %w", err) } return fmt.Errorf("Ошибка при выполнении команды: %s\n Вывод команды: %s\n", err, output) } return nil } func RawNetplanHandler(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: getRawNetplanConfig(w, r) case http.MethodPut: updateRawNetplanConfig(w, r) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } func getRawNetplanConfig(w http.ResponseWriter, r *http.Request) { content, err := readRawNetplanConfig() if err != nil { http.Error(w, fmt.Sprintf("Failed to read raw config: %v", err), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "text/plain") w.Write([]byte(content)) } func updateRawNetplanConfig(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, fmt.Sprintf("Failed to read request body: %v", err), http.StatusBadRequest) return } rawYamlContent := string(body) // Валидация YAML перед записью if !isValidYAML(rawYamlContent) { http.Error(w, "Invalid YAML content", http.StatusBadRequest) return } err = writeRawNetplanConfig(rawYamlContent) if err != nil { http.Error(w, fmt.Sprintf("Failed to write raw config: %v", err), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) w.Write([]byte("Raw Netplan configuration updated successfully")) } func readRawNetplanConfig() (string, error) { yamlFile, err := os.ReadFile(netplanFilePath) if err != nil { return "", fmt.Errorf("failed to read netplan file: %w", err) } return string(yamlFile), nil } func writeRawNetplanConfig(content string) error { savedConfig, err := readRawNetplanConfig() if err != nil { return fmt.Errorf("failed to read eth yaml: %w", err) } err = os.WriteFile(netplanFilePath, []byte(content), 0644) if err != nil { return fmt.Errorf("failed to write netplan file: %w", err) } cmd := exec.Command("netplan", "apply") output, err := cmd.CombinedOutput() if err != nil { err = os.WriteFile(netplanFilePath, []byte(savedConfig), 0644) if err != nil { return fmt.Errorf("failed to write netplan file: %w", err) } return fmt.Errorf("Ошибка при выполнении команды: %s\n Вывод команды: %s\n", err, output) } return nil } // isValidYAML проверяет, является ли строка валидным YAML func isValidYAML(yamlString string) bool { var temp map[interface{}]interface{} err := yaml.Unmarshal([]byte(yamlString), &temp) return err == nil } // Функция для создания тестового файла eth.yaml (для демонстрации) func createTestNetplanFile() { initialYaml := ` network: version: 2 renderer: networkd ethernets: eth0: dhcp4: yes addresses: [192.168.8.111/24] nameservers: addresses: [8.8.8.8, 8.8.4.4] ` err := os.WriteFile(netplanFilePath, []byte(initialYaml), 0644) if err != nil { log.Fatalf("Failed to create test netplan file: %v", err) } fmt.Println("Test netplan file created at:", netplanFilePath) } func init() { // Создаем тестовый файл при запуске сервера, если его нет (для демонстрации) if _, err := os.Stat(netplanFilePath); os.IsNotExist(err) { createTestNetplanFile() } } // MacAdres HTTP handler для получения MAC адреса интерфейса eth0 func MacAdres(w http.ResponseWriter, r *http.Request) { interfaces, err := net.Interfaces() if err != nil { response := models.MacAddressResponse{ Error: fmt.Sprintf("Failed to get network interfaces: %v", err), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) // 500 Internal Server Error json.NewEncoder(w).Encode(response) return } var eth0Interface *net.Interface for _, iface := range interfaces { if iface.Name == "eth0" { eth0Interface = &iface break } } if eth0Interface == nil { response := models.MacAddressResponse{ Error: "Interface eth0 not found", Interface: "eth0", } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) // 404 Not Found json.NewEncoder(w).Encode(response) return } macAddress := eth0Interface.HardwareAddr.String() response := models.MacAddressResponse{ MacAddress: macAddress, Interface: "eth0", } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } // InterfaceIPs HTTP handler для получения списка IP адресов интерфейса eth0 func InterfaceIPs(w http.ResponseWriter, r *http.Request) { interfaces, err := net.Interfaces() if err != nil { response := models.InterfaceIPsResponse{ Error: fmt.Sprintf("Failed to get network interfaces: %v", err), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) // 500 Internal Server Error json.NewEncoder(w).Encode(response) return } var eth0Interface *net.Interface for _, iface := range interfaces { if iface.Name == "eth0" { eth0Interface = &iface break } } if eth0Interface == nil { response := models.InterfaceIPsResponse{ Interface: "eth0", Error: "Interface eth0 not found", } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) // 404 Not Found json.NewEncoder(w).Encode(response) return } addrs, err := eth0Interface.Addrs() if err != nil { response := models.InterfaceIPsResponse{ Interface: "eth0", Error: fmt.Sprintf("Failed to get addresses for eth0: %v", err), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) // 500 Internal Server Error json.NewEncoder(w).Encode(response) return } ipAddresses := make([]string, 0) for _, addr := range addrs { if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil || ipnet.IP.To16() != nil { ipAddresses = append(ipAddresses, ipnet.IP.String()) } } } response := models.InterfaceIPsResponse{ Interface: "eth0", IPAddresses: ipAddresses, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) // 200 OK json.NewEncoder(w).Encode(response) }