fix: daily report без локального Telegram при fallback SAC (2.1.6-SAC)

Суточные report.daily.* уходят только в SAC/spool; SAC_TIMEOUT_SEC=45;
приоритет report.* в sac_flush_spool, до 50 файлов за цикл.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
PTah
2026-07-06 12:00:35 +10:00
parent 0a80effd77
commit 9e756674d0
5 changed files with 89 additions and 19 deletions
+62 -12
View File
@@ -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"
+10 -4
View File
@@ -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
+3 -1
View File
@@ -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=""
+13 -1
View File
@@ -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
+1 -1
View File
@@ -1 +1 @@
2.1.5-SAC
2.1.6-SAC