2025-03-12 22:35:36 +03:00

330 lines
8.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}