Speed matchchecker
This commit is contained in:
parent
a658bf8c05
commit
8a37c62e63
1 changed files with 89 additions and 20 deletions
107
matchcheck.go
107
matchcheck.go
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue