feat: улучшен парсинг конфигурации в коллекторе proxvms

- Добавлен парсинг nameserver в формат dns1: ip1, dns2: ip2
- Добавлен парсинг searchdomain в структурированный формат
- Добавлен парсинг features в структурированный формат
- Переименовано description_parsed в description
- Переименовано pool_disk_size в pool_disk_size_gb
- Добавлена конвертация единиц измерения: T в GB, M в GB
- Улучшена логика удаления оригинальных полей после успешного парсинга
This commit is contained in:
Sergey Antropoff 2025-09-15 13:09:21 +03:00
parent 15e6260ac3
commit 96b841d6c8

View File

@ -349,7 +349,7 @@ func processQEMUVM(vm VM, nodeName, clusterUID, nodeUID string) map[string]any {
// Парсим JSON из поля description // Парсим JSON из поля description
if description, ok := config["description"].(string); ok { if description, ok := config["description"].(string); ok {
if parsedDesc := parseDescriptionJSON(description); parsedDesc != nil { if parsedDesc := parseDescriptionJSON(description); parsedDesc != nil {
config["description_parsed"] = parsedDesc config["description"] = parsedDesc
// Удаляем оригинальное поле description, если парсинг прошел успешно // Удаляем оригинальное поле description, если парсинг прошел успешно
delete(config, "description") delete(config, "description")
} }
@ -442,7 +442,7 @@ func processLXCContainer(ct VM, nodeName, clusterUID, nodeUID string) map[string
// Парсим JSON из поля description // Парсим JSON из поля description
if description, ok := config["description"].(string); ok { if description, ok := config["description"].(string); ok {
if parsedDesc := parseDescriptionJSON(description); parsedDesc != nil { if parsedDesc := parseDescriptionJSON(description); parsedDesc != nil {
config["description_parsed"] = parsedDesc config["description"] = parsedDesc
// Удаляем оригинальное поле description, если парсинг прошел успешно // Удаляем оригинальное поле description, если парсинг прошел успешно
delete(config, "description") delete(config, "description")
} }
@ -501,6 +501,24 @@ func enrichConfigWithParsedData(config map[string]interface{}) {
// Удаляем оригинальные mpX поля, если они были распарсены // Удаляем оригинальные mpX поля, если они были распарсены
removeParsedFields(config, "mp") removeParsedFields(config, "mp")
} }
// Парсим nameserver
if nameserver := parseNameserver(config); nameserver != nil {
config["nameserver"] = nameserver
delete(config, "nameserver")
}
// Парсим searchdomain
if searchdomain := parseSearchdomain(config); searchdomain != nil {
config["searchdomain"] = searchdomain
delete(config, "searchdomain")
}
// Парсим features
if features := parseFeatures(config); features != nil {
config["features"] = features
delete(config, "features")
}
} }
// removeParsedFields удаляет оригинальные поля, которые были успешно распарсены // removeParsedFields удаляет оригинальные поля, которые были успешно распарсены
@ -784,9 +802,9 @@ func parseSCSIConfig(value interface{}) map[string]interface{} {
val := strings.TrimSpace(part[equalIndex+1:]) val := strings.TrimSpace(part[equalIndex+1:])
if key != "" { if key != "" {
// Переименовываем size в pool_disk_size для SCSI устройств // Переименовываем size в pool_disk_size_gb для SCSI устройств и конвертируем единицы
if key == "size" { if key == "size" {
result["pool_disk_size"] = val result["pool_disk_size_gb"] = convertToGB(val)
} else { } else {
result[key] = val result[key] = val
} }
@ -981,6 +999,131 @@ func parseMPDevices(config map[string]interface{}) map[string]interface{} {
return mp return mp
} }
// parseNameserver парсит nameserver в формат dns1: ip1, dns2: ip2
func parseNameserver(config map[string]interface{}) map[string]interface{} {
if nameserver, ok := config["nameserver"].(string); ok {
if nameserver == "" {
return nil
}
// Разбиваем по пробелам
servers := strings.Fields(nameserver)
result := make(map[string]interface{})
for i, server := range servers {
key := fmt.Sprintf("dns%d", i+1)
result[key] = server
}
return result
}
return nil
}
// parseSearchdomain парсит searchdomain в массив доменов
func parseSearchdomain(config map[string]interface{}) map[string]interface{} {
if searchdomain, ok := config["searchdomain"].(string); ok {
if searchdomain == "" {
return nil
}
// Разбиваем по пробелам
domains := strings.Fields(searchdomain)
result := make(map[string]interface{})
for i, domain := range domains {
key := fmt.Sprintf("domain%d", i+1)
result[key] = domain
}
return result
}
return nil
}
// parseFeatures парсит features в структурированный формат
func parseFeatures(config map[string]interface{}) map[string]interface{} {
if features, ok := config["features"].(string); ok {
if features == "" {
return nil
}
// Разбиваем по запятым
parts := strings.Split(features, ",")
result := make(map[string]interface{})
for _, part := range parts {
part = strings.TrimSpace(part)
if part == "" {
continue
}
// Ищем знак равенства
equalIndex := strings.Index(part, "=")
if equalIndex == -1 {
// Если нет знака равенства, добавляем как ключ со значением true
result[part] = true
} else {
key := strings.TrimSpace(part[:equalIndex])
val := strings.TrimSpace(part[equalIndex+1:])
result[key] = val
}
}
return result
}
return nil
}
// convertToGB конвертирует размер в гигабайты
func convertToGB(sizeStr string) string {
if sizeStr == "" {
return ""
}
// Убираем пробелы
sizeStr = strings.TrimSpace(sizeStr)
// Определяем единицу измерения
var multiplier float64
var size float64
var err error
if strings.HasSuffix(strings.ToUpper(sizeStr), "T") {
// Терабайты
sizeStr = strings.TrimSuffix(strings.ToUpper(sizeStr), "T")
multiplier = 1024 // 1TB = 1024GB
} else if strings.HasSuffix(strings.ToUpper(sizeStr), "G") {
// Гигабайты
sizeStr = strings.TrimSuffix(strings.ToUpper(sizeStr), "G")
multiplier = 1
} else if strings.HasSuffix(strings.ToUpper(sizeStr), "M") {
// Мегабайты
sizeStr = strings.TrimSuffix(strings.ToUpper(sizeStr), "M")
multiplier = 1.0 / 1024 // 1MB = 1/1024GB
} else {
// По умолчанию считаем гигабайтами
multiplier = 1
}
size, err = strconv.ParseFloat(sizeStr, 64)
if err != nil {
return sizeStr // Возвращаем оригинальную строку, если не удалось распарсить
}
// Конвертируем в гигабайты
result := size * multiplier
// Форматируем результат
if result == float64(int64(result)) {
// Если целое число, возвращаем без дробной части
return fmt.Sprintf("%.0fG", result)
} else {
// Если дробное, возвращаем с 2 знаками после запятой
return fmt.Sprintf("%.2fG", result)
}
}
// debugLog выводит отладочную информацию (только если установлена переменная окружения DEBUG=1) // debugLog выводит отладочную информацию (только если установлена переменная окружения DEBUG=1)
func debugLog(format string, args ...interface{}) { func debugLog(format string, args ...interface{}) {
if os.Getenv("DEBUG") == "1" { if os.Getenv("DEBUG") == "1" {