magos/db.go
2026-03-25 16:47:57 +03:00

242 lines
7.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"database/sql"
"fmt"
"log"
"strings"
_ "github.com/lib/pq"
)
// connectToDB подключается к базе данных PostgreSQL
// Сначала пытается подключиться к primary, если не удалось - к secondary
func connectToDB(config Config) *sql.DB {
log.Println("Попытка подключения к первичной БД...")
connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
config.PrimaryDBHost, config.DBPort, config.DBUser, config.DBPassword, config.DBName)
db, err := sql.Open("postgres", connStr)
if err == nil {
err = db.Ping()
if err == nil {
log.Printf("Успешное подключение к первичной БД: %s", config.PrimaryDBHost)
return db
}
}
log.Printf("Не удалось подключиться к первичной БД: %v", err)
log.Println("Попытка подключения к вторичной БД...")
connStr = fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
config.SecondaryDBHost, config.DBPort, config.DBUser, config.DBPassword, config.DBName)
db, err = sql.Open("postgres", connStr)
if err != nil {
log.Fatalf("Ошибка открытия соединения с вторичной БД: %v", err)
}
err = db.Ping()
if err != nil {
log.Fatalf("Ошибка подключения к вторичной БД: %v", err)
}
log.Printf("Успешное подключение к вторичной БД: %s", config.SecondaryDBHost)
return db
}
// getInstancesByHostname получает все instances для hostname из таблицы instances
// Возвращает массив instances, т.к. один hostname может быть связан с несколькими instance
func getInstancesByHostname(db *sql.DB, hostname string) ([]string, error) {
query := "SELECT instance FROM instances_new WHERE hostname = $1 ORDER BY instance"
rows, err := db.Query(query, hostname)
if err != nil {
return nil, fmt.Errorf("ошибка выполнения запроса для hostname %s: %w", hostname, err)
}
defer rows.Close()
var instances []string
for rows.Next() {
var instance string
if err := rows.Scan(&instance); err != nil {
return nil, fmt.Errorf("ошибка чтения instance: %w", err)
}
instances = append(instances, instance)
}
if err = rows.Err(); err != nil {
return nil, fmt.Errorf("ошибка обработки результатов: %w", err)
}
if len(instances) == 0 {
return nil, fmt.Errorf("instances не найдены для hostname %s", hostname)
}
return instances, nil
}
// checkHostBelongsToInstance проверяет принадлежит ли хост к указанному instance
func checkHostBelongsToInstance(db *sql.DB, hostname, instance string) (bool, error) {
query := `
SELECT COUNT(*)
FROM instances_new
WHERE hostname = $1 AND instance = $2
`
var count int
err := db.QueryRow(query, hostname, instance).Scan(&count)
if err != nil {
return false, fmt.Errorf("ошибка проверки принадлежности хоста: %w", err)
}
return count > 0, nil
}
// getClientInfoByInstance получает всех клиентов для заданного waf_instance
func getClientInfoByInstance(db *sql.DB, instance string) ([]ClientInfo, error) {
query := `
SELECT containers_count, ptaf_config, client_title, fluent_bit_port, waf_instance,
docker_image, docker_image_download, debug, shm_size
FROM client_info
WHERE waf_instance = $1
`
rows, err := db.Query(query, instance)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
return nil, fmt.Errorf("ошибка структуры таблицы client_info: %w (возможно изменилась схема БД)", err)
}
return nil, fmt.Errorf("ошибка выполнения запроса: %w", err)
}
defer rows.Close()
var clientInfoList []ClientInfo
for rows.Next() {
var ci ClientInfo
var wafInstance sql.NullString
err := rows.Scan(
&ci.ContainersCount,
&ci.PTAFConfig,
&ci.ClientTitle,
&ci.FluentBitPort,
&wafInstance,
&ci.DockerImage,
&ci.DockerImageDownload,
&ci.Debug,
&ci.ShmSize,
)
if err != nil {
return nil, fmt.Errorf("ошибка сканирования строки: %w", err)
}
if wafInstance.Valid {
ci.WAFInstance = wafInstance.String
}
clientInfoList = append(clientInfoList, ci)
}
return clientInfoList, nil
}
// getAppsSettingsByClientTitle получает apps_settings для заданного client_title
func getAppsSettingsByClientTitle(db *sql.DB, clientTitle string) ([]AppsSettings, error) {
query := `
SELECT
l7resourceid, waf_enabled, waf_vendor,
custom_input_http_ports, custom_input_https_ports,
custom_output_http_ports, custom_output_https_ports,
upstream_angie_custom, server_nginx_custom,
server_angie_custom, client_title,
upstream_nginx_custom,
location_angie_custom, location_nginx_custom,
server_directives_angie_custom, server_directives_nginx_custom,
sni,
mode,
ssl_enabled,
custom_angie_ssl,
max_fails,
fail_timeout,
balancing_method,
custom_sw_nginx_ssl
FROM apps_settings
WHERE client_title = $1
ORDER BY l7resourceid ASC
`
rows, err := db.Query(query, clientTitle)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
return nil, fmt.Errorf("ошибка структуры таблицы apps_settings: %w (возможно изменилась схема БД)", err)
}
return nil, fmt.Errorf("ошибка выполнения запроса: %w", err)
}
defer rows.Close()
var appsSettingsList []AppsSettings
for rows.Next() {
var a AppsSettings
err := rows.Scan(
&a.L7ResourceID, &a.WAFEnabled, &a.WAFVendor,
&a.CustomInputHTTPPorts, &a.CustomInputHTTPSPorts,
&a.CustomOutputHTTPPorts, &a.CustomOutputHTTPSPorts,
&a.UpstreamAngieCustom, &a.ServerNginxCustom,
&a.ServerAngieCustom, &a.ClientTitle,
&a.UpstreamNginxCustom,
&a.LocationAngieCustom, &a.LocationNginxCustom,
&a.ServerDirectivesAngieCustom, &a.ServerDirectivesNginxCustom,
&a.SNI,
&a.Mode,
&a.SSLEnabled,
&a.CustomAngieSSL,
&a.MaxFails,
&a.FailTimeout,
&a.BalancingMethod,
&a.CustomSWNginxSSL,
)
if err != nil {
return nil, fmt.Errorf("ошибка сканирования строки: %w", err)
}
appsSettingsList = append(appsSettingsList, a)
}
return appsSettingsList, nil
}
// getClientInfoByClientTitle получает информацию о клиенте из таблицы client_info
func getClientInfoByClientTitle(db *sql.DB, clientTitle string) (*ClientInfo, error) {
query := `
SELECT containers_count, ptaf_config, client_title, fluent_bit_port, waf_instance,
docker_image, docker_image_download, debug, shm_size
FROM client_info
WHERE client_title = $1
`
var clientInfo ClientInfo
var wafInstance sql.NullString
err := db.QueryRow(query, clientTitle).Scan(
&clientInfo.ContainersCount,
&clientInfo.PTAFConfig,
&clientInfo.ClientTitle,
&clientInfo.FluentBitPort,
&wafInstance,
&clientInfo.DockerImage,
&clientInfo.DockerImageDownload,
&clientInfo.Debug,
&clientInfo.ShmSize,
)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
return nil, fmt.Errorf("ошибка структуры таблицы client_info: %w (возможно изменилась схема БД)", err)
}
return nil, fmt.Errorf("ошибка получения данных из client_info: %w", err)
}
if wafInstance.Valid {
clientInfo.WAFInstance = wafInstance.String
}
return &clientInfo, nil
}