diff --git a/sac-client.sh b/sac-client.sh index a741e49..32ecc2b 100644 --- a/sac-client.sh +++ b/sac-client.sh @@ -51,8 +51,8 @@ sac_check_health() { return 0 fi code="$(curl -sS -o /dev/null -w '%{http_code}' \ - --connect-timeout "${SAC_TIMEOUT_SEC:-12}" \ - --max-time "${SAC_TIMEOUT_SEC:-12}" \ + --connect-timeout "${SAC_TIMEOUT_SEC:-45}" \ + --max-time "${SAC_TIMEOUT_SEC:-45}" \ "${base}/health" || echo 000)" [ "$code" = "200" ] } @@ -152,8 +152,8 @@ sac_post_payload() { -H "Authorization: Bearer ${SAC_API_KEY}" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: ${event_id}" \ - --connect-timeout "${SAC_TIMEOUT_SEC:-12}" \ - --max-time "${SAC_TIMEOUT_SEC:-12}" \ + --connect-timeout "${SAC_TIMEOUT_SEC:-45}" \ + --max-time "${SAC_TIMEOUT_SEC:-45}" \ -d @"$tmp" 2>/dev/null || echo 000)" rm -f "$tmp" @@ -170,9 +170,36 @@ sac_post_payload() { return 1 } +# Список spool: report.daily.* первыми (старые раньше), затем остальное. +sac_flush_spool_list_files() { + local dir="${1:-}" + [ -n "$dir" ] && [ -d "$dir" ] || return 0 + SPOOL_DIR="$dir" python3 <<'PY' +import glob +import json +import os + +dir_path = os.environ.get("SPOOL_DIR", "") +daily, other = [], [] +for path in glob.glob(os.path.join(dir_path, "*.json")): + event_type = "" + try: + with open(path, encoding="utf-8") as handle: + event_type = json.load(handle).get("type", "") or "" + except Exception: + pass + mtime = os.path.getmtime(path) + bucket = daily if event_type in ("report.daily.ssh", "report.daily.rdp") else other + bucket.append((mtime, path)) +for bucket in (daily, other): + for _, path in sorted(bucket): + print(path) +PY +} + # Повторная отправка файлов из SAC_SPOOL_DIR (до max_files за вызов). sac_flush_spool() { - local mode max_files="${1:-20}" + local mode max_files="${1:-${SAC_SPOOL_FLUSH_MAX_FILES:-50}}" mode="$(sac_normalize_mode "${UseSAC:-off}")" case "$mode" in off) return 0 ;; @@ -184,17 +211,14 @@ sac_flush_spool() { local dir="${SAC_SPOOL_DIR:-/var/lib/ssh-monitor/sac-spool}" [ -d "$dir" ] || return 0 - local f count=0 - shopt -s nullglob - for f in "$dir"/*.json; do - [ -f "$f" ] || continue + local f count=0 payload + while IFS= read -r f; do + [ -n "$f" ] && [ -f "$f" ] || continue count=$((count + 1)) [ "$count" -gt "$max_files" ] && break - local payload payload="$(cat "$f")" sac_post_payload "$payload" || true - done - shopt -u nullglob + done < <(sac_flush_spool_list_files "$dir") return 0 } @@ -333,6 +357,13 @@ sac_is_heartbeat_only_event() { [ "${1:-}" = "agent.heartbeat" ] } +sac_is_daily_report_event() { + case "${1:-}" in + report.daily.ssh|report.daily.rdp) return 0 ;; + *) return 1 ;; + esac +} + # Добавляет generated_by / telegram_via в JSON details для ingest. sac_merge_notify_details() { local details_json="${1:-}" @@ -393,6 +424,25 @@ notify_or_sac() { esac fi + # Суточный отчёт — только SAC/spool; при сбое ingest не дублировать в локальный Telegram. + if sac_is_daily_report_event "$event_type"; then + case "$mode" in + off) + return 0 + ;; + exclusive|dual|fallback) + if sac_send_event "$event_type" "$severity" "$title" "$summary" "$details_json"; then + return 0 + fi + write_log "WARN: daily report не принят SAC — остаётся в spool (локальный Telegram пропущен)" + return 1 + ;; + *) + return 0 + ;; + esac + fi + case "$mode" in off) notify_send "$telegram_message" diff --git a/ssh-monitor b/ssh-monitor index 590e717..5f0bf9c 100644 --- a/ssh-monitor +++ b/ssh-monitor @@ -7,7 +7,7 @@ IFS=$'\n\t' # ============================================ CONFIG_FILE="/etc/ssh-monitor.conf" -SSH_MONITOR_VERSION="2.1.5-SAC" +SSH_MONITOR_VERSION="2.1.6-SAC" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ -f "$SCRIPT_DIR/sac-client.sh" ]; then @@ -34,7 +34,9 @@ UseSAC="off" SAC_URL="" SAC_API_KEY="" SAC_SPOOL_DIR="/var/lib/ssh-monitor/sac-spool" -SAC_TIMEOUT_SEC="12" +SAC_TIMEOUT_SEC="45" +SAC_SPOOL_FLUSH_MAX_FILES="50" +SAC_SPOOL_MAX_AGE_HOURS="72" SAC_SEND_HEARTBEAT="1" SAC_FALLBACK_FAILURES="5" @@ -224,7 +226,9 @@ load_config() { local cfg_sac_url="${SAC_URL:-}" local cfg_sac_api_key="${SAC_API_KEY:-}" local cfg_sac_spool_dir="${SAC_SPOOL_DIR:-/var/lib/ssh-monitor/sac-spool}" - local cfg_sac_timeout_sec="${SAC_TIMEOUT_SEC:-12}" + local cfg_sac_timeout_sec="${SAC_TIMEOUT_SEC:-45}" + local cfg_sac_spool_flush_max="${SAC_SPOOL_FLUSH_MAX_FILES:-50}" + local cfg_sac_spool_max_age_h="${SAC_SPOOL_MAX_AGE_HOURS:-72}" local cfg_mail_smtp_host="${MAIL_SMTP_HOST:-}" local cfg_mail_smtp_port="${MAIL_SMTP_PORT:-587}" local cfg_mail_smtp_user="${MAIL_SMTP_USER:-}" @@ -297,6 +301,8 @@ load_config() { SAC_API_KEY="$(trim_value "${SAC_API_KEY:-$cfg_sac_api_key}")" SAC_SPOOL_DIR="$(trim_value "${SAC_SPOOL_DIR:-$cfg_sac_spool_dir}")" SAC_TIMEOUT_SEC="$(trim_value "${SAC_TIMEOUT_SEC:-$cfg_sac_timeout_sec}")" + SAC_SPOOL_FLUSH_MAX_FILES="$(trim_value "${SAC_SPOOL_FLUSH_MAX_FILES:-$cfg_sac_spool_flush_max}")" + SAC_SPOOL_MAX_AGE_HOURS="$(trim_value "${SAC_SPOOL_MAX_AGE_HOURS:-$cfg_sac_spool_max_age_h}")" MAIL_SMTP_HOST="$(trim_value "${MAIL_SMTP_HOST:-$cfg_mail_smtp_host}")" MAIL_SMTP_PORT="${MAIL_SMTP_PORT:-$cfg_mail_smtp_port}" MAIL_SMTP_USER="$(trim_value "${MAIL_SMTP_USER:-$cfg_mail_smtp_user}")" @@ -2046,7 +2052,7 @@ main() { monitor_logind check_daily_report check_heartbeat - sac_flush_spool 20 2>/dev/null || true + sac_flush_spool "${SAC_SPOOL_FLUSH_MAX_FILES:-50}" 2>/dev/null || true write_health_and_metrics local current_time diff --git a/ssh-monitor.conf.example b/ssh-monitor.conf.example index 44c0173..c304cc3 100644 --- a/ssh-monitor.conf.example +++ b/ssh-monitor.conf.example @@ -35,7 +35,9 @@ SAC_API_KEY="sac_UkOsAT3UWiQS54KK5OJPBDCSucysQDrKFju28wmYiz8" SAC_SPOOL_DIR="/var/lib/ssh-monitor/sac-spool" SAC_FAIL_COUNT_FILE="/var/lib/ssh-monitor/sac-fail.count" SAC_FALLBACK_FAILURES="5" -SAC_TIMEOUT_SEC="12" +SAC_TIMEOUT_SEC="45" +SAC_SPOOL_FLUSH_MAX_FILES="50" +SAC_SPOOL_MAX_AGE_HOURS="72" # SMTP (python3). Для авто-режима почты нужны MAIL_SMTP_HOST, MAIL_FROM, MAIL_TO. MAIL_SMTP_HOST="" diff --git a/update_ssh_monitor.sh b/update_ssh_monitor.sh index cfc2f4b..50b38b2 100755 --- a/update_ssh_monitor.sh +++ b/update_ssh_monitor.sh @@ -89,6 +89,8 @@ SAC_CONFIG_KEYS=( SAC_FAIL_COUNT_FILE SAC_FALLBACK_FAILURES SAC_TIMEOUT_SEC + SAC_SPOOL_FLUSH_MAX_FILES + SAC_SPOOL_MAX_AGE_HOURS ) SAC_USE_MODE_DEFAULT="fallback" @@ -189,7 +191,9 @@ sync_sac_config_keys() { SAC_SPOOL_DIR) val="$SAC_SPOOL_DIR_DEFAULT" ;; SAC_FAIL_COUNT_FILE) val="/var/lib/ssh-monitor/sac-fail.count" ;; SAC_FALLBACK_FAILURES) val="5" ;; - SAC_TIMEOUT_SEC) val="12" ;; + SAC_TIMEOUT_SEC) val="45" ;; + SAC_SPOOL_FLUSH_MAX_FILES) val="50" ;; + SAC_SPOOL_MAX_AGE_HOURS) val="72" ;; SAC_URL) val="https://sac.kalinamall.ru" ;; esac fi @@ -208,6 +212,14 @@ sync_sac_config_keys() { changed=1 fi + current=$(config_conf_value "SAC_TIMEOUT_SEC" "$file" 2>/dev/null || true) + if [ "$current" = "12" ]; then + backup_config_if_needed "$file" backed_up + set_config_kv "SAC_TIMEOUT_SEC" "45" "$file" + log_message "INFO" "Config $file: SAC_TIMEOUT_SEC 12 → 45 (ingest timeout)." + changed=1 + fi + if [ "$changed" -eq 0 ]; then return 1 fi diff --git a/version.txt b/version.txt index f14000d..6cf3433 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.1.5-SAC +2.1.6-SAC