330 lines
8.7 KiB
Go
330 lines
8.7 KiB
Go
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)
|
||
}
|