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.
This commit is contained in:
2026-05-28 08:13:24 +10:00
parent d179b360f2
commit f3b7c9d41c
2 changed files with 188 additions and 37 deletions
+177 -37
View File
@@ -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