Docker check playbooks added
This commit is contained in:
parent
ff1a3528c0
commit
efb980d47f
3 changed files with 520 additions and 3 deletions
|
|
@ -56,6 +56,7 @@ var (
|
||||||
cfgNginxConfigGlob = "/home/install/conf/ptaf-nginx/*/*/*/*.conf"
|
cfgNginxConfigGlob = "/home/install/conf/ptaf-nginx/*/*/*/*.conf"
|
||||||
cfgStateFilePath = "/tmp/port_checker_state.json"
|
cfgStateFilePath = "/tmp/port_checker_state.json"
|
||||||
cfgServiceStateFilePath = "/tmp/auspex_service_state.json"
|
cfgServiceStateFilePath = "/tmp/auspex_service_state.json"
|
||||||
|
cfgDockerStateFilePath = "/tmp/auspex_docker_state.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// --- Параметры проверки портов ---
|
// --- Параметры проверки портов ---
|
||||||
|
|
@ -183,6 +184,9 @@ func applyConfig(env map[string]string) {
|
||||||
if v, ok := env["SERVICE_STATE_FILE_PATH"]; ok && v != "" {
|
if v, ok := env["SERVICE_STATE_FILE_PATH"]; ok && v != "" {
|
||||||
cfgServiceStateFilePath = v
|
cfgServiceStateFilePath = v
|
||||||
}
|
}
|
||||||
|
if v, ok := env["DOCKER_STATE_FILE_PATH"]; ok && v != "" {
|
||||||
|
cfgDockerStateFilePath = v
|
||||||
|
}
|
||||||
if v, ok := env["LOG_DIR"]; ok && v != "" {
|
if v, ok := env["LOG_DIR"]; ok && v != "" {
|
||||||
cfgLogDir = v
|
cfgLogDir = v
|
||||||
}
|
}
|
||||||
|
|
|
||||||
499
dockercheck.go
Normal file
499
dockercheck.go
Normal file
|
|
@ -0,0 +1,499 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ── Типы ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
type dcContainerInfo struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Status string // running, exited, dead, restarting, paused, created
|
||||||
|
Health string // healthy, unhealthy, starting, none
|
||||||
|
Image string
|
||||||
|
}
|
||||||
|
|
||||||
|
type dcStateFile struct {
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Containers map[string]dcContainerState `json:"containers"` // name → state
|
||||||
|
}
|
||||||
|
|
||||||
|
type dcContainerState struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Health string `json:"health"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type dcChangeKind string
|
||||||
|
|
||||||
|
const (
|
||||||
|
dcKindStatusChanged dcChangeKind = "status_changed"
|
||||||
|
dcKindHealthChanged dcChangeKind = "health_changed"
|
||||||
|
dcKindDisappeared dcChangeKind = "disappeared"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dcStateChange struct {
|
||||||
|
Name string
|
||||||
|
Kind dcChangeKind
|
||||||
|
PrevState dcContainerState
|
||||||
|
CurrState dcContainerState
|
||||||
|
Image string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch dcStateChange) isProblem() bool {
|
||||||
|
switch ch.Kind {
|
||||||
|
case dcKindDisappeared:
|
||||||
|
return true
|
||||||
|
case dcKindStatusChanged:
|
||||||
|
return ch.CurrState.Status != "running"
|
||||||
|
case dcKindHealthChanged:
|
||||||
|
return ch.CurrState.Health == "unhealthy"
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch dcStateChange) isRecovery() bool {
|
||||||
|
switch ch.Kind {
|
||||||
|
case dcKindStatusChanged:
|
||||||
|
return ch.CurrState.Status == "running" && ch.PrevState.Status != "running"
|
||||||
|
case dcKindHealthChanged:
|
||||||
|
return ch.CurrState.Health == "healthy" && ch.PrevState.Health == "unhealthy"
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Точка входа ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
func runDockerCheck() error {
|
||||||
|
hostname, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
hostname = "unknown"
|
||||||
|
log.Printf("⚠️ Не удалось получить hostname: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("🔍 DockerCheck запущен на хосте: %s", hostname)
|
||||||
|
|
||||||
|
// Проверяем доступность docker
|
||||||
|
if err := dcCheckDockerAvailable(); err != nil {
|
||||||
|
return fmt.Errorf("docker недоступен: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем текущий список контейнеров
|
||||||
|
containers, err := dcGetContainers()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ошибка получения списка контейнеров: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(containers) == 0 {
|
||||||
|
log.Println("ℹ️ Запущенных контейнеров не найдено")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("📦 Найдено контейнеров: %d", len(containers))
|
||||||
|
|
||||||
|
// Выводим текущее состояние
|
||||||
|
for _, c := range containers {
|
||||||
|
emoji := dcStatusEmoji(c.Status, c.Health)
|
||||||
|
if c.Health != "" && c.Health != "none" {
|
||||||
|
log.Printf("%s %-30s | %-12s | health: %s | %s", emoji, c.Name, c.Status, c.Health, c.Image)
|
||||||
|
} else {
|
||||||
|
log.Printf("%s %-30s | %-12s | %s", emoji, c.Name, c.Status, c.Image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Загружаем предыдущее состояние
|
||||||
|
prevState := dcLoadState()
|
||||||
|
|
||||||
|
// Строим map текущего состояния
|
||||||
|
current := make(map[string]dcContainerInfo, len(containers))
|
||||||
|
for _, c := range containers {
|
||||||
|
current[c.Name] = c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сравниваем
|
||||||
|
changes := dcCompareStates(prevState.Containers, current)
|
||||||
|
|
||||||
|
// Статистика
|
||||||
|
runningCount := 0
|
||||||
|
problemCount := 0
|
||||||
|
for _, c := range containers {
|
||||||
|
if c.Status == "running" && c.Health != "unhealthy" {
|
||||||
|
runningCount++
|
||||||
|
} else {
|
||||||
|
problemCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("\n📊 Итоги проверки контейнеров:")
|
||||||
|
log.Printf(" ✅ Работают нормально: %d", runningCount)
|
||||||
|
log.Printf(" ❌ Проблемных: %d", problemCount)
|
||||||
|
log.Printf(" 🔄 Изменений статуса: %d", len(changes))
|
||||||
|
|
||||||
|
if len(changes) > 0 {
|
||||||
|
log.Println("\n🔄 Изменения с последней проверки:")
|
||||||
|
log.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
||||||
|
for _, ch := range changes {
|
||||||
|
arrow := dcChangeArrow(ch)
|
||||||
|
switch ch.Kind {
|
||||||
|
case dcKindDisappeared:
|
||||||
|
log.Printf(" %s %-30s | исчез (был: %s)", arrow, ch.Name, ch.PrevState.Status)
|
||||||
|
case dcKindStatusChanged:
|
||||||
|
log.Printf(" %s %-30s | %s → %s", arrow, ch.Name, ch.PrevState.Status, ch.CurrState.Status)
|
||||||
|
case dcKindHealthChanged:
|
||||||
|
log.Printf(" %s %-30s | health: %s → %s", arrow, ch.Name, ch.PrevState.Health, ch.CurrState.Health)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
||||||
|
|
||||||
|
if isTelegramConfigured() {
|
||||||
|
dcSendAlert(hostname, changes)
|
||||||
|
} else {
|
||||||
|
log.Println("\nℹ️ Telegram уведомления отключены (не настроены данные)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(prevState.Containers) == 0 {
|
||||||
|
log.Println("\nℹ️ Первый запуск — состояние сохранено, уведомления при изменениях")
|
||||||
|
} else {
|
||||||
|
log.Println("\n✅ Изменений нет — уведомления не отправляются")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохраняем текущее состояние
|
||||||
|
dcSaveState(current)
|
||||||
|
|
||||||
|
log.Println("=== Проверка контейнеров завершена ===")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Получение контейнеров ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
func dcCheckDockerAvailable() error {
|
||||||
|
err := exec.Command("docker", "info").Run()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("docker info завершился с ошибкой: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dcGetContainers() ([]dcContainerInfo, error) {
|
||||||
|
// Получаем все контейнеры (включая не-running) через Go-шаблон
|
||||||
|
// Поля: ID, Name, Status, Health, Image — разделитель |
|
||||||
|
out, err := exec.Command(
|
||||||
|
"docker", "ps", "-a",
|
||||||
|
"--format", "{{.ID}}|{{.Names}}|{{.Status}}|{{.Health}}|{{.Image}}",
|
||||||
|
).Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("docker ps завершился с ошибкой: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var containers []dcContainerInfo
|
||||||
|
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parts := strings.SplitN(line, "|", 5)
|
||||||
|
if len(parts) != 5 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c := dcContainerInfo{
|
||||||
|
ID: strings.TrimSpace(parts[0]),
|
||||||
|
Name: strings.TrimSpace(parts[1]),
|
||||||
|
Image: strings.TrimSpace(parts[4]),
|
||||||
|
Health: strings.ToLower(strings.TrimSpace(parts[3])),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status из docker ps выглядит как "Up 2 hours" или "Exited (1) 3 minutes ago"
|
||||||
|
// Нормализуем до короткого статуса
|
||||||
|
c.Status = dcNormalizeStatus(parts[2])
|
||||||
|
|
||||||
|
containers = append(containers, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return containers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dcNormalizeStatus приводит вывод docker ps к короткому статусу
|
||||||
|
func dcNormalizeStatus(raw string) string {
|
||||||
|
raw = strings.TrimSpace(raw)
|
||||||
|
lower := strings.ToLower(raw)
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(lower, "up"):
|
||||||
|
return "running"
|
||||||
|
case strings.HasPrefix(lower, "exited"):
|
||||||
|
return "exited"
|
||||||
|
case strings.HasPrefix(lower, "restarting"):
|
||||||
|
return "restarting"
|
||||||
|
case strings.HasPrefix(lower, "dead"):
|
||||||
|
return "dead"
|
||||||
|
case strings.HasPrefix(lower, "paused"):
|
||||||
|
return "paused"
|
||||||
|
case strings.HasPrefix(lower, "created"):
|
||||||
|
return "created"
|
||||||
|
case strings.HasPrefix(lower, "removal"):
|
||||||
|
return "removing"
|
||||||
|
default:
|
||||||
|
return lower
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Сравнение состояний ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
func dcCompareStates(prev map[string]dcContainerState, curr map[string]dcContainerInfo) []dcStateChange {
|
||||||
|
var changes []dcStateChange
|
||||||
|
|
||||||
|
// Проверяем текущие контейнеры
|
||||||
|
for name, currInfo := range curr {
|
||||||
|
prevInfo, existed := prev[name]
|
||||||
|
|
||||||
|
if !existed {
|
||||||
|
// Новый контейнер — не алертим, просто добавится в state
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
currState := dcContainerState{Status: currInfo.Status, Health: currInfo.Health}
|
||||||
|
|
||||||
|
// Изменение статуса
|
||||||
|
if prevInfo.Status != currState.Status {
|
||||||
|
changes = append(changes, dcStateChange{
|
||||||
|
Name: name,
|
||||||
|
Kind: dcKindStatusChanged,
|
||||||
|
PrevState: prevInfo,
|
||||||
|
CurrState: currState,
|
||||||
|
Image: currInfo.Image,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Изменение health (независимо от статуса)
|
||||||
|
if prevInfo.Health != currState.Health &&
|
||||||
|
currState.Health != "" && currState.Health != "none" &&
|
||||||
|
prevInfo.Health != "" && prevInfo.Health != "none" {
|
||||||
|
changes = append(changes, dcStateChange{
|
||||||
|
Name: name,
|
||||||
|
Kind: dcKindHealthChanged,
|
||||||
|
PrevState: prevInfo,
|
||||||
|
CurrState: currState,
|
||||||
|
Image: currInfo.Image,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем исчезнувшие контейнеры (были в state, нет сейчас)
|
||||||
|
for name, prevInfo := range prev {
|
||||||
|
if _, exists := curr[name]; !exists {
|
||||||
|
changes = append(changes, dcStateChange{
|
||||||
|
Name: name,
|
||||||
|
Kind: dcKindDisappeared,
|
||||||
|
PrevState: prevInfo,
|
||||||
|
CurrState: dcContainerState{},
|
||||||
|
Image: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── State-файл ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
func dcLoadState() dcStateFile {
|
||||||
|
data, err := os.ReadFile(cfgDockerStateFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return dcStateFile{Containers: make(map[string]dcContainerState)}
|
||||||
|
}
|
||||||
|
|
||||||
|
var state dcStateFile
|
||||||
|
if err := json.Unmarshal(data, &state); err != nil {
|
||||||
|
log.Printf("⚠️ Не удалось прочитать state-файл docker: %v", err)
|
||||||
|
return dcStateFile{Containers: make(map[string]dcContainerState)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
func dcSaveState(current map[string]dcContainerInfo) {
|
||||||
|
containers := make(map[string]dcContainerState, len(current))
|
||||||
|
for name, info := range current {
|
||||||
|
containers[name] = dcContainerState{
|
||||||
|
Status: info.Status,
|
||||||
|
Health: info.Health,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state := dcStateFile{
|
||||||
|
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
Containers: containers,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.MarshalIndent(state, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("⚠️ Ошибка сериализации state-файла docker: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(cfgDockerStateFilePath, data, 0644); err != nil {
|
||||||
|
log.Printf("⚠️ Ошибка записи state-файла %s: %v", cfgDockerStateFilePath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Отправка алерта ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
func dcSendAlert(hostname string, changes []dcStateChange) {
|
||||||
|
var problems, recoveries []dcStateChange
|
||||||
|
for _, ch := range changes {
|
||||||
|
if ch.isRecovery() {
|
||||||
|
recoveries = append(recoveries, ch)
|
||||||
|
} else if ch.isProblem() {
|
||||||
|
problems = append(problems, ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если нет ни проблем, ни восстановлений — молчим
|
||||||
|
if len(problems) == 0 && len(recoveries) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Заголовок по наиболее критичному событию
|
||||||
|
var header string
|
||||||
|
switch {
|
||||||
|
case len(problems) > 0 && len(recoveries) > 0:
|
||||||
|
header = "⚠️ <b>Изменения в состоянии контейнеров</b>"
|
||||||
|
case len(problems) > 0:
|
||||||
|
header = "🚨 <b>АЛЕРТ: Проблемы с контейнерами!</b>"
|
||||||
|
default:
|
||||||
|
header = "✅ <b>Контейнеры восстановлены</b>"
|
||||||
|
}
|
||||||
|
|
||||||
|
message := fmt.Sprintf(
|
||||||
|
"%s\n\n"+
|
||||||
|
"🖥 <b>Хост:</b> <code>%s</code>\n"+
|
||||||
|
"⏰ <b>Время:</b> %s\n\n",
|
||||||
|
header,
|
||||||
|
hostname,
|
||||||
|
time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Проблемные контейнеры
|
||||||
|
if len(problems) > 0 {
|
||||||
|
message += "━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
message += fmt.Sprintf("❌ <b>Проблемы (%d):</b>\n\n", len(problems))
|
||||||
|
for _, ch := range problems {
|
||||||
|
emoji := dcChangeEmoji(ch)
|
||||||
|
switch ch.Kind {
|
||||||
|
case dcKindDisappeared:
|
||||||
|
message += fmt.Sprintf(
|
||||||
|
"%s <b>%s</b>\n"+
|
||||||
|
" 📌 Контейнер исчез (был: <code>%s</code>)\n\n",
|
||||||
|
emoji, ch.Name, ch.PrevState.Status,
|
||||||
|
)
|
||||||
|
case dcKindStatusChanged:
|
||||||
|
message += fmt.Sprintf(
|
||||||
|
"%s <b>%s</b>\n"+
|
||||||
|
" 📌 <code>%s</code> → <code>%s</code>\n"+
|
||||||
|
" 🐳 <code>%s</code>\n"+
|
||||||
|
" 🔧 <code>docker logs %s --tail 50</code>\n\n",
|
||||||
|
emoji, ch.Name,
|
||||||
|
ch.PrevState.Status, ch.CurrState.Status,
|
||||||
|
ch.Image, ch.Name,
|
||||||
|
)
|
||||||
|
case dcKindHealthChanged:
|
||||||
|
message += fmt.Sprintf(
|
||||||
|
"%s <b>%s</b>\n"+
|
||||||
|
" 📌 health: <code>%s</code> → <code>%s</code>\n"+
|
||||||
|
" 🐳 <code>%s</code>\n"+
|
||||||
|
" 🔧 <code>docker inspect %s</code>\n\n",
|
||||||
|
emoji, ch.Name,
|
||||||
|
ch.PrevState.Health, ch.CurrState.Health,
|
||||||
|
ch.Image, ch.Name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Восстановленные контейнеры
|
||||||
|
if len(recoveries) > 0 {
|
||||||
|
message += "━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
message += fmt.Sprintf("✅ <b>Восстановились (%d):</b>\n\n", len(recoveries))
|
||||||
|
for _, ch := range recoveries {
|
||||||
|
switch ch.Kind {
|
||||||
|
case dcKindStatusChanged:
|
||||||
|
message += fmt.Sprintf(
|
||||||
|
"✅ <b>%s</b>\n"+
|
||||||
|
" 📌 <code>%s</code> → <code>%s</code>\n\n",
|
||||||
|
ch.Name, ch.PrevState.Status, ch.CurrState.Status,
|
||||||
|
)
|
||||||
|
case dcKindHealthChanged:
|
||||||
|
message += fmt.Sprintf(
|
||||||
|
"✅ <b>%s</b>\n"+
|
||||||
|
" 📌 health: <code>%s</code> → <code>%s</code>\n\n",
|
||||||
|
ch.Name, ch.PrevState.Health, ch.CurrState.Health,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message += "━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
message += "💡 <i>docker ps -a | docker logs <имя> --tail 50</i>"
|
||||||
|
|
||||||
|
if err := telegramSendHTML(message); err != nil {
|
||||||
|
log.Printf("❌ Ошибка отправки в Telegram: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("✅ Алерт успешно отправлен в Telegram")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Вспомогательные функции ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
func dcStatusEmoji(status, health string) string {
|
||||||
|
if health == "unhealthy" {
|
||||||
|
return "🤒"
|
||||||
|
}
|
||||||
|
switch status {
|
||||||
|
case "running":
|
||||||
|
return "✅"
|
||||||
|
case "restarting":
|
||||||
|
return "🔄"
|
||||||
|
case "exited":
|
||||||
|
return "🔴"
|
||||||
|
case "dead":
|
||||||
|
return "💀"
|
||||||
|
case "paused":
|
||||||
|
return "⏸"
|
||||||
|
default:
|
||||||
|
return "❓"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dcChangeEmoji(ch dcStateChange) string {
|
||||||
|
switch ch.Kind {
|
||||||
|
case dcKindDisappeared:
|
||||||
|
return "👻"
|
||||||
|
case dcKindHealthChanged:
|
||||||
|
return "🤒"
|
||||||
|
case dcKindStatusChanged:
|
||||||
|
switch ch.CurrState.Status {
|
||||||
|
case "restarting":
|
||||||
|
return "🔄"
|
||||||
|
case "exited":
|
||||||
|
return "🔴"
|
||||||
|
case "dead":
|
||||||
|
return "💀"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "❓"
|
||||||
|
}
|
||||||
|
|
||||||
|
func dcChangeArrow(ch dcStateChange) string {
|
||||||
|
if ch.isRecovery() {
|
||||||
|
return "✅"
|
||||||
|
}
|
||||||
|
if ch.isProblem() {
|
||||||
|
return "❌"
|
||||||
|
}
|
||||||
|
return "🔄"
|
||||||
|
}
|
||||||
20
main.go
20
main.go
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const appVersion = "1.1.0"
|
const appVersion = "1.2.0"
|
||||||
|
|
||||||
// Цвета терминала (общие для всех модулей)
|
// Цвета терминала (общие для всех модулей)
|
||||||
const (
|
const (
|
||||||
|
|
@ -86,6 +86,13 @@ func runByFlag(flag string, extraArgs []string) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "-dc", "-d":
|
||||||
|
fmt.Printf("%s🐳 Auspex — Проверка контейнеров Docker%s\n\n", cCyan, cReset)
|
||||||
|
if err := runDockerCheck(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
case "-v", "--version":
|
case "-v", "--version":
|
||||||
fmt.Printf("auspex v%s\n", appVersion)
|
fmt.Printf("auspex v%s\n", appVersion)
|
||||||
|
|
||||||
|
|
@ -109,9 +116,10 @@ func showMenu() {
|
||||||
fmt.Printf(" %s4%s) %s-m %s Проверка совпадений портов Angie ↔ Docker\n", cGreen, cReset, cCyan, cReset)
|
fmt.Printf(" %s4%s) %s-m %s Проверка совпадений портов Angie ↔ Docker\n", cGreen, cReset, cCyan, cReset)
|
||||||
fmt.Printf(" %s5%s) %s-l %s Проверка активности логов (PostgreSQL)\n", cGreen, cReset, cCyan, cReset)
|
fmt.Printf(" %s5%s) %s-l %s Проверка активности логов (PostgreSQL)\n", cGreen, cReset, cCyan, cReset)
|
||||||
fmt.Printf(" %s6%s) %s-sv%s Проверка состояния служб (systemd)\n", cGreen, cReset, cCyan, cReset)
|
fmt.Printf(" %s6%s) %s-sv%s Проверка состояния служб (systemd)\n", cGreen, cReset, cCyan, cReset)
|
||||||
|
fmt.Printf(" %s7%s) %s-dc%s Проверка контейнеров Docker\n", cGreen, cReset, cCyan, cReset)
|
||||||
fmt.Printf(" %s0%s) Выход\n\n", cGreen, cReset)
|
fmt.Printf(" %s0%s) Выход\n\n", cGreen, cReset)
|
||||||
fmt.Printf("%sДля быстрого вызова: auspex <ключ>%s\n", cYellow, cReset)
|
fmt.Printf("%sДля быстрого вызова: auspex <ключ>%s\n", cYellow, cReset)
|
||||||
fmt.Printf("%sПример: auspex -ss | auspex -c | auspex -p | auspex -m [клиент] | auspex -l | auspex -sv%s\n\n", cYellow, cReset)
|
fmt.Printf("%sПример: auspex -ss | auspex -c | auspex -p | auspex -m [клиент] | auspex -l | auspex -sv | auspex -dc%s\n\n", cYellow, cReset)
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
|
|
@ -154,11 +162,16 @@ func showMenu() {
|
||||||
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
case "7", "-dc", "-d", "dc", "d":
|
||||||
|
if err := runDockerCheck(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
case "0", "q", "quit", "exit":
|
case "0", "q", "quit", "exit":
|
||||||
fmt.Println("Выход.")
|
fmt.Println("Выход.")
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
fmt.Printf("%sНеизвестная команда. Введите 1-6 или 0 для выхода.%s\n", cRed, cReset)
|
fmt.Printf("%sНеизвестная команда. Введите 1-7 или 0 для выхода.%s\n", cRed, cReset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,6 +197,7 @@ func printUsage() {
|
||||||
fmt.Printf(" %-12s Проверка совпадений портов Angie ↔ Docker [имя_клиента]\n", "-m")
|
fmt.Printf(" %-12s Проверка совпадений портов Angie ↔ Docker [имя_клиента]\n", "-m")
|
||||||
fmt.Printf(" %-12s Проверка активности логов (PostgreSQL)\n", "-l")
|
fmt.Printf(" %-12s Проверка активности логов (PostgreSQL)\n", "-l")
|
||||||
fmt.Printf(" %-12s Проверка состояния служб systemd\n", "-sv")
|
fmt.Printf(" %-12s Проверка состояния служб systemd\n", "-sv")
|
||||||
|
fmt.Printf(" %-12s Проверка контейнеров Docker\n", "-dc")
|
||||||
fmt.Printf(" %-12s Показать версию\n", "-v")
|
fmt.Printf(" %-12s Показать версию\n", "-v")
|
||||||
fmt.Printf(" %-12s Показать эту справку\n\n", "-h")
|
fmt.Printf(" %-12s Показать эту справку\n\n", "-h")
|
||||||
fmt.Printf("Без аргументов запускается интерактивное меню.\n")
|
fmt.Printf("Без аргументов запускается интерактивное меню.\n")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue