From eb5175ccab12543eb74cdf90a794e0769316aeff Mon Sep 17 00:00:00 2001 From: anten-ka Date: Fri, 10 Apr 2026 20:01:20 +0300 Subject: [PATCH] v2.4.6: universal apt_lock_wait helper (fix nginx install on fresh VPS) - lib/common.sh: add apt_lock_wait + apt_install + apt_update helpers * waits up to 300s for dpkg lock held by unattended-upgrades * uses DPkg::Lock::Timeout=120 native flag * captures stderr to show real error if install fails - lib/website.sh: install_nginx/install_certbot use apt_install (fixes "Could not get lock /var/lib/dpkg/lock-frontend" during Pro setup) - install.sh: bot_install uses apt_install (removes duplicated lock logic) - lib/common.sh: ensure_deps uses apt_update + apt_install --- gotelegram-bot/bot.py | 2 +- install.sh | 46 +++++++----------------------- lib/common.sh | 66 +++++++++++++++++++++++++++++++++++++++---- lib/website.sh | 12 ++++---- 4 files changed, 77 insertions(+), 49 deletions(-) mode change 100644 => 100755 install.sh mode change 100644 => 100755 lib/common.sh diff --git a/gotelegram-bot/bot.py b/gotelegram-bot/bot.py index d479181..ca7138e 100644 --- a/gotelegram-bot/bot.py +++ b/gotelegram-bot/bot.py @@ -100,7 +100,7 @@ logger = logging.getLogger(__name__) # CONFIGURATION # ============================================================================ -GOTELEGRAM_VERSION = "2.4.5" +GOTELEGRAM_VERSION = "2.4.6" GOTELEGRAM_CONFIG = "/opt/gotelegram/config.json" TELEMT_CONFIG = "/etc/telemt/config.toml" TELEMT_SERVICE = "telemt" diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 9bff3e0..e92e0ff --- a/install.sh +++ b/install.sh @@ -762,42 +762,22 @@ bot_install() { if [ "$need_py" = "1" ]; then log_info "$(t bot_install_python)" if command -v apt-get &>/dev/null; then - # Wait for dpkg lock (unattended-upgrades often holds it on fresh VPS) - local lock_waited=0 - while fuser /var/lib/dpkg/lock-frontend &>/dev/null \ - || fuser /var/lib/dpkg/lock &>/dev/null \ - || fuser /var/lib/apt/lists/lock &>/dev/null; do - if [ $lock_waited -eq 0 ]; then - log_warning "apt/dpkg locked by another process (likely unattended-upgrades), waiting up to 300s..." - fi - sleep 3 - lock_waited=$((lock_waited + 3)) - if [ $lock_waited -ge 300 ]; then - log_error "apt lock not released after 300s. Kill unattended-upgrades and retry: systemctl stop unattended-upgrades; pkill -9 unattended-upgr" - return 1 - fi - done - [ $lock_waited -gt 0 ] && log_success "apt lock released (waited ${lock_waited}s)" - - # Detect Python version for versioned venv package (Debian 12 / Ubuntu 24.04 need python3.12-venv etc.) + # Detect Python version for versioned venv package (Debian 12 / Ubuntu 24.04 need python3.12-venv) local py_ver="" if command -v python3 &>/dev/null; then py_ver=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null) fi - # apt's native lock timeout as extra safety - local APT_OPTS="-o DPkg::Lock::Timeout=120" - - apt-get $APT_OPTS update -qq || log_warning "apt update had errors (continuing)" + apt_update # Build package list with versioned venv fallback - local pkg_list="python3 python3-venv python3-pip" - [ -n "$py_ver" ] && pkg_list="$pkg_list python${py_ver}-venv" - # python3-full is optional (not on all distros); try it first, then without - if ! apt-get $APT_OPTS install -y $pkg_list python3-full; then + local pkg_list=(python3 python3-venv python3-pip) + [ -n "$py_ver" ] && pkg_list+=("python${py_ver}-venv") + # python3-full optional + if ! apt_install "${pkg_list[@]}" python3-full; then log_warning "python3-full unavailable, installing core packages only..." - apt-get $APT_OPTS install -y $pkg_list || { - log_error "Failed to install Python packages. Run manually: apt install $pkg_list" + apt_install "${pkg_list[@]}" || { + log_error "Failed to install Python packages. Run manually: apt install ${pkg_list[*]}" return 1 } fi @@ -845,17 +825,11 @@ bot_install() { cat /tmp/venv_err >&2 2>/dev/null # Try to fix by installing versioned python3.X-venv package if command -v apt-get &>/dev/null; then - # Wait for lock again (unattended-upgrades may have restarted) - local lock_waited=0 - while fuser /var/lib/dpkg/lock-frontend &>/dev/null; do - sleep 3 - lock_waited=$((lock_waited + 3)) - [ $lock_waited -ge 180 ] && break - done local py_ver py_ver=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null) log_info "reinstalling python${py_ver}-venv..." - apt-get -o DPkg::Lock::Timeout=120 install -y python3-venv python3-pip "python${py_ver}-venv" python3-full 2>&1 | tail -n 10 >&2 || true + apt_install python3-venv python3-pip "python${py_ver}-venv" python3-full || \ + apt_install python3-venv python3-pip "python${py_ver}-venv" || true rm -rf "$BOT_DIR/venv" python3 -m venv "$BOT_DIR/venv" || { log_error "venv still broken, aborting. Manual fix: apt install python${py_ver}-venv python3-pip"; return 1; } else diff --git a/lib/common.sh b/lib/common.sh old mode 100644 new mode 100755 index 72398d1..b5291c8 --- a/lib/common.sh +++ b/lib/common.sh @@ -3,7 +3,7 @@ # Colors, logging, spinner, system helpers, v1 compat, i18n-aware # ── Version ─────────────────────────────────────────────────────────────────── -GOTELEGRAM_VERSION="2.4.5" +GOTELEGRAM_VERSION="2.4.6" GOTELEGRAM_NAME="GoTelegram" # ── Пути ────────────────────────────────────────────────────────────────────── @@ -240,13 +240,68 @@ get_pkg_manager() { install_pkg() { local pkg="$1" case "$(get_pkg_manager)" in - apt) apt-get install -y -qq "$pkg" ;; + apt) apt_install "$pkg" ;; dnf) dnf install -y -q "$pkg" ;; yum) yum install -y -q "$pkg" ;; *) log_error "$(_t_or err_bad_pkg_mgr 'Unknown package manager')"; return 1 ;; esac } +# ── apt lock wait + install ───────────────────────────────────────────────── +# На свежих Ubuntu/Debian unattended-upgrades часто держит dpkg lock на старте +# → любой apt-get install падает с "Could not get lock /var/lib/dpkg/lock-frontend". +# Эти функции ждут освобождения лока до 300с, потом запускают apt с нативным +# таймаутом DPkg::Lock::Timeout. Использовать везде, где раньше был +# "apt-get install ...". +apt_lock_wait() { + local max_wait="${1:-300}" + local waited=0 + local warned=0 + while fuser /var/lib/dpkg/lock-frontend &>/dev/null \ + || fuser /var/lib/dpkg/lock &>/dev/null \ + || fuser /var/lib/apt/lists/lock &>/dev/null \ + || pgrep -f '^/usr/bin/unattended-upgrade' &>/dev/null; do + if [ "$warned" = "0" ]; then + log_warning "apt/dpkg locked by unattended-upgrades, waiting up to ${max_wait}s..." + warned=1 + fi + sleep 3 + waited=$((waited + 3)) + if [ "$waited" -ge "$max_wait" ]; then + log_error "apt lock not released after ${max_wait}s" + log_dim "Manual fix: systemctl stop unattended-upgrades && killall -9 unattended-upgr 2>/dev/null; dpkg --configure -a" + return 1 + fi + done + [ "$warned" = "1" ] && log_success "apt lock released (waited ${waited}s)" + return 0 +} + +# apt_install [pkg2 ...] — ждёт lock + ставит пакеты + показывает ошибку +apt_install() { + [ $# -eq 0 ] && return 0 + apt_lock_wait || return 1 + export DEBIAN_FRONTEND=noninteractive + local opts="-o DPkg::Lock::Timeout=120" + local err_file; err_file=$(mktemp 2>/dev/null || echo /tmp/apt_err.$$) + if ! apt-get $opts install -y -qq "$@" 2>"$err_file"; then + log_error "apt-get install failed: $*" + [ -s "$err_file" ] && tail -n 5 "$err_file" | sed 's/^/ /' >&2 + rm -f "$err_file" + return 1 + fi + rm -f "$err_file" + return 0 +} + +# apt_update — тихий update с ожиданием лока +apt_update() { + apt_lock_wait || return 1 + export DEBIAN_FRONTEND=noninteractive + apt-get -o DPkg::Lock::Timeout=120 update -qq 2>/dev/null || true + return 0 +} + # ── Зависимости GoTelegram ────────────────────────────────────────────────── # Полный список внешних команд, которые скрипт использует. Для каждой команды # указан пакет на apt и dnf/yum (имена различаются: например dig = dnsutils на @@ -344,9 +399,8 @@ ensure_deps() { case "$pkg_mgr" in apt) - export DEBIAN_FRONTEND=noninteractive - apt-get update -qq 2>/dev/null - apt-get install -y -qq "${uniq_pkgs[@]}" 2>/dev/null + apt_update + apt_install "${uniq_pkgs[@]}" || true ;; dnf) dnf install -y -q "${uniq_pkgs[@]}" 2>/dev/null ;; yum) yum install -y -q "${uniq_pkgs[@]}" 2>/dev/null ;; @@ -358,7 +412,7 @@ ensure_deps() { # Фолбэки для xxd: на некоторых системах нужен vim-common вместо xxd if ! command -v xxd &>/dev/null && [ "$pkg_mgr" = "apt" ]; then - apt-get install -y -qq vim-common 2>/dev/null + apt_install vim-common || true fi # Повторная проверка критических команд diff --git a/lib/website.sh b/lib/website.sh index 68e5c8d..9f01504 100755 --- a/lib/website.sh +++ b/lib/website.sh @@ -9,9 +9,9 @@ install_nginx() { fi log_info "Установка nginx..." case "$(get_pkg_manager)" in - apt) apt-get update -qq && apt-get install -y -qq nginx ;; - dnf) dnf install -y -q nginx ;; - yum) yum install -y -q nginx ;; + apt) apt_update && apt_install nginx || return 1 ;; + dnf) dnf install -y -q nginx || return 1 ;; + yum) yum install -y -q nginx || return 1 ;; esac systemctl enable nginx 2>/dev/null } @@ -24,9 +24,9 @@ install_certbot() { fi log_info "Установка certbot..." case "$(get_pkg_manager)" in - apt) apt-get install -y -qq certbot python3-certbot-nginx ;; - dnf) dnf install -y -q certbot python3-certbot-nginx ;; - yum) yum install -y -q certbot python3-certbot-nginx ;; + apt) apt_install certbot python3-certbot-nginx || return 1 ;; + dnf) dnf install -y -q certbot python3-certbot-nginx || return 1 ;; + yum) yum install -y -q certbot python3-certbot-nginx || return 1 ;; esac }