package main import ( "bufio" "fmt" "os" "strconv" "strings" ) // ============================================================================= // Глобальная конфигурация Auspex // ============================================================================= // // Конфигурация загружается из /etc/auspex/auspex.env // Fallback значения используются если env файл не найден // ============================================================================= const ( // Путь к файлу конфигурации envFilePath = "/etc/auspex/auspex.env" ) // --- Telegram --- var ( cfgTelegramBotToken = "" cfgTelegramChatID = "" cfgTelegramSocks5Proxy = "" // Опционально: host:port cfgTelegramSocks5User = "" // Логин прокси (опционально) cfgTelegramSocks5Password = "" // Пароль прокси (опционально) cfgTelegramHTTPProxy = "" // Опционально: http://user:pass@host:port ) // --- Mattermost --- var ( cfgMattermostURL = "" // https://mattermost.example.com cfgMattermostBotToken = "" // Токен бота cfgMattermostChannelID = "" // ID канала для отправки ) // --- Email / SMTP --- var ( cfgEmailSMTPHost = "" cfgEmailSMTPPort = 587 cfgEmailSMTPUser = "" cfgEmailSMTPPassword = "" cfgEmailFrom = "" cfgEmailTo = []string{} ) // --- PostgreSQL Database --- var ( cfgDBUser = "" cfgDBPassword = "" cfgDBName = "waf_info" // Значение по умолчанию cfgDBPort = 5432 // Значение по умолчанию ) // --- Пути к хостам БД --- var ( cfgPrimaryDBHost = "10.100.10.8" cfgSecondaryDBHost = "10.100.13.5" ) // --- Пороги сертификатов (дни) --- var ( cfgCertCriticalDays = 3 cfgCertWarningDays = 15 cfgCertInfoDays = 30 ) // --- Пути --- var ( cfgPTAFBaseDir = "/home/install/ptaf" cfgAngieConfDir = "/etc/angie/http.d" cfgSSLDir = "/etc/ssl" cfgNginxConfigGlob = "/home/install/conf/ptaf-nginx/*/*/*/*.conf" cfgStateFilePath = "/tmp/port_checker_state.json" cfgServiceStateFilePath = "/tmp/auspex_service_state.json" cfgDockerStateFilePath = "/tmp/auspex_docker_state.json" ) // --- Параметры проверки портов --- var ( cfgCheckTimeoutSec = 10 cfgMaxRetries = 3 cfgRetryDelaySec = 2 ) // cfgMaxWorkers — количество горутин для параллельной обработки var cfgMaxWorkers = 10 // --- Log Check --- var ( cfgLogDir = "/var/log/ptaf_nginx" cfgLogStaleMinutes = 61 // Порог в минутах для определения устаревшего лога ) // --- Service Check --- // Список служб systemd для проверки на текущем хосте. // Задаётся через SERVICES_TO_CHECK в auspex.env в виде списка через запятую. // Пример: SERVICES_TO_CHECK=angie,docker var cfgServicesToCheck = []string{} // ============================================================================= // Загрузка конфигурации из файла // ============================================================================= // loadConfig загружает конфигурацию из /etc/auspex/auspex.env func loadConfig() error { file, err := os.Open(envFilePath) if err != nil { // Файл не найден - используем значения по умолчанию return fmt.Errorf("файл конфигурации не найден: %s", envFilePath) } defer file.Close() envVars := make(map[string]string) scanner := bufio.NewScanner(file) lineNum := 0 for scanner.Scan() { lineNum++ line := strings.TrimSpace(scanner.Text()) // Пропускаем пустые строки и комментарии if line == "" || strings.HasPrefix(line, "#") { continue } // Парсим KEY=VALUE parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { fmt.Printf("⚠️ Некорректная строка %d в %s: %s\n", lineNum, envFilePath, line) continue } key := strings.TrimSpace(parts[0]) value := strings.TrimSpace(parts[1]) // Убираем кавычки если есть value = strings.Trim(value, `"'`) envVars[key] = value } if err := scanner.Err(); err != nil { return fmt.Errorf("ошибка чтения файла: %v", err) } // Применяем значения applyConfig(envVars) return nil } // applyConfig применяет загруженные значения к переменным конфигурации func applyConfig(env map[string]string) { // Telegram if v, ok := env["TELEGRAM_BOT_TOKEN"]; ok && v != "" { cfgTelegramBotToken = v } if v, ok := env["TELEGRAM_CHAT_ID"]; ok && v != "" { cfgTelegramChatID = v } if v, ok := env["TELEGRAM_SOCKS5_PROXY"]; ok && v != "" { cfgTelegramSocks5Proxy = v } if v, ok := env["TELEGRAM_SOCKS5_USER"]; ok && v != "" { cfgTelegramSocks5User = v } if v, ok := env["TELEGRAM_SOCKS5_PASSWORD"]; ok && v != "" { cfgTelegramSocks5Password = v } if v, ok := env["TELEGRAM_HTTP_PROXY"]; ok && v != "" { cfgTelegramHTTPProxy = v } // Database if v, ok := env["DB_USER"]; ok && v != "" { cfgDBUser = v } if v, ok := env["DB_PASSWORD"]; ok && v != "" { cfgDBPassword = v } if v, ok := env["DB_NAME"]; ok && v != "" { cfgDBName = v } if v, ok := env["DB_PORT"]; ok && v != "" { if port, err := strconv.Atoi(v); err == nil { cfgDBPort = port } } if v, ok := env["PRIMARY_DB_HOST"]; ok && v != "" { cfgPrimaryDBHost = v } if v, ok := env["SECONDARY_DB_HOST"]; ok && v != "" { cfgSecondaryDBHost = v } // Paths if v, ok := env["PTAF_BASE_DIR"]; ok && v != "" { cfgPTAFBaseDir = v } if v, ok := env["ANGIE_CONF_DIR"]; ok && v != "" { cfgAngieConfDir = v } if v, ok := env["SSL_DIR"]; ok && v != "" { cfgSSLDir = v } if v, ok := env["NGINX_CONFIG_GLOB"]; ok && v != "" { cfgNginxConfigGlob = v } if v, ok := env["STATE_FILE_PATH"]; ok && v != "" { cfgStateFilePath = v } if v, ok := env["SERVICE_STATE_FILE_PATH"]; ok && v != "" { cfgServiceStateFilePath = v } if v, ok := env["DOCKER_STATE_FILE_PATH"]; ok && v != "" { cfgDockerStateFilePath = v } if v, ok := env["LOG_DIR"]; ok && v != "" { cfgLogDir = v } // Thresholds if v, ok := env["CERT_CRITICAL_DAYS"]; ok && v != "" { if days, err := strconv.Atoi(v); err == nil { cfgCertCriticalDays = days } } if v, ok := env["CERT_WARNING_DAYS"]; ok && v != "" { if days, err := strconv.Atoi(v); err == nil { cfgCertWarningDays = days } } if v, ok := env["CERT_INFO_DAYS"]; ok && v != "" { if days, err := strconv.Atoi(v); err == nil { cfgCertInfoDays = days } } if v, ok := env["LOG_STALE_MINUTES"]; ok && v != "" { if mins, err := strconv.Atoi(v); err == nil { cfgLogStaleMinutes = mins } } // Timeouts and retries if v, ok := env["CHECK_TIMEOUT_SEC"]; ok && v != "" { if sec, err := strconv.Atoi(v); err == nil { cfgCheckTimeoutSec = sec } } if v, ok := env["MAX_RETRIES"]; ok && v != "" { if retries, err := strconv.Atoi(v); err == nil { cfgMaxRetries = retries } } if v, ok := env["RETRY_DELAY_SEC"]; ok && v != "" { if sec, err := strconv.Atoi(v); err == nil { cfgRetryDelaySec = sec } } if v, ok := env["MAX_WORKERS"]; ok && v != "" { if workers, err := strconv.Atoi(v); err == nil { cfgMaxWorkers = workers } } // Services to check if v, ok := env["SERVICES_TO_CHECK"]; ok && v != "" { parts := strings.Split(v, ",") services := make([]string, 0, len(parts)) for _, s := range parts { s = strings.TrimSpace(s) if s != "" { services = append(services, s) } } cfgServicesToCheck = services } // Email / SMTP if v, ok := env["EMAIL_SMTP_HOST"]; ok && v != "" { cfgEmailSMTPHost = v } if v, ok := env["EMAIL_SMTP_PORT"]; ok && v != "" { if port, err := strconv.Atoi(v); err == nil { cfgEmailSMTPPort = port } } if v, ok := env["EMAIL_SMTP_USER"]; ok && v != "" { cfgEmailSMTPUser = v } if v, ok := env["EMAIL_SMTP_PASSWORD"]; ok && v != "" { cfgEmailSMTPPassword = v } if v, ok := env["EMAIL_FROM"]; ok && v != "" { cfgEmailFrom = v } // Mattermost if v, ok := env["MATTERMOST_URL"]; ok && v != "" { cfgMattermostURL = v } if v, ok := env["MATTERMOST_BOT_TOKEN"]; ok && v != "" { cfgMattermostBotToken = v } if v, ok := env["MATTERMOST_CHANNEL_ID"]; ok && v != "" { cfgMattermostChannelID = v } // Email / SMTP if v, ok := env["EMAIL_TO"]; ok && v != "" { parts := strings.Split(v, ",") recipients := make([]string, 0, len(parts)) for _, s := range parts { s = strings.TrimSpace(s) if s != "" { recipients = append(recipients, s) } } cfgEmailTo = recipients } } // ============================================================================= // Вспомогательные функции // ============================================================================= func isTelegramConfigured() bool { return cfgTelegramBotToken != "" && cfgTelegramBotToken != "YOUR_BOT_TOKEN" && cfgTelegramChatID != "" && cfgTelegramChatID != "YOUR_CHAT_ID" } func isMattermostConfigured() bool { return cfgMattermostURL != "" && cfgMattermostBotToken != "" && cfgMattermostChannelID != "" } func isEmailConfigured() bool { return cfgEmailSMTPHost != "" && cfgEmailFrom != "" && len(cfgEmailTo) > 0 } // printConfigStatus выводит статус загруженной конфигурации func printConfigStatus() { fmt.Println("📋 Статус конфигурации:") // Telegram if isTelegramConfigured() { switch { case cfgTelegramSocks5Proxy != "": if cfgTelegramSocks5User != "" { fmt.Printf(" ✅ Telegram: настроен (SOCKS5: %s, пользователь: %s)\n", cfgTelegramSocks5Proxy, cfgTelegramSocks5User) } else { fmt.Printf(" ✅ Telegram: настроен (SOCKS5: %s, без авторизации)\n", cfgTelegramSocks5Proxy) } case cfgTelegramHTTPProxy != "": fmt.Printf(" ✅ Telegram: настроен (HTTP прокси: %s)\n", cfgTelegramHTTPProxy) default: fmt.Println(" ✅ Telegram: настроен (прямое соединение)") } } else { fmt.Println(" ⚠️ Telegram: не настроен") } // Database if cfgDBUser != "" && cfgDBPassword != "" { fmt.Printf(" ✅ База данных: %s@%s:%d/%s\n", cfgDBUser, cfgPrimaryDBHost, cfgDBPort, cfgDBName) } else { fmt.Println(" ⚠️ База данных: не настроена") } // Mattermost if isMattermostConfigured() { fmt.Printf(" ✅ Mattermost: настроен (%s, channel: %s)\n", cfgMattermostURL, cfgMattermostChannelID) } else { fmt.Println(" ⚠️ Mattermost: не настроен (MATTERMOST_URL, MATTERMOST_BOT_TOKEN, MATTERMOST_CHANNEL_ID)") } // Email if isEmailConfigured() { fmt.Printf(" ✅ Email: %s → %s (smtp: %s:%d)\n", cfgEmailFrom, strings.Join(cfgEmailTo, ", "), cfgEmailSMTPHost, cfgEmailSMTPPort) } else { fmt.Println(" ⚠️ Email: не настроен (EMAIL_SMTP_HOST, EMAIL_FROM, EMAIL_TO)") } // Services if len(cfgServicesToCheck) > 0 { fmt.Printf(" ✅ Службы для проверки: %s\n", strings.Join(cfgServicesToCheck, ", ")) } else { fmt.Println(" ⚠️ Службы для проверки: не заданы (SERVICES_TO_CHECK)") } fmt.Println() }