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:
+62
-12
@@ -51,8 +51,8 @@ sac_check_health() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
code="$(curl -sS -o /dev/null -w '%{http_code}' \
|
code="$(curl -sS -o /dev/null -w '%{http_code}' \
|
||||||
--connect-timeout "${SAC_TIMEOUT_SEC:-12}" \
|
--connect-timeout "${SAC_TIMEOUT_SEC:-45}" \
|
||||||
--max-time "${SAC_TIMEOUT_SEC:-12}" \
|
--max-time "${SAC_TIMEOUT_SEC:-45}" \
|
||||||
"${base}/health" || echo 000)"
|
"${base}/health" || echo 000)"
|
||||||
[ "$code" = "200" ]
|
[ "$code" = "200" ]
|
||||||
}
|
}
|
||||||
@@ -152,8 +152,8 @@ sac_post_payload() {
|
|||||||
-H "Authorization: Bearer ${SAC_API_KEY}" \
|
-H "Authorization: Bearer ${SAC_API_KEY}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "Idempotency-Key: ${event_id}" \
|
-H "Idempotency-Key: ${event_id}" \
|
||||||
--connect-timeout "${SAC_TIMEOUT_SEC:-12}" \
|
--connect-timeout "${SAC_TIMEOUT_SEC:-45}" \
|
||||||
--max-time "${SAC_TIMEOUT_SEC:-12}" \
|
--max-time "${SAC_TIMEOUT_SEC:-45}" \
|
||||||
-d @"$tmp" 2>/dev/null || echo 000)"
|
-d @"$tmp" 2>/dev/null || echo 000)"
|
||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
|
|
||||||
@@ -170,9 +170,36 @@ sac_post_payload() {
|
|||||||
return 1
|
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_SPOOL_DIR (до max_files за вызов).
|
||||||
sac_flush_spool() {
|
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}")"
|
mode="$(sac_normalize_mode "${UseSAC:-off}")"
|
||||||
case "$mode" in
|
case "$mode" in
|
||||||
off) return 0 ;;
|
off) return 0 ;;
|
||||||
@@ -184,17 +211,14 @@ sac_flush_spool() {
|
|||||||
local dir="${SAC_SPOOL_DIR:-/var/lib/ssh-monitor/sac-spool}"
|
local dir="${SAC_SPOOL_DIR:-/var/lib/ssh-monitor/sac-spool}"
|
||||||
[ -d "$dir" ] || return 0
|
[ -d "$dir" ] || return 0
|
||||||
|
|
||||||
local f count=0
|
local f count=0 payload
|
||||||
shopt -s nullglob
|
while IFS= read -r f; do
|
||||||
for f in "$dir"/*.json; do
|
[ -n "$f" ] && [ -f "$f" ] || continue
|
||||||
[ -f "$f" ] || continue
|
|
||||||
count=$((count + 1))
|
count=$((count + 1))
|
||||||
[ "$count" -gt "$max_files" ] && break
|
[ "$count" -gt "$max_files" ] && break
|
||||||
local payload
|
|
||||||
payload="$(cat "$f")"
|
payload="$(cat "$f")"
|
||||||
sac_post_payload "$payload" || true
|
sac_post_payload "$payload" || true
|
||||||
done
|
done < <(sac_flush_spool_list_files "$dir")
|
||||||
shopt -u nullglob
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,6 +357,13 @@ sac_is_heartbeat_only_event() {
|
|||||||
[ "${1:-}" = "agent.heartbeat" ]
|
[ "${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.
|
# Добавляет generated_by / telegram_via в JSON details для ingest.
|
||||||
sac_merge_notify_details() {
|
sac_merge_notify_details() {
|
||||||
local details_json="${1:-}"
|
local details_json="${1:-}"
|
||||||
@@ -393,6 +424,25 @@ notify_or_sac() {
|
|||||||
esac
|
esac
|
||||||
fi
|
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
|
case "$mode" in
|
||||||
off)
|
off)
|
||||||
notify_send "$telegram_message"
|
notify_send "$telegram_message"
|
||||||
|
|||||||
+10
-4
@@ -7,7 +7,7 @@ IFS=$'\n\t'
|
|||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
CONFIG_FILE="/etc/ssh-monitor.conf"
|
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)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
if [ -f "$SCRIPT_DIR/sac-client.sh" ]; then
|
if [ -f "$SCRIPT_DIR/sac-client.sh" ]; then
|
||||||
@@ -34,7 +34,9 @@ UseSAC="off"
|
|||||||
SAC_URL=""
|
SAC_URL=""
|
||||||
SAC_API_KEY=""
|
SAC_API_KEY=""
|
||||||
SAC_SPOOL_DIR="/var/lib/ssh-monitor/sac-spool"
|
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_SEND_HEARTBEAT="1"
|
||||||
SAC_FALLBACK_FAILURES="5"
|
SAC_FALLBACK_FAILURES="5"
|
||||||
|
|
||||||
@@ -224,7 +226,9 @@ load_config() {
|
|||||||
local cfg_sac_url="${SAC_URL:-}"
|
local cfg_sac_url="${SAC_URL:-}"
|
||||||
local cfg_sac_api_key="${SAC_API_KEY:-}"
|
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_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_host="${MAIL_SMTP_HOST:-}"
|
||||||
local cfg_mail_smtp_port="${MAIL_SMTP_PORT:-587}"
|
local cfg_mail_smtp_port="${MAIL_SMTP_PORT:-587}"
|
||||||
local cfg_mail_smtp_user="${MAIL_SMTP_USER:-}"
|
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_API_KEY="$(trim_value "${SAC_API_KEY:-$cfg_sac_api_key}")"
|
||||||
SAC_SPOOL_DIR="$(trim_value "${SAC_SPOOL_DIR:-$cfg_sac_spool_dir}")"
|
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_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_HOST="$(trim_value "${MAIL_SMTP_HOST:-$cfg_mail_smtp_host}")"
|
||||||
MAIL_SMTP_PORT="${MAIL_SMTP_PORT:-$cfg_mail_smtp_port}"
|
MAIL_SMTP_PORT="${MAIL_SMTP_PORT:-$cfg_mail_smtp_port}"
|
||||||
MAIL_SMTP_USER="$(trim_value "${MAIL_SMTP_USER:-$cfg_mail_smtp_user}")"
|
MAIL_SMTP_USER="$(trim_value "${MAIL_SMTP_USER:-$cfg_mail_smtp_user}")"
|
||||||
@@ -2046,7 +2052,7 @@ main() {
|
|||||||
monitor_logind
|
monitor_logind
|
||||||
check_daily_report
|
check_daily_report
|
||||||
check_heartbeat
|
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
|
write_health_and_metrics
|
||||||
|
|
||||||
local current_time
|
local current_time
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ SAC_API_KEY="sac_UkOsAT3UWiQS54KK5OJPBDCSucysQDrKFju28wmYiz8"
|
|||||||
SAC_SPOOL_DIR="/var/lib/ssh-monitor/sac-spool"
|
SAC_SPOOL_DIR="/var/lib/ssh-monitor/sac-spool"
|
||||||
SAC_FAIL_COUNT_FILE="/var/lib/ssh-monitor/sac-fail.count"
|
SAC_FAIL_COUNT_FILE="/var/lib/ssh-monitor/sac-fail.count"
|
||||||
SAC_FALLBACK_FAILURES="5"
|
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.
|
# SMTP (python3). Для авто-режима почты нужны MAIL_SMTP_HOST, MAIL_FROM, MAIL_TO.
|
||||||
MAIL_SMTP_HOST=""
|
MAIL_SMTP_HOST=""
|
||||||
|
|||||||
+13
-1
@@ -89,6 +89,8 @@ SAC_CONFIG_KEYS=(
|
|||||||
SAC_FAIL_COUNT_FILE
|
SAC_FAIL_COUNT_FILE
|
||||||
SAC_FALLBACK_FAILURES
|
SAC_FALLBACK_FAILURES
|
||||||
SAC_TIMEOUT_SEC
|
SAC_TIMEOUT_SEC
|
||||||
|
SAC_SPOOL_FLUSH_MAX_FILES
|
||||||
|
SAC_SPOOL_MAX_AGE_HOURS
|
||||||
)
|
)
|
||||||
SAC_USE_MODE_DEFAULT="fallback"
|
SAC_USE_MODE_DEFAULT="fallback"
|
||||||
|
|
||||||
@@ -189,7 +191,9 @@ sync_sac_config_keys() {
|
|||||||
SAC_SPOOL_DIR) val="$SAC_SPOOL_DIR_DEFAULT" ;;
|
SAC_SPOOL_DIR) val="$SAC_SPOOL_DIR_DEFAULT" ;;
|
||||||
SAC_FAIL_COUNT_FILE) val="/var/lib/ssh-monitor/sac-fail.count" ;;
|
SAC_FAIL_COUNT_FILE) val="/var/lib/ssh-monitor/sac-fail.count" ;;
|
||||||
SAC_FALLBACK_FAILURES) val="5" ;;
|
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" ;;
|
SAC_URL) val="https://sac.kalinamall.ru" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
@@ -208,6 +212,14 @@ sync_sac_config_keys() {
|
|||||||
changed=1
|
changed=1
|
||||||
fi
|
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
|
if [ "$changed" -eq 0 ]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
2.1.5-SAC
|
2.1.6-SAC
|
||||||
|
|||||||
Reference in New Issue
Block a user