Speed matchchecker

This commit is contained in:
Magnus Root 2026-04-24 09:05:22 +03:00
parent a658bf8c05
commit 8a37c62e63

View file

@ -9,6 +9,7 @@ import (
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
"sync"
) )
// ── Типы ───────────────────────────────────────────────────────────────────── // ── Типы ─────────────────────────────────────────────────────────────────────
@ -173,7 +174,7 @@ func mcCheckClient(client, hostname string) mcClientCheck {
func mcCheckContainer(client string, num int, angiePorts []int, hostname string) mcContainerCheck { func mcCheckContainer(client string, num int, angiePorts []int, hostname string) mcContainerCheck {
result := mcContainerCheck{Number: num} result := mcContainerCheck{Number: num}
fullName := fmt.Sprintf("ptaf_%s_%03d", client, num) fullName := mcBuildContainerName(client, hostname, num)
label := fmt.Sprintf("контейнер %03d", num) label := fmt.Sprintf("контейнер %03d", num)
fmt.Printf(" ┌─ Контейнер %03d\n", num) fmt.Printf(" ┌─ Контейнер %03d\n", num)
@ -365,31 +366,99 @@ func mcIsValidJSON(filePath string) bool {
return json.Unmarshal(data, &js) == nil return json.Unmarshal(data, &js) == nil
} }
func mcIsContainerRunning(name string) bool { // mcBuildContainerName строит имя Docker-контейнера по новому формату:
cmd := exec.Command("docker", "ps", "--format", "{{.Names}}") // {ClientTitle}_{AZN}_{prefix}{nodeN}_a{agentN}
output, err := cmd.Output() //
// Пример:
//
// hostname: PTAF-TB-docker-AZ3-HW-node01, client: PSB_CFA, agent: 1
// → PSB_CFA_AZ3_hn01_a001
//
// hostname: PTAF-TB-docker-AZ1-node04, client: ITAR-TASS, agent: 1
// → ITAR-TASS_AZ1_n04_a001
func mcBuildContainerName(client, hostname string, agentNum int) string {
// Извлекаем AZN: ищем AZ + цифры в hostname
azRe := regexp.MustCompile(`AZ(\d+)`)
azMatch := azRe.FindStringSubmatch(hostname)
azPart := "AZ0"
if len(azMatch) > 1 {
azPart = "AZ" + azMatch[1]
}
// Определяем префикс ноды: HW → hn, иначе n
nodePrefix := "n"
if strings.Contains(hostname, "-HW-") {
nodePrefix = "hn"
}
// Извлекаем номер ноды: цифры после "node"
nodeRe := regexp.MustCompile(`node(\d+)`)
nodeMatch := nodeRe.FindStringSubmatch(hostname)
nodePart := "00"
if len(nodeMatch) > 1 {
// Берём последние 2 цифры с ведущим нулём
num := nodeMatch[1]
if len(num) >= 2 {
nodePart = num[len(num)-2:]
} else {
nodePart = fmt.Sprintf("%02s", num)
}
}
return fmt.Sprintf("%s_%s_%s%s_a%03d", client, azPart, nodePrefix, nodePart, agentNum)
}
// ── Кэш системных вызовов ────────────────────────────────────────────────────
// docker ps и ss вызываются один раз на всё выполнение и кэшируются.
// Это критично при большом количестве контейнеров и портов (51+ портов на контейнер).
var (
mcRunningContainers map[string]bool // имя контейнера → запущен
mcListeningPorts map[int]bool // порт → слушается
mcCacheOnce sync.Once
)
func mcInitCache() {
mcCacheOnce.Do(func() {
mcRunningContainers = make(map[string]bool)
mcListeningPorts = make(map[int]bool)
// Один вызов docker ps — все запущенные контейнеры
if out, err := exec.Command("docker", "ps", "--format", "{{.Names}}").Output(); err == nil {
for _, line := range strings.Split(string(out), "\n") {
name := strings.TrimSpace(line)
if name != "" {
mcRunningContainers[name] = true
}
}
}
// Один вызов ss — все слушающие порты
out, err := exec.Command("ss", "-tlnp").Output()
if err != nil { if err != nil {
return false out, err = exec.Command("netstat", "-tlnp").Output()
} }
for _, line := range strings.Split(string(output), "\n") { if err == nil {
if strings.TrimSpace(line) == name { re := regexp.MustCompile(`127\.0\.0\.1:(\d+)`)
return true for _, m := range re.FindAllStringSubmatch(string(out), -1) {
if len(m) > 1 {
var p int
fmt.Sscanf(m[1], "%d", &p)
mcListeningPorts[p] = true
} }
} }
return false }
})
}
func mcIsContainerRunning(name string) bool {
mcInitCache()
return mcRunningContainers[name]
} }
func mcIsPortListening(port int) bool { func mcIsPortListening(port int) bool {
cmd := exec.Command("ss", "-tlnp") mcInitCache()
output, err := cmd.Output() return mcListeningPorts[port]
if err != nil {
cmd = exec.Command("netstat", "-tlnp")
output, err = cmd.Output()
if err != nil {
return false
}
}
return strings.Contains(string(output), fmt.Sprintf("127.0.0.1:%d", port))
} }
func mcContainsInt(slice []int, val int) bool { func mcContainsInt(slice []int, val int) bool {