Исправлен парсинг данных в коллекторе proxcluster

- Исправлен парсинг /etc/pve/.members - теперь правильно обрабатывает JSON структуру
- Улучшен парсинг corosync.conf для извлечения имен нод
- Исправлено определение онлайн статуса нод (поддержка разных форматов статуса)
- Добавлена отладочная информация для диагностики проблем
- Исправлена проблема с неправильными именами нод в выводе

Автор: Сергей Антропов, сайт: https://devops.org.ru
This commit is contained in:
Sergey Antropoff 2025-09-11 18:54:49 +03:00
parent bb966dcea2
commit 17f5a04c9e
2 changed files with 1887 additions and 10 deletions

1826
prox.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -615,22 +615,45 @@ func getCorosyncInfo(ctx context.Context) (map[string]interface{}, error) {
func getClusterMembers() ([]string, error) {
data, err := os.ReadFile("/etc/pve/.members")
if err != nil {
debugLog("Failed to read /etc/pve/.members: %v", err)
return nil, err
}
// Парсим JSON
var members []string
if err := json.Unmarshal(data, &members); err != nil {
// Если не JSON, пробуем построчно
lines := strings.Split(string(data), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" {
members = append(members, line)
debugLog("Raw .members data: %s", string(data))
// Пробуем парсить как JSON объект
var membersData map[string]interface{}
if err := json.Unmarshal(data, &membersData); err == nil {
debugLog("Parsed .members as JSON object")
// Если это JSON объект, извлекаем имена нод из nodelist
if nodelist, ok := membersData["nodelist"].(map[string]interface{}); ok {
var members []string
for nodeName := range nodelist {
members = append(members, nodeName)
debugLog("Found node in nodelist: %s", nodeName)
}
return members, nil
}
}
// Пробуем парсить как JSON массив
var members []string
if err := json.Unmarshal(data, &members); err == nil {
debugLog("Parsed .members as JSON array with %d members", len(members))
return members, nil
}
debugLog("Failed to parse as JSON, trying line by line")
// Если не JSON, пробуем построчно
lines := strings.Split(string(data), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" {
members = append(members, line)
}
}
debugLog("Parsed %d members from lines", len(members))
return members, nil
}
@ -642,7 +665,6 @@ func getNodeIDsFromCorosync(confPath string, members []string) (map[string]int,
}
nodeIDs := make(map[string]int)
content := string(data)
// Пробуем парсить как JSON сначала
var jsonData map[string]interface{}
@ -661,6 +683,7 @@ func getNodeIDsFromCorosync(confPath string, members []string) (map[string]int,
}
// Если не JSON, используем regex для текстового формата
content := string(data)
for _, member := range members {
// Ищем блок node { ... nodeid: X ... name: member }
re := regexp.MustCompile(`node\s*{[^}]*name:\s*` + member + `[^}]*nodeid:\s*([0-9]+)`)
@ -755,23 +778,44 @@ func checkNodeOnline(ctx context.Context, nodeName string) (bool, error) {
cmd := exec.CommandContext(ctx, "pvesh", "get", "/nodes", "--output-format", "json")
out, err := cmd.Output()
if err != nil {
debugLog("Failed to get nodes list: %v", err)
return false, err
}
debugLog("Raw pvesh nodes output: %s", string(out))
var nodes []map[string]interface{}
if err := json.Unmarshal(out, &nodes); err != nil {
debugLog("Failed to parse nodes JSON: %v", err)
return false, err
}
debugLog("Found %d nodes in pvesh output", len(nodes))
// Ищем нашу ноду в списке
for _, node := range nodes {
if name, ok := node["node"].(string); ok && name == nodeName {
debugLog("Found node %s in pvesh output", nodeName)
// Проверяем разные варианты статуса
if status, ok := node["status"].(string); ok {
debugLog("Node %s status (string): %s", nodeName, status)
return status == "online", nil
}
// Проверяем числовой статус (1 = online, 0 = offline)
if status, ok := node["status"].(float64); ok {
debugLog("Node %s status (float64): %f", nodeName, status)
return status == 1, nil
}
// Проверяем булевый статус
if status, ok := node["status"].(bool); ok {
debugLog("Node %s status (bool): %t", nodeName, status)
return status, nil
}
debugLog("Node %s found but status field is unknown type", nodeName)
}
}
debugLog("Node %s not found in pvesh output", nodeName)
return false, fmt.Errorf("node %s not found", nodeName)
}
@ -918,3 +962,10 @@ func parseNumber(s string) int {
return num
}
// debugLog выводит отладочную информацию (только если установлена переменная окружения DEBUG=1)
func debugLog(format string, args ...interface{}) {
if os.Getenv("DEBUG") == "1" {
fmt.Fprintf(os.Stderr, "[DEBUG] "+format+"\n", args...)
}
}