diff --git a/src/collectors/proxvms/proxvms_linux.go b/src/collectors/proxvms/proxvms_linux.go index 26925fd..60891e3 100644 --- a/src/collectors/proxvms/proxvms_linux.go +++ b/src/collectors/proxvms/proxvms_linux.go @@ -279,24 +279,8 @@ func processQEMUVM(vm VM, nodeName, clusterUID, nodeUID string) map[string]any { machineID = "unknown" } - // Для QEMU VM пытаемся получить UUID из smbios1 - var machineUID string - if smbiosUUID := getString(config, "smbios1"); smbiosUUID != "" { - // Извлекаем UUID из строки типа "uuid=5325693e-271b-47ed-95c2-3a2cf42f4886" - if strings.Contains(smbiosUUID, "uuid=") { - parts := strings.Split(smbiosUUID, "uuid=") - if len(parts) > 1 { - uuid := strings.TrimSpace(parts[1]) - machineUID = generateMachineUID(uuid) - } else { - machineUID = generateMachineUID(machineID) - } - } else { - machineUID = generateMachineUID(machineID) - } - } else { - machineUID = generateMachineUID(machineID) - } + // Генерируем machine_uid + machineUID := generateMachineUID("QEMU", vmidStr, config) // Создаем структуру VM vmData := map[string]any{ @@ -396,7 +380,7 @@ func processLXCContainer(ct VM, nodeName, clusterUID, nodeUID string) map[string } // Генерируем machine_uid - machineUID := generateMachineUID(machineID) + machineUID := generateMachineUID("LXC", vmidStr, config) // Создаем структуру контейнера ctData := map[string]any{ @@ -573,13 +557,123 @@ func generateNodeUID(clusterUUID, nodeID string) string { return hex.EncodeToString(hash[:])[:16] } -// generateMachineUID создает уникальный ID машины на основе machine_id -func generateMachineUID(machineID string) string { - if machineID == "" { - machineID = "unknown-machine-id" +// generateMachineUID генерирует уникальный ID машины для QEMU и LXC +func generateMachineUID(vmType, vmid string, config map[string]interface{}) string { + if vmType == "QEMU" { + return generateQEMUMachineUID(vmid, config) + } else if vmType == "LXC" { + return generateLXCMachineUID(vmid, config) } - hash := sha256.Sum256([]byte(machineID)) - return hex.EncodeToString(hash[:])[:16] + return "" +} + +// generateQEMUMachineUID генерирует machine_uid для QEMU VM +func generateQEMUMachineUID(vmid string, config map[string]interface{}) string { + // 1. Пытаемся получить uuid из конфигурации + if uuid, ok := config["uuid"].(string); ok && uuid != "" { + hash := sha256.Sum256([]byte(uuid)) + return hex.EncodeToString(hash[:])[:16] + } + + // 2. Пытаемся получить smbios1 uuid из конфигурации + if smbios1, ok := config["smbios1"].(string); ok && smbios1 != "" { + // Парсим smbios1 для поиска uuid + if parsed := parseKeyValueString(smbios1); parsed != nil { + if uuid, exists := parsed["uuid"]; exists { + if uuidStr, ok := uuid.(string); ok && uuidStr != "" { + hash := sha256.Sum256([]byte(uuidStr)) + return hex.EncodeToString(hash[:])[:16] + } + } + } + } + + // 3. Fallback: используем machine_id + if machineID, ok := config["machine_id"].(string); ok && machineID != "" { + hash := sha256.Sum256([]byte(machineID)) + return hex.EncodeToString(hash[:])[:16] + } + + return "" +} + +// generateLXCMachineUID генерирует machine_uid для LXC контейнера +func generateLXCMachineUID(vmid string, config map[string]interface{}) string { + // 1. Пытаемся получить machine-id из конфигурации + if machineID, ok := config["machine_id"].(string); ok && machineID != "" { + hash := sha256.Sum256([]byte(machineID)) + return hex.EncodeToString(hash[:])[:16] + } + + // 2. Пытаемся получить machine-id через pct exec (если контейнер запущен) + if machineID := getLXCMachineIDViaExec(vmid); machineID != "" { + hash := sha256.Sum256([]byte(machineID)) + return hex.EncodeToString(hash[:])[:16] + } + + // 3. Пытаемся прочитать machine-id из rootfs (если контейнер остановлен) + if machineID := getLXCMachineIDFromRootfs(vmid); machineID != "" { + hash := sha256.Sum256([]byte(machineID)) + return hex.EncodeToString(hash[:])[:16] + } + + return "" +} + +// getLXCMachineIDViaExec получает machine-id через pct exec (для запущенных контейнеров) +func getLXCMachineIDViaExec(vmid string) string { + cmd := exec.Command("pct", "exec", vmid, "--", "cat", "/etc/machine-id") + output, err := cmd.Output() + if err != nil { + debugLog("Failed to get machine-id via pct exec for LXC %s: %v", vmid, err) + return "" + } + + machineID := strings.TrimSpace(string(output)) + if machineID == "" { + debugLog("Empty machine-id from pct exec for LXC %s", vmid) + return "" + } + + debugLog("Successfully got machine-id via pct exec for LXC %s: %s", vmid, machineID) + return machineID +} + +// getLXCMachineIDFromRootfs читает machine-id из rootfs (для остановленных контейнеров) +func getLXCMachineIDFromRootfs(vmid string) string { + // Пробуем разные возможные пути + paths := []string{ + fmt.Sprintf("/var/lib/lxc/%s/rootfs/etc/machine-id", vmid), + fmt.Sprintf("/rpool/data/subvol-%s-disk-0/etc/machine-id", vmid), + fmt.Sprintf("/var/lib/lxc/%s/rootfs/var/lib/dbus/machine-id", vmid), + } + + for _, path := range paths { + if machineID := readMachineIDFromFile(path); machineID != "" { + debugLog("Successfully read machine-id from %s for LXC %s: %s", path, vmid, machineID) + return machineID + } + } + + debugLog("Failed to read machine-id from rootfs for LXC %s", vmid) + return "" +} + +// readMachineIDFromFile читает machine-id из файла +func readMachineIDFromFile(path string) string { + data, err := os.ReadFile(path) + if err != nil { + debugLog("Failed to read file %s: %v", path, err) + return "" + } + + machineID := strings.TrimSpace(string(data)) + if machineID == "" { + debugLog("Empty machine-id in file %s", path) + return "" + } + + return machineID } // getString извлекает строку из map[string]interface{}