From f3b7c9d41c26f2be731b1d744d295f02530a23ce Mon Sep 17 00:00:00 2001 From: PTah Date: Thu, 28 May 2026 08:13:24 +1000 Subject: [PATCH] feat: verbose update_ssh_monitor action log and run summary Log each step to /var/log/update_script.log and stdout (unless --quiet). End-of-run summary explains skip reasons: checksum match, git pull fail, missing clone path, versions and sha256 prefixes. --- docs/auto-update.ru.md | 11 +++ update_ssh_monitor.sh | 214 ++++++++++++++++++++++++++++++++++------- 2 files changed, 188 insertions(+), 37 deletions(-) diff --git a/docs/auto-update.ru.md b/docs/auto-update.ru.md index b365e10..d4a2de0 100644 --- a/docs/auto-update.ru.md +++ b/docs/auto-update.ru.md @@ -146,6 +146,17 @@ sudo cp /usr/local/bin/ssh-monitor.backup.YYYYMMDD_HHMMSS /usr/local/bin/ssh-mon sudo systemctl restart ssh-monitor.service ``` +## Лог и диагностика «мгновенного» завершения + +Все шаги пишутся в **`/var/log/update_script.log`**. При обычном запуске те же строки дублируются в stdout (кроме **`--quiet`**). + +В конце каждого прогона — блок **«Итог обновления»**: статус `ssh-monitor` / `sac-client` / git / перезапуск и **причина**, если файлы не копировались (checksum совпал, git pull failed, скрипт не найден в клоне). + +```bash +sudo /opt/scripts/update_ssh_monitor.sh +sudo tail -40 /var/log/update_script.log +``` + ## Ограничения - Обновляется **только** файл **`ssh-monitor`**, не конфиг и не watchdog. diff --git a/update_ssh_monitor.sh b/update_ssh_monitor.sh index f818f77..c20b261 100755 --- a/update_ssh_monitor.sh +++ b/update_ssh_monitor.sh @@ -10,6 +10,16 @@ LOG_FILE="/var/log/update_script.log" # Режим отладки: 1 = включён, 0 = выключен DEBUG=0 DEPLOY_MODE=0 +QUIET=0 + +# Итог последнего прогона (для лога и консоли) +SUMMARY_SCRIPT="—" +SUMMARY_SCRIPT_REASON="—" +SUMMARY_SAC_CLIENT="—" +SUMMARY_SAC_REASON="—" +SUMMARY_CONFIG="—" +SUMMARY_GIT="—" +SUMMARY_SERVICE_RESTART="—" CONFIG_FILE="/etc/ssh-monitor.conf" DEPLOY_INSTALL_PATH="/opt/scripts/update_ssh_monitor.sh" @@ -51,8 +61,11 @@ update_ssh_monitor.sh — обновление или первичная уст Опции: --deploy установить ssh-monitor, sac-client, пример конфига, systemd unit --debug подробный лог в /var/log/update_script.log + --quiet не печатать шаги в stdout (только в $LOG_FILE) -h, --help эта справка +Лог действий: /var/log/update_script.log (в конце каждого прогона — блок «Итог обновления»). + При первой установке или апгрейде с UseSAC=off / пустым SAC_API_KEY / без sac-client.sh example из git перезаписывает /etc/ssh-monitor.conf (старый файл — .bak.*). EOF @@ -153,6 +166,10 @@ parse_command_line() { DEBUG=1 shift ;; + --quiet) + QUIET=1 + shift + ;; -h | --help) show_help exit 0 @@ -198,6 +215,47 @@ log_message() { fi } +# Всегда в лог; в stdout — если не --quiet (удобно при ручном запуске и cron с mail) +log_action() { + log_message "INFO" "$1" + if [ "$QUIET" -eq 0 ]; then + printf '[update_ssh_monitor] %s\n' "$1" + fi +} + +get_git_short_rev() { + local repo_dir="$1" + git -C "$repo_dir" rev-parse --short HEAD 2>/dev/null || printf 'unknown' +} + +read_ssh_monitor_version() { + local f="$1" + local line + [ -f "$f" ] || return 0 + line=$(grep -E '^[[:space:]]*SSH_MONITOR_VERSION=' "$f" 2>/dev/null | head -1) || return 0 + line=${line#SSH_MONITOR_VERSION=} + line=${line#\"} + line=${line%\"} + line=${line#\'} + line=${line%\'} + printf '%s' "$line" +} + +file_sha256() { + sha256sum "$1" 2>/dev/null | awk '{print $1}' || true +} + +log_update_summary() { + log_action "===== Итог обновления =====" + log_action "ssh-monitor: $SUMMARY_SCRIPT ($SUMMARY_SCRIPT_REASON)" + log_action "sac-client.sh: $SUMMARY_SAC_CLIENT ($SUMMARY_SAC_REASON)" + log_action "конфиг: $SUMMARY_CONFIG" + log_action "git: $SUMMARY_GIT" + log_action "перезапуск ssh-monitor.service: $SUMMARY_SERVICE_RESTART" + log_action "полный лог: $LOG_FILE" + log_action "===========================" +} + # Функция для логирования шагов с комментариями (работает только при DEBUG=1) debug_step() { if [ "$DEBUG" -eq 1 ]; then @@ -377,38 +435,50 @@ sync_sac_client() { SAC_CLIENT_CHANGED=0 local remote local_dst local_sum remote_sum remote=$(find_sac_client_remote) || { - log_message "INFO" "WARNING: sac-client.sh not found in repository clone" + SUMMARY_SAC_CLIENT="не найден в клоне" + SUMMARY_SAC_REASON="путь $UPDATE_DIR/$SCRIPT_NAME/sac-client.sh" + log_action "WARNING: sac-client.sh не найден в клоне git" debug_step "sac-client.sh не найден в клоне репозитория" return 0 } local_dst="${LOCAL_SCRIPT_PATH%/*}/sac-client.sh" - remote_sum=$(sha256sum "$remote" 2>/dev/null | awk '{print $1}') + log_action "sac-client: remote=$remote local=$local_dst" + remote_sum=$(file_sha256 "$remote") if [ -z "$remote_sum" ]; then - log_message "INFO" "ERROR: Failed to checksum remote sac-client.sh" + SUMMARY_SAC_CLIENT="ошибка" + SUMMARY_SAC_REASON="не удалось sha256 remote" + log_action "ERROR: не удалось посчитать sha256 для $remote" return 1 fi if [ "$DEPLOY_MODE" -ne 1 ] && [ -f "$local_dst" ]; then - local_sum=$(sha256sum "$local_dst" 2>/dev/null | awk '{print $1}') + local_sum=$(file_sha256 "$local_dst") if [ "$local_sum" = "$remote_sum" ]; then - log_message "INFO" "sac-client.sh checksums match. No update needed." + SUMMARY_SAC_CLIENT="без изменений" + SUMMARY_SAC_REASON="sha256 совпадает (${local_sum:0:16}…)" + log_action "sac-client.sh: checksum совпадает, копирование не требуется" debug_step "sac-client.sh без изменений" return 0 fi + log_action "sac-client.sh: checksum отличается (local ${local_sum:0:16}… != remote ${remote_sum:0:16}…)" elif [ ! -f "$local_dst" ]; then - log_message "INFO" "Local sac-client.sh not found. Will install." + log_action "sac-client.sh: локальный файл отсутствует, будет установлен" debug_step "Локальный sac-client.sh отсутствует, будет установлен" fi debug_step "Копируем sac-client.sh в $local_dst" if ! cp "$remote" "$local_dst"; then - log_message "INFO" "ERROR: Failed to copy sac-client.sh" + SUMMARY_SAC_CLIENT="ошибка копирования" + SUMMARY_SAC_REASON="cp $remote -> $local_dst" + log_action "ERROR: не удалось скопировать sac-client.sh" return 1 fi chmod 644 "$local_dst" SAC_CLIENT_CHANGED=1 - log_message "INFO" "sac-client.sh updated." + SUMMARY_SAC_CLIENT="обновлён" + SUMMARY_SAC_REASON="sha256 ${remote_sum:0:16}…" + log_action "sac-client.sh обновлён → $local_dst" if [ "$DEPLOY_MODE" -eq 1 ]; then say_ok "sac-client.sh → $local_dst" fi @@ -419,27 +489,33 @@ find_remote_ssh_monitor_path() { REMOTE_SCRIPT_PATH="$UPDATE_DIR/$SCRIPT_NAME/src/branch/main/$SCRIPT_NAME" ALT_REMOTE_PATH="$UPDATE_DIR/$SCRIPT_NAME/$SCRIPT_NAME" if [ -f "$REMOTE_SCRIPT_PATH" ]; then + log_action "ssh-monitor в клоне: $REMOTE_SCRIPT_PATH (src/branch/main)" printf '%s\n' "$REMOTE_SCRIPT_PATH" return 0 fi if [ -f "$ALT_REMOTE_PATH" ]; then - log_message "INFO" "Script found at alternative path" + log_action "ssh-monitor в клоне: $ALT_REMOTE_PATH (корень репозитория)" printf '%s\n' "$ALT_REMOTE_PATH" return 0 fi + log_action "WARNING: ssh-monitor не найден ни в $REMOTE_SCRIPT_PATH, ни в $ALT_REMOTE_PATH" return 1 } install_ssh_monitor_from() { local actual_script_path="$1" + local backup_path="" if [ -f "$LOCAL_SCRIPT_PATH" ]; then - cp "$LOCAL_SCRIPT_PATH" "${LOCAL_SCRIPT_PATH}.backup.$(date +%Y%m%d_%H%M%S)" 2>/dev/null || true + backup_path="${LOCAL_SCRIPT_PATH}.backup.$(date +%Y%m%d_%H%M%S)" + cp "$LOCAL_SCRIPT_PATH" "$backup_path" 2>/dev/null || true + log_action "резервная копия: $backup_path" fi if ! cp "$actual_script_path" "$LOCAL_SCRIPT_PATH"; then - log_message "INFO" "ERROR: Failed to copy script" + log_action "ERROR: не удалось скопировать $actual_script_path → $LOCAL_SCRIPT_PATH" return 1 fi chmod +x "$LOCAL_SCRIPT_PATH" + log_action "ssh-monitor установлен: $LOCAL_SCRIPT_PATH (версия $(read_ssh_monitor_version "$LOCAL_SCRIPT_PATH"))" if [ "$DEPLOY_MODE" -eq 1 ]; then say_ok "ssh-monitor → $LOCAL_SCRIPT_PATH" fi @@ -536,99 +612,155 @@ restart_ssh_monitor_service() { debug_step "Перезапускаем сервис ssh-monitor.service" if command -v systemctl &>/dev/null; then if systemctl restart ssh-monitor.service 2>/dev/null; then - log_message "INFO" "Service restarted successfully." + SUMMARY_SERVICE_RESTART="выполнен" + log_action "ssh-monitor.service перезапущен" debug_step "Сервис успешно перезапущен" else - log_message "INFO" "WARNING: Failed to restart service (may not be running)" + SUMMARY_SERVICE_RESTART="не удался" + log_action "WARNING: systemctl restart ssh-monitor.service не выполнен" debug_step "ПРЕДУПРЕЖДЕНИЕ: Не удалось перезапустить сервис" fi else - log_message "INFO" "systemctl not found, service not restarted" + SUMMARY_SERVICE_RESTART="пропущен (нет systemctl)" + log_action "systemctl не найден, перезапуск сервиса пропущен" debug_step "systemctl не найден, сервис не перезапущен" fi } # Функция для обновления скрипта update_script() { - log_message "INFO" "Starting script update..." + local git_repo="$UPDATE_DIR/$SCRIPT_NAME" + local git_before="" git_after="" pull_ok=1 + local actual_script_path="" script_changed=0 + local local_ver="" remote_ver="" local_sum="" remote_sum="" + + SUMMARY_SCRIPT="—" + SUMMARY_SCRIPT_REASON="—" + SUMMARY_SAC_CLIENT="—" + SUMMARY_SAC_REASON="—" + SUMMARY_CONFIG="—" + SUMMARY_GIT="—" + SUMMARY_SERVICE_RESTART="не требовался" + + log_action "Старт обновления (deploy=$DEPLOY_MODE, debug=$DEBUG)" debug_step "Запуск функции обновления скрипта" - # Гарантируем наличие директории debug_step "Гарантируем наличие директории для работы" if ! ensure_directories; then + SUMMARY_SCRIPT="ошибка" + SUMMARY_SCRIPT_REASON="нет каталога $UPDATE_DIR или нет прав на запись" + log_update_summary return 1 fi - # Переходим в директорию для клона репозитория debug_step "Переходим в директорию для клона репозитория: $UPDATE_DIR" if ! cd "$UPDATE_DIR" 2>/dev/null; then - log_message "INFO" "ERROR: Cannot cd to $UPDATE_DIR" + SUMMARY_SCRIPT="ошибка" + SUMMARY_SCRIPT_REASON="cannot cd $UPDATE_DIR" + log_action "ERROR: cannot cd $UPDATE_DIR" + log_update_summary return 1 fi - # Клонируем или обновляем репозиторий debug_step "Проверяем наличие репозитория и обновляем/клонируем" if [ -d "$SCRIPT_NAME" ]; then - log_message "INFO" "Repository exists, pulling updates..." + git_before="$(get_git_short_rev "$git_repo")" + log_action "git: pull origin main (было commit $git_before) → $REPO_URL" debug_step "Выполняем git pull origin main" - if ! git -C "$SCRIPT_NAME" pull origin main >> "$LOG_FILE" 2>&1; then - log_message "INFO" "WARNING: git pull failed, continuing with existing local copy..." + if git -C "$SCRIPT_NAME" pull origin main >> "$LOG_FILE" 2>&1; then + git_after="$(get_git_short_rev "$git_repo")" + SUMMARY_GIT="pull ok, $git_before → $git_after" + log_action "git pull: успех (commit $git_before → $git_after)" + else + pull_ok=0 + git_after="$(get_git_short_rev "$git_repo")" + SUMMARY_GIT="pull FAILED, используется локальный клон ($git_after)" + log_action "WARNING: git pull не удался — продолжаем со старым клоном (commit $git_after). См. хвост $LOG_FILE" fi else - log_message "INFO" "Cloning repository from $REPO_URL" + log_action "git: clone $REPO_URL → $UPDATE_DIR/$SCRIPT_NAME" debug_step "Выполняем git clone $REPO_URL $SCRIPT_NAME" if ! git clone "$REPO_URL" "$SCRIPT_NAME" >> "$LOG_FILE" 2>&1; then - log_message "INFO" "ERROR: git clone failed" + SUMMARY_GIT="clone FAILED" + SUMMARY_SCRIPT="ошибка" + SUMMARY_SCRIPT_REASON="git clone failed" + log_action "ERROR: git clone failed (см. $LOG_FILE)" + log_update_summary return 1 fi + git_after="$(get_git_short_rev "$git_repo")" + SUMMARY_GIT="clone ok, commit $git_after" + log_action "git clone: успех (commit $git_after)" fi - local actual_script_path="" actual_script_path="$(find_remote_ssh_monitor_path 2>/dev/null || true)" debug_step "Путь к ssh-monitor в клоне: ${actual_script_path:-не найден}" SAC_CLIENT_CHANGED=0 if ! sync_sac_client; then + log_update_summary return 1 fi CONFIG_CHANGED=0 if ! ensure_ssh_monitor_config_from_example; then + log_update_summary return 1 fi - - local script_changed=0 + if [ "${CONFIG_CHANGED:-0}" -eq 1 ]; then + SUMMARY_CONFIG="обновлён из example" + else + SUMMARY_CONFIG="без изменений" + fi if [ -n "$actual_script_path" ] && [ -f "$actual_script_path" ]; then if [ "$DEPLOY_MODE" -eq 1 ]; then - log_message "INFO" "Deploy: installing ssh-monitor to $LOCAL_SCRIPT_PATH" + log_action "режим --deploy: установка ssh-monitor → $LOCAL_SCRIPT_PATH" if install_ssh_monitor_from "$actual_script_path"; then script_changed=1 + SUMMARY_SCRIPT="установлен (--deploy)" + SUMMARY_SCRIPT_REASON="$(read_ssh_monitor_version "$LOCAL_SCRIPT_PATH")" else + SUMMARY_SCRIPT="ошибка установки" + log_update_summary return 1 fi else - log_message "INFO" "Remote script found. Comparing checksums..." if [ ! -f "$LOCAL_SCRIPT_PATH" ]; then LOCAL_CHECKSUM="" + local_ver="(нет файла)" else - LOCAL_CHECKSUM=$(sha256sum "$LOCAL_SCRIPT_PATH" 2>/dev/null | awk '{print $1}') + LOCAL_CHECKSUM=$(file_sha256 "$LOCAL_SCRIPT_PATH") + local_ver="$(read_ssh_monitor_version "$LOCAL_SCRIPT_PATH")" + fi + REMOTE_CHECKSUM=$(file_sha256 "$actual_script_path") + remote_ver="$(read_ssh_monitor_version "$actual_script_path")" + log_action "сравнение: local=$LOCAL_SCRIPT_PATH ver=$local_ver sha=${LOCAL_CHECKSUM:0:16}…" + log_action "сравнение: remote=$actual_script_path ver=$remote_ver sha=${REMOTE_CHECKSUM:0:16}…" + if [ "$pull_ok" -eq 0 ]; then + log_action "примечание: git pull не удался — remote может быть устаревшим" fi - REMOTE_CHECKSUM=$(sha256sum "$actual_script_path" 2>/dev/null | awk '{print $1}') if [ "$LOCAL_CHECKSUM" != "$REMOTE_CHECKSUM" ]; then - log_message "INFO" "Checksums differ. Updating $LOCAL_SCRIPT_PATH..." + log_action "checksum различается — обновляем $LOCAL_SCRIPT_PATH" if install_ssh_monitor_from "$actual_script_path"; then script_changed=1 - log_message "INFO" "Script updated successfully." + SUMMARY_SCRIPT="обновлён" + SUMMARY_SCRIPT_REASON="${local_ver} → ${remote_ver}, sha изменился" else + SUMMARY_SCRIPT="ошибка копирования" + log_update_summary return 1 fi else - log_message "INFO" "Checksums match. No update needed." + SUMMARY_SCRIPT="без изменений" + SUMMARY_SCRIPT_REASON="sha256 совпадает; версия local=$local_ver remote=$remote_ver" + log_action "ssh-monitor: файлы идентичны, копирование не требуется" fi fi else - log_message "INFO" "No remote script found. No update needed." + SUMMARY_SCRIPT="не найден в клоне" + SUMMARY_SCRIPT_REASON="проверьте структуру репозитория после git pull" + log_action "ERROR: ssh-monitor не найден в клоне $UPDATE_DIR/$SCRIPT_NAME" if [ "$DEPLOY_MODE" -eq 1 ]; then say_warn "ssh-monitor не найден в клоне $UPDATE_DIR/$SCRIPT_NAME" fi @@ -643,11 +775,12 @@ update_script() { script_changed=1 elif [ "$script_changed" -eq 1 ] || [ "${SAC_CLIENT_CHANGED:-0}" -eq 1 ] || [ "${CONFIG_CHANGED:-0}" -eq 1 ]; then restart_ssh_monitor_service + else + log_action "перезапуск сервиса не нужен (ни один файл не изменился)" fi - # Логируем значения переменных скрипта при DEBUG=1 log_script_vars - + log_update_summary return 0 } @@ -661,7 +794,12 @@ if [ "$DEPLOY_MODE" -eq 1 ]; then say_step "Репозиторий и файлы" fi +_updater_self="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || printf '%s' "$0")" +_updater_sha="$(file_sha256 "$_updater_self")" log_message "INFO" "=== Script update started (deploy=$DEPLOY_MODE) ===" +log_action "запуск updater: $_updater_self (sha ${_updater_sha:0:16}…)" +log_action "хост=$(hostname 2>/dev/null || echo '?') user=$(id -un 2>/dev/null) uid=$(id -u 2>/dev/null)" +log_action "пути: LOCAL=$LOCAL_SCRIPT_PATH UPDATE_DIR=$UPDATE_DIR REPO=$REPO_URL" debug_step "Инициализация скрипта обновления" if ! ensure_directories; then @@ -693,11 +831,13 @@ fi if [ $exit_code -eq 0 ]; then log_message "INFO" "=== Script update completed successfully ===" + log_action "завершено успешно (код 0). Итог см. выше или: tail -30 $LOG_FILE" if [ "$DEPLOY_MODE" -eq 1 ]; then printf '\n=== Установка завершена. Отредактируйте %s и перезапустите сервис. ===\n' "$CONFIG_FILE" fi else log_message "INFO" "=== Script update completed with errors (exit code: $exit_code) ===" + log_action "завершено с ошибкой (код $exit_code). См. $LOG_FILE" fi exit $exit_code