magos/containers_part1.go
2026-03-23 15:38:18 +03:00

216 lines
9.1 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 (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
func setupContainers(config Config, clientTitle string, clientInfo *ClientInfo, resources []ResourceData, resourcePortMap map[int][]PortMapping) error {
log.Printf("Настройка контейнеров для %s", clientTitle)
baseDir := filepath.Join("/home/install/ptaf", clientTitle)
containerChanges := make(map[int]bool)
composeChanges := make(map[int]bool)
for containerNum := 1; containerNum <= clientInfo.ContainersCount; containerNum++ {
containerName := fmt.Sprintf("%s-ptaf-agent%03d", clientTitle, containerNum)
containerDir := filepath.Join(baseDir, containerName)
log.Printf(" Обработка контейнера: %s", containerName)
dirs := []string{
containerDir,
filepath.Join("/home/install/conf/ptaf-nginx", clientTitle, fmt.Sprintf("ptaf-agent%03d", containerNum), "conf.d"),
}
for _, dir := range dirs {
existed := false
if _, err := os.Stat(dir); err == nil {
existed = true
}
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("ошибка создания директории %s: %w", dir, err)
}
if !existed {
log.Printf(" ✓ Создана директория: %s", dir)
}
}
logDir := filepath.Join("/var/log/ptaf_nginx", clientTitle, fmt.Sprintf("ptaf-agent%03d", containerNum))
logDirExisted := false
if _, err := os.Stat(logDir); err == nil {
logDirExisted = true
}
if err := os.MkdirAll(logDir, 0777); err != nil {
return fmt.Errorf("ошибка создания директории логов %s: %w", logDir, err)
}
if err := os.Chmod(logDir, 0777); err != nil {
return fmt.Errorf("ошибка установки прав для директории логов %s: %w", logDir, err)
}
if !logDirExisted {
log.Printf(" ✓ Создана директория логов: %s (права: 0777)", logDir)
}
nginxConfPath := filepath.Join("/home/install/conf/ptaf-nginx", clientTitle, fmt.Sprintf("ptaf-agent%03d", containerNum), "nginx.conf")
existingPodIP := ""
if info, err := os.Stat(nginxConfPath); err == nil {
if info.IsDir() {
log.Printf(" ⚠ nginx.conf является директорией, удаляем...")
os.RemoveAll(nginxConfPath)
} else {
existingPodIP = extractPodIPFromConfig(nginxConfPath)
}
}
ptafConfig := ""
if clientInfo.PTAFConfig.Valid {
ptafConfig = clientInfo.PTAFConfig.String
}
changed, err := generateNginxConf(nginxConfPath, config, ptafConfig, existingPodIP, clientInfo.Debug)
if err != nil {
return fmt.Errorf("ошибка генерации nginx.conf: %w", err)
}
if changed {
log.Printf(" ✓ nginx.conf изменен: %s", nginxConfPath)
containerChanges[containerNum] = true
} else {
log.Printf(" ○ nginx.conf не изменился: %s", nginxConfPath)
}
mimeTypesPath := filepath.Join("/home/install/conf/ptaf-nginx", clientTitle, fmt.Sprintf("ptaf-agent%03d", containerNum), "mime.types")
if info, err := os.Stat(mimeTypesPath); err == nil {
if info.IsDir() {
log.Printf(" ⚠ mime.types является директорией, удаляем...")
os.RemoveAll(mimeTypesPath)
}
}
changed, err = generateMimeTypes(mimeTypesPath)
if err != nil {
return fmt.Errorf("ошибка генерации mime.types: %w", err)
}
if changed {
log.Printf(" ✓ mime.types изменен: %s", mimeTypesPath)
containerChanges[containerNum] = true
}
confDPath := filepath.Join("/home/install/conf/ptaf-nginx", clientTitle, fmt.Sprintf("ptaf-agent%03d", containerNum), "conf.d")
// Удаляем конфиги ресурсов которых больше нет в БД
activeConfFiles := make(map[string]bool)
for _, res := range resources {
activeConfFiles[fmt.Sprintf("%s_%d.conf", clientTitle, res.L7ResourceID)] = true
}
if entries, err := os.ReadDir(confDPath); err == nil {
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".conf") {
if !activeConfFiles[entry.Name()] {
stalePath := filepath.Join(confDPath, entry.Name())
if err := os.Remove(stalePath); err == nil {
log.Printf(" → Удалён устаревший конфиг ресурса: %s", entry.Name())
containerChanges[containerNum] = true
} else {
log.Printf(" ⚠ Ошибка удаления устаревшего конфига %s: %v", entry.Name(), err)
}
}
}
}
}
containerPorts := []PortMapping{}
for _, res := range resources {
ports, ok := resourcePortMap[res.L7ResourceID]
if !ok || containerNum-1 >= len(ports) {
return fmt.Errorf("не найдены порты для l7ResourceID %d контейнер %d", res.L7ResourceID, containerNum)
}
containerPorts = append(containerPorts, ports[containerNum-1])
confFile := filepath.Join(confDPath, fmt.Sprintf("%s_%d.conf", clientTitle, res.L7ResourceID))
oldHash := ""
if _, err := os.Stat(confFile); err == nil {
oldHash, _ = getFileHash(confFile)
}
err := generateNginxResourceConfig(confFile, config, res, ports[containerNum-1])
if err != nil {
return fmt.Errorf("ошибка генерации конфига для ресурса: %w", err)
}
newHash, _ := getFileHash(confFile)
if oldHash != "" && oldHash != newHash {
log.Printf(" ✓ Конфиг ресурса изменен: %s", confFile)
containerChanges[containerNum] = true
} else if oldHash == "" {
log.Printf(" ✓ Создан конфиг ресурса: %s", confFile)
containerChanges[containerNum] = true
} else {
log.Printf(" ○ Конфиг ресурса не изменился: %s", confFile)
}
}
composeFile := filepath.Join(containerDir, "docker-compose.yml")
log.Printf(" → DEBUG порты контейнера %d:", containerNum)
for idx, pm := range containerPorts {
log.Printf(" PortMapping[%d]: HTTP=%v, HTTPS=%v", idx, pm.HTTPPorts, pm.HTTPSPorts)
}
changed, err = generateDockerCompose(composeFile, config, clientTitle, clientInfo, containerNum, resources, containerPorts)
if err != nil {
return fmt.Errorf("ошибка генерации docker-compose.yml: %w", err)
}
if changed {
log.Printf(" ✓ docker-compose.yml изменен: %s", composeFile)
composeChanges[containerNum] = true
}
if err := saveContainerPorts(containerDir, containerNum, resources, containerPorts); err != nil {
log.Printf(" ⚠ Ошибка сохранения портов: %v", err)
}
}
log.Printf(" Запуск и обновление контейнеров для %s", clientTitle)
for containerNum := 1; containerNum <= clientInfo.ContainersCount; containerNum++ {
containerName := fmt.Sprintf("%s-ptaf-agent%03d", clientTitle, containerNum)
containerDir := filepath.Join(baseDir, containerName)
composeFile := filepath.Join(containerDir, "docker-compose.yml")
containerFullName := fmt.Sprintf("ptaf_%s_%03d", clientTitle, containerNum)
containerExists, containerRunning := checkContainerStatus(containerFullName)
if containerExists {
if composeChanges[containerNum] {
recreateContainer(containerFullName, composeFile, containerDir, clientTitle, resources, resourcePortMap, containerNum)
continue
}
if !containerRunning {
startContainer(containerFullName, composeFile, containerDir)
}
if containerChanges[containerNum] {
log.Printf(" Конфигурация изменилась, проверяем и перезагружаем nginx в %s", containerFullName)
if err := testNginxConfig(containerFullName); err != nil {
log.Printf(" ⚠ Ошибка проверки конфигурации в %s: %v", containerFullName, err)
continue
}
if err := reloadNginx(containerFullName); err != nil {
log.Printf(" ⚠ Ошибка перезагрузки nginx в %s: %v", containerFullName, err)
continue
}
log.Printf(" ✓ Nginx успешно перезагружен в контейнере %s", containerFullName)
} else {
log.Printf(" ○ Конфигурация не изменилась, проверка и перезагрузка не требуются для %s", containerFullName)
}
} else {
log.Printf(" Запуск нового контейнера %s", containerName)
cmd := exec.Command("docker-compose", "-f", composeFile, "up", "-d")
cmd.Dir = containerDir
output, _ := cmd.CombinedOutput()
log.Printf(" → Вывод docker-compose: %s", string(output))
time.Sleep(5 * time.Second)
_, isRunning := checkContainerStatus(containerFullName)
if !isRunning {
log.Printf(" ⚠ Контейнер %s не запустился. Попробуйте вручную: cd %s && docker-compose up -d", containerFullName, containerDir)
continue
}
log.Printf(" ✓ Контейнер %s успешно запущен", containerName)
}
}
log.Printf(" Проверка лишних контейнеров для %s", clientTitle)
processDrainingContainers(clientTitle, clientInfo.ContainersCount)
return nil
}