Fix
This commit is contained in:
parent
1e0690b061
commit
f01944f474
4 changed files with 110 additions and 48 deletions
59
drain.go
59
drain.go
|
|
@ -30,21 +30,28 @@ func getActualContainerCount(clientTitle string) int {
|
|||
}
|
||||
|
||||
// Считаем по drain-маркерам в /tmp (контейнеры могли быть уже удалены с диска)
|
||||
// Ищем маркеры по паттерну /tmp/ptaf-drain-{clientTitle}_* независимо от формата имени
|
||||
matches, _ := filepath.Glob(fmt.Sprintf("/tmp/ptaf-drain-%s_*", clientTitle))
|
||||
for _, match := range matches {
|
||||
// Извлекаем номер агента из конца имени файла (формат: ..._a001 или ..._001)
|
||||
base := filepath.Base(match)
|
||||
base = strings.TrimPrefix(base, "ptaf-drain-")
|
||||
// Убираем префикс clientTitle_
|
||||
rest := strings.TrimPrefix(base, clientTitle+"_")
|
||||
// Ищем номер в конце: _a001 или _001
|
||||
parts := strings.Split(rest, "_")
|
||||
lastPart := parts[len(parts)-1]
|
||||
lastPart = strings.TrimPrefix(lastPart, "a")
|
||||
var num int
|
||||
if _, err := fmt.Sscanf(lastPart, "%d", &num); err == nil && num > max {
|
||||
max = num
|
||||
// Ищем маркеры по двум паттернам — с и без префикса ptaf_
|
||||
patterns := []string{
|
||||
fmt.Sprintf("/tmp/ptaf-drain-%s_*", clientTitle), // новый формат: {clientTitle}_AZ1_n01_a001
|
||||
fmt.Sprintf("/tmp/ptaf-drain-ptaf_%s_*", clientTitle), // fallback формат: ptaf_{clientTitle}_001
|
||||
}
|
||||
for _, pattern := range patterns {
|
||||
matches, _ := filepath.Glob(pattern)
|
||||
for _, match := range matches {
|
||||
base := filepath.Base(match)
|
||||
base = strings.TrimPrefix(base, "ptaf-drain-")
|
||||
// Убираем возможный префикс ptaf_
|
||||
base = strings.TrimPrefix(base, "ptaf_")
|
||||
// Убираем префикс clientTitle_
|
||||
rest := strings.TrimPrefix(base, clientTitle+"_")
|
||||
// Ищем номер в конце: _a001 или _001
|
||||
parts := strings.Split(rest, "_")
|
||||
lastPart := parts[len(parts)-1]
|
||||
lastPart = strings.TrimPrefix(lastPart, "a")
|
||||
var num int
|
||||
if _, err := fmt.Sscanf(lastPart, "%d", &num); err == nil && num > max {
|
||||
max = num
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +149,12 @@ func processAllDrainingContainersGlobally(db *sql.DB, hostname string) {
|
|||
continue
|
||||
}
|
||||
clientTitle := entry.Name()
|
||||
|
||||
// Пропускаем блочные директории — они управляются через родительский клиент
|
||||
if isBlockClientTitle(clientTitle) {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf(" → Проверка клиента: %s", clientTitle)
|
||||
|
||||
clientInfo, err := getClientInfoByClientTitle(db, clientTitle)
|
||||
|
|
@ -204,7 +217,7 @@ func processAllDrainingContainersGlobally(db *sql.DB, hostname string) {
|
|||
processedClients++
|
||||
} else {
|
||||
log.Printf(" ✓ Клиент должен быть здесь, проверяю устаревшие drain-маркеры")
|
||||
checkAndProcessExistingDrainMarkers(clientTitle, clientInfo.ContainersCount, &processedClients)
|
||||
checkAndProcessExistingDrainMarkers(clientTitle, 0, &processedClients)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,10 +234,16 @@ func processAllDrainingContainersGlobally(db *sql.DB, hostname string) {
|
|||
|
||||
func checkAndProcessExistingDrainMarkers(clientTitle string, containersCount int, processedCount *int) {
|
||||
hasAnyDrainMarkers := false
|
||||
// Ищем маркеры по паттерну независимо от формата имени контейнера
|
||||
matches, _ := filepath.Glob(fmt.Sprintf("/tmp/ptaf-drain-%s_*", clientTitle))
|
||||
if len(matches) > 0 {
|
||||
hasAnyDrainMarkers = true
|
||||
// Ищем маркеры по двум паттернам — новый и fallback формат
|
||||
for _, pattern := range []string{
|
||||
fmt.Sprintf("/tmp/ptaf-drain-%s_*", clientTitle),
|
||||
fmt.Sprintf("/tmp/ptaf-drain-ptaf_%s_*", clientTitle),
|
||||
} {
|
||||
matches, _ := filepath.Glob(pattern)
|
||||
if len(matches) > 0 {
|
||||
hasAnyDrainMarkers = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasAnyDrainMarkers {
|
||||
if _, err := os.Stat(fmt.Sprintf("/tmp/ptaf-angie-drain-%s", clientTitle)); err == nil {
|
||||
|
|
|
|||
47
main.go
47
main.go
|
|
@ -127,11 +127,6 @@ func main() {
|
|||
log.Fatalf("Ошибка загрузки конфигурации: %v", err)
|
||||
}
|
||||
|
||||
// Проверяем доступность Docker daemon
|
||||
if err := checkDockerAvailable(); err != nil {
|
||||
log.Fatalf("❌ Docker daemon недоступен: %v", err)
|
||||
}
|
||||
|
||||
instanceNames, err := getInstancesByHostname(db, hostname)
|
||||
if err != nil {
|
||||
log.Fatalf("Ошибка получения instances для hostname %s: %v", hostname, err)
|
||||
|
|
@ -146,8 +141,12 @@ func main() {
|
|||
// Проверка наличия Docker образов для каждого PTAF-клиента отдельно
|
||||
ptafClients := getPTAFClients(db, instanceNames)
|
||||
if len(ptafClients) == 0 {
|
||||
log.Printf("ℹ PTAF-клиентов на хосте нет, проверка Docker образов пропускается")
|
||||
log.Printf("ℹ PTAF-клиентов на хосте нет, проверка Docker пропускается")
|
||||
} else {
|
||||
// Проверяем Docker только если есть PTAF-клиенты
|
||||
if err := checkDockerAvailable(); err != nil {
|
||||
log.Fatalf("❌ Docker daemon недоступен: %v", err)
|
||||
}
|
||||
checkedImages := make(map[string]bool) // не проверяем один образ дважды
|
||||
for _, clientInfo := range ptafClients {
|
||||
image, url := getClientDockerImage(clientInfo, config)
|
||||
|
|
@ -358,14 +357,14 @@ func processClient(db *sql.DB, config Config, hostname, instanceName string, cli
|
|||
log.Printf("WAF Vendor: %s", vendor)
|
||||
|
||||
switch vendor {
|
||||
case "ptaf":
|
||||
return processPTAFClient(db, config, hostname, instanceName, clientInfo, appsSettingsList, portAllocator)
|
||||
case "sw":
|
||||
return processSWClient(db, config, hostname, instanceName, clientInfo, appsSettingsList, portAllocator)
|
||||
default:
|
||||
log.Printf("⚠ Неизвестный или не указан waf_vendor для клиента %s, пропускаем", clientInfo.ClientTitle)
|
||||
log.Printf(" Ожидается: 'ptaf' или 'sw' в поле waf_vendor таблицы apps_settings")
|
||||
return false
|
||||
case "ptaf":
|
||||
return processPTAFClient(db, config, hostname, instanceName, clientInfo, appsSettingsList, portAllocator)
|
||||
case "sw":
|
||||
return processSWClient(db, config, hostname, instanceName, clientInfo, appsSettingsList, portAllocator)
|
||||
default:
|
||||
log.Printf("⚠ Неизвестный или не указан waf_vendor для клиента %s, пропускаем", clientInfo.ClientTitle)
|
||||
log.Printf(" Ожидается: 'ptaf' или 'sw' в поле waf_vendor таблицы apps_settings")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +385,7 @@ func determineVendor(appsSettingsList []AppsSettings) string {
|
|||
// handleClientMigration обрабатывает миграцию клиента с текущего хоста
|
||||
func handleClientMigration(clientInfo ClientInfo, hostname string) {
|
||||
log.Printf("⚠ Клиент %s должен быть на instance '%s', текущий хост '%s' не принадлежит этому instance",
|
||||
clientInfo.ClientTitle, clientInfo.WAFInstance, hostname)
|
||||
clientInfo.ClientTitle, clientInfo.WAFInstance, hostname)
|
||||
log.Printf(" Инициирую удаление контейнеров с текущего хоста (миграция)")
|
||||
|
||||
actualCount := getActualContainerCount(clientInfo.ClientTitle)
|
||||
|
|
@ -395,7 +394,7 @@ func handleClientMigration(clientInfo ClientInfo, hostname string) {
|
|||
exists, _ := checkContainerStatus(containerFullName)
|
||||
if exists {
|
||||
log.Printf(" → Помечаю контейнер %s для drain (миграция, таймаут %d сек)",
|
||||
containerFullName, MigrationDrainTimeout)
|
||||
containerFullName, MigrationDrainTimeout)
|
||||
if err := markContainerForDrain(containerFullName, true); err != nil {
|
||||
log.Printf(" ⚠ Ошибка пометки: %v", err)
|
||||
}
|
||||
|
|
@ -437,7 +436,9 @@ func cleanStaleDrainMarkers(clientInfo ClientInfo, hostname string) {
|
|||
cleanedContainers++
|
||||
}
|
||||
} else if found && !isMigration {
|
||||
if containerNum <= clientInfo.ContainersCount {
|
||||
// Не удаляем маркер если клиент в блочном режиме —
|
||||
// контейнер помечен на drain из-за перехода one_container: true → false
|
||||
if clientInfo.OneContainer && containerNum <= clientInfo.ContainersCount {
|
||||
if err := os.Remove(markerFile); err == nil {
|
||||
log.Printf(" ✓ Удалён устаревший маркер drain для контейнера %s (масштабирование отменено)", containerFullName)
|
||||
cleanedContainers++
|
||||
|
|
@ -449,9 +450,13 @@ func cleanStaleDrainMarkers(clientInfo ClientInfo, hostname string) {
|
|||
|
||||
angieMarkerFile := fmt.Sprintf("/tmp/ptaf-angie-drain-%s", clientInfo.ClientTitle)
|
||||
if _, err := os.Stat(angieMarkerFile); err == nil {
|
||||
if err := os.Remove(angieMarkerFile); err == nil {
|
||||
log.Printf(" ✓ Удалён устаревший маркер drain для конфига Angie (миграция отменена)")
|
||||
cleanedAngieMarker = true
|
||||
// Не удаляем маркер Angie если клиент в блочном режиме —
|
||||
// конфиг помечен на drain из-за перехода one_container: true → false
|
||||
if clientInfo.OneContainer {
|
||||
if err := os.Remove(angieMarkerFile); err == nil {
|
||||
log.Printf(" ✓ Удалён устаревший маркер drain для конфига Angie (миграция отменена)")
|
||||
cleanedAngieMarker = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -521,7 +526,7 @@ func resolvePortsForClient(clientInfo ClientInfo, resourcesData []ResourceData,
|
|||
}
|
||||
|
||||
log.Printf(" → Сохранены порты для %d существующих контейнеров, выделяю порты для %d новых (контейнеры %d-%d)",
|
||||
lastLoadedContainer, newContainersCount, lastLoadedContainer+1, clientInfo.ContainersCount)
|
||||
lastLoadedContainer, newContainersCount, lastLoadedContainer+1, clientInfo.ContainersCount)
|
||||
|
||||
newPortMap, err := portAllocator.allocatePortsForResources(resourcesData, newContainersCount, existingPorts)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,10 @@ func processPTAFClient(
|
|||
}
|
||||
|
||||
// Автоочистка устаревших маркеров drain
|
||||
cleanStaleDrainMarkers(clientInfo, hostname)
|
||||
// При блочном режиме не очищаем — маркеры управляются через cleanupOneContainerContainers
|
||||
if clientInfo.OneContainer {
|
||||
cleanStaleDrainMarkers(clientInfo, hostname)
|
||||
}
|
||||
|
||||
// Получение данных ресурсов
|
||||
resourcesData := fetchPTAFResourcesData(db, config, appsSettingsList)
|
||||
|
|
@ -441,12 +444,16 @@ func cleanupStaleBlocks(clientTitle string, activeBlocks map[string]bool, hostna
|
|||
log.Printf(" → Удаление устаревшего блока %s для %s", blockName, clientTitle)
|
||||
blockClientTitle := fmt.Sprintf("%s_%s", clientTitle, blockName)
|
||||
|
||||
// Помечаем контейнеры на drain
|
||||
// Помечаем контейнеры на drain (только если маркер ещё не существует)
|
||||
actualCount := getActualContainerCount(blockClientTitle)
|
||||
for containerNum := 1; containerNum <= actualCount; containerNum++ {
|
||||
containerFullName := buildContainerFullName(blockClientTitle, containerNum, hostname)
|
||||
exists, _ := checkContainerStatus(containerFullName)
|
||||
if exists {
|
||||
markerFile := fmt.Sprintf("/tmp/ptaf-drain-%s", containerFullName)
|
||||
if _, err := os.Stat(markerFile); err == nil {
|
||||
continue // маркер уже есть — не перезаписываем
|
||||
}
|
||||
if err := markContainerForDrain(containerFullName, false); err != nil {
|
||||
log.Printf(" ⚠ Ошибка пометки контейнера %s: %v", containerFullName, err)
|
||||
} else {
|
||||
|
|
@ -455,11 +462,14 @@ func cleanupStaleBlocks(clientTitle string, activeBlocks map[string]bool, hostna
|
|||
}
|
||||
}
|
||||
|
||||
// Помечаем Angie конфиг для drain
|
||||
if err := markAngieConfigForDrain(blockClientTitle, false); err != nil {
|
||||
log.Printf(" ⚠ Ошибка пометки Angie конфига для %s: %v", blockClientTitle, err)
|
||||
} else {
|
||||
log.Printf(" ✓ Angie конфиг для блока %s помечен для drain", blockName)
|
||||
// Помечаем Angie конфиг для drain (только если маркер ещё не существует)
|
||||
angieMarker := fmt.Sprintf("/tmp/ptaf-angie-drain-%s", blockClientTitle)
|
||||
if _, err := os.Stat(angieMarker); err != nil {
|
||||
if err := markAngieConfigForDrain(blockClientTitle, false); err != nil {
|
||||
log.Printf(" ⚠ Ошибка пометки Angie конфига для %s: %v", blockClientTitle, err)
|
||||
} else {
|
||||
log.Printf(" ✓ Angie конфиг для блока %s помечен для drain", blockName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -485,6 +495,12 @@ func cleanupOneContainerContainers(clientTitle string, hostname string) {
|
|||
containerFullName := buildContainerFullName(clientTitle, containerNum, hostname)
|
||||
exists, _ := checkContainerStatus(containerFullName)
|
||||
if exists {
|
||||
// Проверяем что маркер ещё не существует чтобы не сбрасывать таймер
|
||||
markerFile := fmt.Sprintf("/tmp/ptaf-drain-%s", containerFullName)
|
||||
if _, err := os.Stat(markerFile); err == nil {
|
||||
// Маркер уже есть — не перезаписываем
|
||||
continue
|
||||
}
|
||||
hasNonBlock = true
|
||||
if err := markContainerForDrain(containerFullName, false); err != nil {
|
||||
log.Printf(" ⚠ Ошибка пометки контейнера %s: %v", containerFullName, err)
|
||||
|
|
@ -494,6 +510,11 @@ func cleanupOneContainerContainers(clientTitle string, hostname string) {
|
|||
}
|
||||
}
|
||||
if hasNonBlock {
|
||||
angieMarker := fmt.Sprintf("/tmp/ptaf-angie-drain-%s", clientTitle)
|
||||
if _, err := os.Stat(angieMarker); err == nil {
|
||||
// Маркер Angie уже есть — не перезаписываем
|
||||
return
|
||||
}
|
||||
if err := markAngieConfigForDrain(clientTitle, false); err != nil {
|
||||
log.Printf(" ⚠ Ошибка пометки Angie конфига: %v", err)
|
||||
}
|
||||
|
|
|
|||
17
utils.go
17
utils.go
|
|
@ -424,3 +424,20 @@ func parseSidBlocks(sidBlock string) ([][]int, error) {
|
|||
}
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
// isBlockClientTitle проверяет является ли clientTitle блочным виртуальным именем
|
||||
// вида {clientTitle}_block{N} которые создаются при one_container=false
|
||||
func isBlockClientTitle(clientTitle string) bool {
|
||||
// Ищем паттерн _block{число} в конце строки
|
||||
parts := strings.Split(clientTitle, "_block")
|
||||
if len(parts) < 2 {
|
||||
return false
|
||||
}
|
||||
lastPart := parts[len(parts)-1]
|
||||
for _, c := range lastPart {
|
||||
if c < '0' || c > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return len(lastPart) > 0
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue