#!/bin/bash # === Конфигурация скрипта === UPDATE_DIR="/opt/scripts/update" SCRIPT_NAME="ssh-monitor" REPO_URL="https://git.kalinamall.ru/PapaTramp/ssh-monitor.git" LOCAL_SCRIPT_PATH="/usr/local/bin/ssh-monitor" LOG_FILE="/var/log/update_script.log" # Режим отладки: 1 = включён, 0 = выключен DEBUG=0 # === Список переменных, объявленных в скрипте (для логирования при DEBUG=1) === SCRIPT_VARS=("UPDATE_DIR" "SCRIPT_NAME" "REPO_URL" "LOCAL_SCRIPT_PATH" "LOG_FILE" "DEBUG" "REMOTE_SCRIPT_PATH" "LOCAL_CHECKSUM" "REMOTE_CHECKSUM") # === Функции === # Основная функция логирования log_message() { local level="$1" local message="$2" local timestamp timestamp="$(date '+%Y-%m-%d %H:%M:%S')" # Создаём лог-файл и директорию при необходимости if [ ! -f "$LOG_FILE" ]; then mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null touch "$LOG_FILE" 2>/dev/null fi if [ "$level" = "INFO" ]; then echo "$timestamp INFO: $message" >> "$LOG_FILE" elif [ "$level" = "DEBUG" ] && [ "$DEBUG" -eq 1 ]; then echo "$timestamp DEBUG: $message" >> "$LOG_FILE" elif [ "$level" = "ERROR" ]; then echo "$timestamp ERROR: $message" >> "$LOG_FILE" fi } # Функция для логирования шагов с комментариями (работает только при DEBUG=1) debug_step() { if [ "$DEBUG" -eq 1 ]; then log_message "DEBUG" "# $1" fi } # Функция для логирования только объявленных в скрипте переменных log_script_vars() { if [ "$DEBUG" -eq 1 ]; then log_message "DEBUG" "=== Значения переменных скрипта ===" for var_name in "${SCRIPT_VARS[@]}"; do local var_value="${!var_name}" log_message "DEBUG" "$var_name='$var_value'" done log_message "DEBUG" "=== Конец списка переменных ===" fi } # === КРИТИЧЕСКАЯ ФУНКЦИЯ: Проверка и установка ipset === ensure_ipset_installed() { debug_step "Проверяем наличие ipset в системе" # Проверяем, установлен ли ipset if ! command -v ipset &>/dev/null; then log_message "INFO" "ipset not found. Attempting silent installation..." debug_step "ipset не обнаружен, начинаем установку в silent режиме" # Определяем пакетный менеджер и устанавливаем ipset if command -v apt-get &>/dev/null || command -v apt &>/dev/null; then debug_step "Обнаружен Debian/Ubuntu, используем apt" log_message "INFO" "Detected apt package manager, installing ipset..." # Тихая установка через apt if apt-get update -qq >/dev/null 2>&1 && apt-get install -y -qq ipset >/dev/null 2>&1; then log_message "INFO" "ipset installed successfully via apt" debug_step "ipset успешно установлен через apt" else log_message "ERROR" "Failed to install ipset via apt" log_message "ERROR" "Работа обновленного скрипта невозможна без установленного ipset" debug_step "КРИТИЧЕСКАЯ ОШИБКА: Не удалось установить ipset через apt" return 1 fi elif command -v yum &>/dev/null; then debug_step "Обнаружен RHEL/CentOS, используем yum" log_message "INFO" "Detected yum package manager, installing ipset..." if yum install -y -q ipset >/dev/null 2>&1; then log_message "INFO" "ipset installed successfully via yum" debug_step "ipset успешно установлен через yum" else log_message "ERROR" "Failed to install ipset via yum" log_message "ERROR" "Работа обновленного скрипта невозможна без установленного ipset" debug_step "КРИТИЧЕСКАЯ ОШИБКА: Не удалось установить ipset через yum" return 1 fi elif command -v dnf &>/dev/null; then debug_step "Обнаружен Fedora/RHEL 8+, используем dnf" log_message "INFO" "Detected dnf package manager, installing ipset..." if dnf install -y -q ipset >/dev/null 2>&1; then log_message "INFO" "ipset installed successfully via dnf" debug_step "ipset успешно установлен через dnf" else log_message "ERROR" "Failed to install ipset via dnf" log_message "ERROR" "Работа обновленного скрипта невозможна без установленного ipset" debug_step "КРИТИЧЕСКАЯ ОШИБКА: Не удалось установить ipset через dnf" return 1 fi elif command -v pacman &>/dev/null; then debug_step "Обнаружен Arch Linux, используем pacman" log_message "INFO" "Detected pacman package manager, installing ipset..." if pacman -S --noconfirm --quiet ipset >/dev/null 2>&1; then log_message "INFO" "ipset installed successfully via pacman" debug_step "ipset успешно установлен через pacman" else log_message "ERROR" "Failed to install ipset via pacman" log_message "ERROR" "Работа обновленного скрипта невозможна без установленного ipset" debug_step "КРИТИЧЕСКАЯ ОШИБКА: Не удалось установить ipset через pacman" return 1 fi elif command -v zypper &>/dev/null; then debug_step "Обнаружен openSUSE, используем zypper" log_message "INFO" "Detected zypper package manager, installing ipset..." if zypper --quiet --non-interactive install ipset >/dev/null 2>&1; then log_message "INFO" "ipset installed successfully via zypper" debug_step "ipset успешно установлен через zypper" else log_message "ERROR" "Failed to install ipset via zypper" log_message "ERROR" "Работа обновленного скрипта невозможна без установленного ipset" debug_step "КРИТИЧЕСКАЯ ОШИБКА: Не удалось установить ipset через zypper" return 1 fi else log_message "ERROR" "Unsupported package manager. Cannot install ipset" log_message "ERROR" "Работа обновленного скрипта невозможна без установленного ipset" debug_step "КРИТИЧЕСКАЯ ОШИБКА: Пакетный менеджер не распознан" return 1 fi # Проверяем, что ipset действительно установился if ! command -v ipset &>/dev/null; then log_message "ERROR" "ipset installation verification failed" log_message "ERROR" "Работа обновленного скрипта невозможна без установленного ipset" debug_step "КРИТИЧЕСКАЯ ОШИБКА: ipset не обнаружен после установки" return 1 fi else debug_step "ipset уже установлен в системе" log_message "INFO" "ipset is already installed" # Проверяем версию ipset (информационно) if [ "$DEBUG" -eq 1 ]; then local ipset_version=$(ipset --version 2>&1) log_message "DEBUG" "ipset version: $ipset_version" fi fi log_message "INFO" "ipset check/installation completed successfully" return 0 } # === Гарантированное создание директорий === ensure_directories() { debug_step "Проверяем и создаём необходимые директории" # Создаём UPDATE_DIR если не существует if [ ! -d "$UPDATE_DIR" ]; then log_message "INFO" "Creating directory: $UPDATE_DIR" debug_step "Директория $UPDATE_DIR не существует, создаём" if mkdir -p "$UPDATE_DIR" 2>/dev/null; then log_message "INFO" "Directory created successfully" else log_message "INFO" "ERROR: Cannot create directory $UPDATE_DIR" return 1 fi else debug_step "Директория $UPDATE_DIR уже существует" fi # Проверяем права на запись if [ ! -w "$UPDATE_DIR" ]; then log_message "INFO" "WARNING: Directory $UPDATE_DIR is not writable" debug_step "ПРЕДУПРЕЖДЕНИЕ: Нет прав на запись в $UPDATE_DIR" return 1 fi return 0 } # Функция для обновления скрипта update_script() { log_message "INFO" "Starting script update..." debug_step "Запуск функции обновления скрипта" # Гарантируем наличие директории debug_step "Гарантируем наличие директории для работы" if ! ensure_directories; then return 1 fi # Переходим в директорию для клона репозитория debug_step "Переходим в директорию для клона репозитория: $UPDATE_DIR" if ! cd "$UPDATE_DIR" 2>/dev/null; then log_message "INFO" "ERROR: Cannot cd to $UPDATE_DIR" return 1 fi # Клонируем или обновляем репозиторий debug_step "Проверяем наличие репозитория и обновляем/клонируем" if [ -d "$SCRIPT_NAME" ]; then log_message "INFO" "Repository exists, pulling updates..." 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..." fi else log_message "INFO" "Cloning repository from $REPO_URL" 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" return 1 fi fi # Формируем путь к скрипту в репозитории (основной и альтернативный) REMOTE_SCRIPT_PATH="$UPDATE_DIR/$SCRIPT_NAME/src/branch/main/$SCRIPT_NAME" ALT_REMOTE_PATH="$UPDATE_DIR/$SCRIPT_NAME/$SCRIPT_NAME" debug_step "Основной путь к скрипту: $REMOTE_SCRIPT_PATH" debug_step "Альтернативный путь к скрипту: $ALT_REMOTE_PATH" # Определяем реальный путь к скрипту local actual_script_path="" if [ -f "$REMOTE_SCRIPT_PATH" ]; then actual_script_path="$REMOTE_SCRIPT_PATH" debug_step "Скрипт найден по основному пути" elif [ -f "$ALT_REMOTE_PATH" ]; then actual_script_path="$ALT_REMOTE_PATH" log_message "INFO" "Script found at alternative path" debug_step "Скрипт найден по альтернативному пути" fi # Проверяем наличие файла скрипта в репозитории if [ -n "$actual_script_path" ] && [ -f "$actual_script_path" ]; then log_message "INFO" "Remote script found. Comparing checksums..." debug_step "Проверяем наличие файла скрипта в репозитории" # Проверяем существование локального скрипта if [ ! -f "$LOCAL_SCRIPT_PATH" ]; then log_message "INFO" "Local script not found. Will install new one." LOCAL_CHECKSUM="" debug_step "Локальный скрипт отсутствует, будет установлен новый" else debug_step "Вычисляем контрольную сумму локального скрипта" LOCAL_CHECKSUM=$(sha256sum "$LOCAL_SCRIPT_PATH" 2>/dev/null | awk '{print $1}') fi debug_step "Вычисляем контрольную сумму удалённого скрипта" REMOTE_CHECKSUM=$(sha256sum "$actual_script_path" 2>/dev/null | awk '{print $1}') # Сравниваем контрольные суммы debug_step "Сравниваем контрольные суммы" if [ "$LOCAL_CHECKSUM" != "$REMOTE_CHECKSUM" ]; then log_message "INFO" "Checksums differ. Updating $LOCAL_SCRIPT_PATH..." debug_step "Контрольные суммы различаются, начинаем обновление" # Создаем бекап текущего скрипта если он существует if [ -f "$LOCAL_SCRIPT_PATH" ]; then debug_step "Создаем резервную копию текущего скрипта" cp "$LOCAL_SCRIPT_PATH" "${LOCAL_SCRIPT_PATH}.backup.$(date +%Y%m%d_%H%M%S)" 2>/dev/null fi debug_step "Копируем новый скрипт в $LOCAL_SCRIPT_PATH" if ! cp "$actual_script_path" "$LOCAL_SCRIPT_PATH"; then log_message "INFO" "ERROR: Failed to copy script" return 1 fi debug_step "Делаем скрипт исполняемым" chmod +x "$LOCAL_SCRIPT_PATH" log_message "INFO" "Script updated successfully." debug_step "Скрипт успешно обновлен" # Перезапускаем сервис 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." debug_step "Сервис успешно перезапущен" else log_message "INFO" "WARNING: Failed to restart service (may not be running)" debug_step "ПРЕДУПРЕЖДЕНИЕ: Не удалось перезапустить сервис" fi else log_message "INFO" "systemctl not found, service not restarted" debug_step "systemctl не найден, сервис не перезапущен" fi else log_message "INFO" "Checksums match. No update needed." debug_step "Контрольные суммы совпадают, обновление не требуется" fi else log_message "INFO" "No remote script found. No update needed." debug_step "Удаленный скрипт не найден ни по одному из путей" # Информация для отладки if [ "$DEBUG" -eq 1 ]; then debug_step "Содержимое директории репозитория:" if [ -d "$UPDATE_DIR/$SCRIPT_NAME" ]; then find "$UPDATE_DIR/$SCRIPT_NAME" -type f -name "$SCRIPT_NAME" 2>/dev/null | while read -r found_file; do log_message "DEBUG" "Найден файл: $found_file" done fi fi fi # Логируем значения переменных скрипта при DEBUG=1 log_script_vars return 0 } # === Основной блок выполнения === log_message "INFO" "=== Script update started ===" debug_step "Инициализация скрипта обновления" # 1. Гарантируем создание необходимых директорий if ! ensure_directories; then log_message "INFO" "ERROR: Failed to ensure directories. Exiting." exit 1 fi # 2. КРИТИЧЕСКИ ВАЖНО: Проверяем и устанавливаем ipset debug_step "Начинаем проверку и установку ipset (КРИТИЧЕСКИЙ ШАГ)" if ! ensure_ipset_installed; then log_message "ERROR" "CRITICAL: ipset installation or verification failed" log_message "ERROR" "Работа обновленного скрипта невозможна без установленного ipset" echo "ERROR: Работа обновленного скрипта невозможна без установленного ipset" >&2 exit 1 fi # 3. Выполняем функцию обновления update_script exit_code=$? if [ $exit_code -eq 0 ]; then log_message "INFO" "=== Script update completed successfully ===" debug_step "Скрипт успешно завершил работу" else log_message "INFO" "=== Script update completed with errors (exit code: $exit_code) ===" debug_step "Скрипт завершил работу с ошибками" fi # Выход с кодом завершения exit $exit_code