Refactor tool setup: unify cleanup, retries, and validation

Introduces unified helper functions for cleaning up keyrings, stopping services, verifying tool versions, and cleaning legacy installs. Adds a retry mechanism for package installation and a repository preparation function to streamline setup and error handling. Refactors all tool setup and removal logic to use these helpers, reducing code duplication and improving maintainability.
This commit is contained in:
CanbiZ 2025-11-04 13:49:51 +01:00
parent 03bf6dadf1
commit 3f7f39abe2

View File

@ -24,6 +24,147 @@ get_cached_version() {
return 0 return 0
} }
# ------------------------------------------------------------------------------
# Clean up ALL keyring locations for a tool (unified helper)
# Usage: cleanup_tool_keyrings "mariadb" "mysql" "postgresql"
# ------------------------------------------------------------------------------
cleanup_tool_keyrings() {
local tool_patterns=("$@")
for pattern in "${tool_patterns[@]}"; do
rm -f /usr/share/keyrings/${pattern}*.gpg \
/etc/apt/keyrings/${pattern}*.gpg \
/etc/apt/trusted.gpg.d/${pattern}*.gpg 2>/dev/null || true
done
}
# ------------------------------------------------------------------------------
# Stop and disable all service instances matching a pattern
# Usage: stop_all_services "php*-fpm" "mysql" "mariadb"
# ------------------------------------------------------------------------------
stop_all_services() {
local service_patterns=("$@")
for pattern in "${service_patterns[@]}"; do
# Find all matching services
systemctl list-units --type=service --all 2>/dev/null |
grep -oE "${pattern}[^ ]*\.service" |
sort -u |
while read -r service; do
$STD systemctl stop "$service" 2>/dev/null || true
$STD systemctl disable "$service" 2>/dev/null || true
done
done
}
# ------------------------------------------------------------------------------
# Verify installed tool version matches expected version
# Returns: 0 if match, 1 if mismatch (with warning)
# Usage: verify_tool_version "nodejs" "22" "$(node -v | grep -oP '^v\K[0-9]+')"
# ------------------------------------------------------------------------------
verify_tool_version() {
local tool_name="$1"
local expected_version="$2"
local installed_version="$3"
# Extract major version for comparison
local expected_major="${expected_version%%.*}"
local installed_major="${installed_version%%.*}"
if [[ "$installed_major" != "$expected_major" ]]; then
msg_warn "$tool_name version mismatch: expected $expected_version, got $installed_version"
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# Clean up legacy installation methods (nvm, rbenv, rustup, etc.)
# Usage: cleanup_legacy_install "nodejs" -> removes nvm
# ------------------------------------------------------------------------------
cleanup_legacy_install() {
local tool_name="$1"
case "$tool_name" in
nodejs | node)
if [[ -d "$HOME/.nvm" ]]; then
msg_info "Removing legacy nvm installation"
rm -rf "$HOME/.nvm" "$HOME/.npm" "$HOME/.bower" "$HOME/.config/yarn" 2>/dev/null || true
sed -i '/NVM_DIR/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null || true
fi
;;
ruby)
if [[ -d "$HOME/.rbenv" ]]; then
msg_info "Removing legacy rbenv installation"
rm -rf "$HOME/.rbenv" 2>/dev/null || true
sed -i '/rbenv/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null || true
fi
;;
rust)
if [[ -d "$HOME/.cargo" ]] || [[ -d "$HOME/.rustup" ]]; then
msg_info "Removing legacy rustup installation"
rm -rf "$HOME/.cargo" "$HOME/.rustup" 2>/dev/null || true
sed -i '/cargo/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null || true
fi
;;
go | golang)
if [[ -d "$HOME/go" ]]; then
msg_info "Removing legacy Go workspace"
# Keep user code, just remove GOPATH env
sed -i '/GOPATH/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null || true
fi
;;
esac
}
# ------------------------------------------------------------------------------
# Unified repository preparation before setup
# Cleans up old repos, keyrings, and ensures APT is working
# Usage: prepare_repository_setup "mariadb" "mysql"
# ------------------------------------------------------------------------------
prepare_repository_setup() {
local repo_names=("$@")
# Clean up all old repository files
for repo in "${repo_names[@]}"; do
cleanup_old_repo_files "$repo"
done
# Clean up all keyrings
cleanup_tool_keyrings "${repo_names[@]}"
# Ensure APT is in working state
ensure_apt_working || return 1
return 0
}
# ------------------------------------------------------------------------------
# Install packages with retry logic
# Usage: install_packages_with_retry "mysql-server" "mysql-client"
# ------------------------------------------------------------------------------
install_packages_with_retry() {
local packages=("$@")
local max_retries=2
local retry=0
while [[ $retry -le $max_retries ]]; do
if $STD apt install -y "${packages[@]}" 2>/dev/null; then
return 0
fi
retry=$((retry + 1))
if [[ $retry -le $max_retries ]]; then
msg_warn "Package installation failed, retrying ($retry/$max_retries)..."
sleep 2
$STD apt update 2>/dev/null || true
fi
done
return 1
}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Check if tool is already installed and optionally verify exact version # Check if tool is already installed and optionally verify exact version
# Returns: 0 if installed (with optional version match), 1 if not installed # Returns: 0 if installed (with optional version match), 1 if not installed
@ -110,30 +251,21 @@ remove_old_tool_version() {
case "$tool_name" in case "$tool_name" in
mariadb) mariadb)
$STD systemctl stop mariadb >/dev/null 2>&1 || true stop_all_services "mariadb"
$STD apt purge -y 'mariadb*' >/dev/null 2>&1 || true $STD apt purge -y 'mariadb*' >/dev/null 2>&1 || true
# Clean up ALL keyring locations cleanup_tool_keyrings "mariadb"
rm -f /usr/share/keyrings/mariadb*.gpg \
/etc/apt/keyrings/mariadb*.gpg \
/etc/apt/trusted.gpg.d/mariadb*.gpg 2>/dev/null || true
;; ;;
mysql) mysql)
$STD systemctl stop mysql >/dev/null 2>&1 || true stop_all_services "mysql"
$STD apt purge -y 'mysql*' >/dev/null 2>&1 || true $STD apt purge -y 'mysql*' >/dev/null 2>&1 || true
rm -rf /var/lib/mysql 2>/dev/null || true rm -rf /var/lib/mysql 2>/dev/null || true
# Clean up ALL keyring locations cleanup_tool_keyrings "mysql"
rm -f /usr/share/keyrings/mysql*.gpg \
/etc/apt/keyrings/mysql*.gpg \
/etc/apt/trusted.gpg.d/mysql*.gpg 2>/dev/null || true
;; ;;
mongodb) mongodb)
$STD systemctl stop mongod >/dev/null 2>&1 || true stop_all_services "mongod"
$STD apt purge -y 'mongodb*' >/dev/null 2>&1 || true $STD apt purge -y 'mongodb*' >/dev/null 2>&1 || true
rm -rf /var/lib/mongodb 2>/dev/null || true rm -rf /var/lib/mongodb 2>/dev/null || true
# Clean up ALL keyring locations cleanup_tool_keyrings "mongodb"
rm -f /usr/share/keyrings/mongodb*.gpg \
/etc/apt/keyrings/mongodb*.gpg \
/etc/apt/trusted.gpg.d/mongodb*.gpg 2>/dev/null || true
;; ;;
node | nodejs) node | nodejs)
$STD apt purge -y nodejs npm >/dev/null 2>&1 || true $STD apt purge -y nodejs npm >/dev/null 2>&1 || true
@ -143,66 +275,42 @@ remove_old_tool_version() {
npm uninstall -g "$module" >/dev/null 2>&1 || true npm uninstall -g "$module" >/dev/null 2>&1 || true
done done
fi fi
# Clean up nvm installations and npm caches cleanup_legacy_install "nodejs"
rm -rf "$HOME/.nvm" "$HOME/.npm" "$HOME/.bower" "$HOME/.config/yarn" 2>/dev/null || true cleanup_tool_keyrings "nodesource"
sed -i '/NVM_DIR/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null || true
# Clean up ALL keyring locations
rm -f /usr/share/keyrings/nodesource*.gpg \
/etc/apt/keyrings/nodesource*.gpg \
/etc/apt/trusted.gpg.d/nodesource*.gpg 2>/dev/null || true
;; ;;
php) php)
# Stop and disable ALL PHP-FPM versions stop_all_services "php.*-fpm"
for fpm_service in $(systemctl list-units --type=service --all | grep -oE 'php[0-9]+\.[0-9]+-fpm' | sort -u); do
$STD systemctl stop "$fpm_service" >/dev/null 2>&1 || true
$STD systemctl disable "$fpm_service" >/dev/null 2>&1 || true
done
$STD apt purge -y 'php*' >/dev/null 2>&1 || true $STD apt purge -y 'php*' >/dev/null 2>&1 || true
rm -rf /etc/php 2>/dev/null || true rm -rf /etc/php 2>/dev/null || true
# Clean up ALL keyring locations (Sury PHP) cleanup_tool_keyrings "deb.sury.org-php" "php"
rm -f /usr/share/keyrings/deb.sury.org-php.gpg \
/usr/share/keyrings/php*.gpg \
/etc/apt/keyrings/php*.gpg \
/etc/apt/trusted.gpg.d/php*.gpg 2>/dev/null || true
;; ;;
postgresql) postgresql)
$STD systemctl stop postgresql >/dev/null 2>&1 || true stop_all_services "postgresql"
$STD apt purge -y 'postgresql*' >/dev/null 2>&1 || true $STD apt purge -y 'postgresql*' >/dev/null 2>&1 || true
# Keep data directory for safety (can be removed manually if needed) # Keep data directory for safety (can be removed manually if needed)
# rm -rf /var/lib/postgresql 2>/dev/null || true # rm -rf /var/lib/postgresql 2>/dev/null || true
# Clean up ALL keyring locations cleanup_tool_keyrings "postgresql" "pgdg"
rm -f /usr/share/keyrings/postgresql*.gpg \
/usr/share/keyrings/pgdg*.gpg \
/etc/apt/keyrings/postgresql*.gpg \
/etc/apt/keyrings/pgdg*.gpg \
/etc/apt/trusted.gpg.d/postgresql*.gpg \
/etc/apt/trusted.gpg.d/pgdg*.gpg 2>/dev/null || true
;; ;;
java) java)
$STD apt purge -y 'temurin*' 'adoptium*' 'openjdk*' >/dev/null 2>&1 || true $STD apt purge -y 'temurin*' 'adoptium*' 'openjdk*' >/dev/null 2>&1 || true
# Clean up ALL keyring locations (Adoptium) cleanup_tool_keyrings "adoptium"
rm -f /usr/share/keyrings/adoptium*.gpg \
/etc/apt/keyrings/adoptium*.gpg \
/etc/apt/trusted.gpg.d/adoptium*.gpg 2>/dev/null || true
;; ;;
ruby) ruby)
rm -rf "$HOME/.rbenv" 2>/dev/null || true cleanup_legacy_install "ruby"
$STD apt purge -y 'ruby*' >/dev/null 2>&1 || true $STD apt purge -y 'ruby*' >/dev/null 2>&1 || true
;; ;;
rust) rust)
rm -rf "$HOME/.cargo" "$HOME/.rustup" 2>/dev/null || true cleanup_legacy_install "rust"
;; ;;
go | golang) go | golang)
rm -rf /usr/local/go 2>/dev/null || true rm -rf /usr/local/go 2>/dev/null || true
cleanup_legacy_install "golang"
;; ;;
clickhouse) clickhouse)
$STD systemctl stop clickhouse-server >/dev/null 2>&1 || true stop_all_services "clickhouse-server"
$STD apt purge -y 'clickhouse*' >/dev/null 2>&1 || true $STD apt purge -y 'clickhouse*' >/dev/null 2>&1 || true
rm -rf /var/lib/clickhouse 2>/dev/null || true rm -rf /var/lib/clickhouse 2>/dev/null || true
# Clean up ALL keyring locations cleanup_tool_keyrings "clickhouse"
rm -f /usr/share/keyrings/clickhouse*.gpg \
/etc/apt/keyrings/clickhouse*.gpg \
/etc/apt/trusted.gpg.d/clickhouse*.gpg 2>/dev/null || true
;; ;;
esac esac
@ -2563,9 +2671,7 @@ function setup_java() {
# Clean up ALL old Adoptium repo configs and keyrings before setup # Clean up ALL old Adoptium repo configs and keyrings before setup
cleanup_old_repo_files "adoptium" cleanup_old_repo_files "adoptium"
rm -f /usr/share/keyrings/adoptium*.gpg \ cleanup_tool_keyrings "adoptium"
/etc/apt/keyrings/adoptium*.gpg \
/etc/apt/trusted.gpg.d/adoptium*.gpg 2>/dev/null || true
# Add repo if needed # Add repo if needed
if [[ ! -f /etc/apt/sources.list.d/adoptium.sources ]]; then if [[ ! -f /etc/apt/sources.list.d/adoptium.sources ]]; then
@ -2812,14 +2918,11 @@ setup_mariadb() {
# Scenario 3: Fresh install or version change # Scenario 3: Fresh install or version change
msg_info "Setup MariaDB $MARIADB_VERSION" msg_info "Setup MariaDB $MARIADB_VERSION"
# Clean up ALL old MariaDB repo configs and keyrings before setup # Prepare repository (cleanup + validation)
cleanup_old_repo_files "mariadb" prepare_repository_setup "mariadb" || {
rm -f /usr/share/keyrings/mariadb*.gpg \ msg_error "Failed to prepare MariaDB repository"
/etc/apt/keyrings/mariadb*.gpg \ return 1
/etc/apt/trusted.gpg.d/mariadb*.gpg 2>/dev/null || true }
# Ensure APT is working before proceeding
ensure_apt_working || return 1
# Install required dependencies first # Install required dependencies first
local mariadb_deps=() local mariadb_deps=()
@ -2847,19 +2950,20 @@ setup_mariadb() {
echo "mariadb-server-$MARIADB_MAJOR_MINOR mariadb-server/feedback boolean false" | debconf-set-selections echo "mariadb-server-$MARIADB_MAJOR_MINOR mariadb-server/feedback boolean false" | debconf-set-selections
fi fi
# Install packages # Install packages with retry logic
DEBIAN_FRONTEND=noninteractive $STD apt install -y mariadb-server mariadb-client || { export DEBIAN_FRONTEND=noninteractive
if ! install_packages_with_retry "mariadb-server" "mariadb-client"; then
# Fallback: try without specific version # Fallback: try without specific version
msg_warn "Failed to install MariaDB packages from upstream repo, trying distro fallback..." msg_warn "Failed to install MariaDB packages from upstream repo, trying distro fallback..."
cleanup_old_repo_files "mariadb" cleanup_old_repo_files "mariadb"
$STD apt update || { $STD apt update || {
msg_warn "APT update also failed, continuing with cache" msg_warn "APT update also failed, continuing with cache"
} }
DEBIAN_FRONTEND=noninteractive $STD apt install -y mariadb-server mariadb-client || { install_packages_with_retry "mariadb-server" "mariadb-client" || {
msg_error "Failed to install MariaDB packages (both upstream and distro)" msg_error "Failed to install MariaDB packages (both upstream and distro)"
return 1 return 1
} }
} fi
cache_installed_version "mariadb" "$MARIADB_VERSION" cache_installed_version "mariadb" "$MARIADB_VERSION"
msg_ok "Setup MariaDB $MARIADB_VERSION" msg_ok "Setup MariaDB $MARIADB_VERSION"
@ -2934,11 +3038,11 @@ function setup_mongodb() {
cleanup_orphaned_sources cleanup_orphaned_sources
# Clean up ALL old MongoDB repo configs and keyrings before setup # Prepare repository (cleanup + validation)
cleanup_old_repo_files "mongodb" prepare_repository_setup "mongodb" || {
rm -f /usr/share/keyrings/mongodb*.gpg \ msg_error "Failed to prepare MongoDB repository"
/etc/apt/keyrings/mongodb*.gpg \ return 1
/etc/apt/trusted.gpg.d/mongodb*.gpg 2>/dev/null || true }
# Setup repository # Setup repository
manage_tool_repository "mongodb" "$MONGO_VERSION" "$MONGO_BASE_URL" \ manage_tool_repository "mongodb" "$MONGO_VERSION" "$MONGO_BASE_URL" \
@ -2953,8 +3057,8 @@ function setup_mongodb() {
return 1 return 1
} }
# Install MongoDB # Install MongoDB with retry logic
$STD apt install -y mongodb-org || { install_packages_with_retry "mongodb-org" || {
msg_error "Failed to install MongoDB packages" msg_error "Failed to install MongoDB packages"
return 1 return 1
} }
@ -2976,9 +3080,7 @@ function setup_mongodb() {
# Verify MongoDB version # Verify MongoDB version
local INSTALLED_VERSION local INSTALLED_VERSION
INSTALLED_VERSION=$(mongod --version 2>/dev/null | grep -oP 'db version v\K[0-9]+\.[0-9]+' | head -n1 || echo "0.0") INSTALLED_VERSION=$(mongod --version 2>/dev/null | grep -oP 'db version v\K[0-9]+\.[0-9]+' | head -n1 || echo "0.0")
if [[ "${INSTALLED_VERSION%%.*}" != "${MONGO_VERSION%%.*}" ]]; then verify_tool_version "MongoDB" "$MONGO_VERSION" "$INSTALLED_VERSION" || true
msg_warn "MongoDB version mismatch: expected $MONGO_VERSION, got $INSTALLED_VERSION"
fi
cache_installed_version "mongodb" "$MONGO_VERSION" cache_installed_version "mongodb" "$MONGO_VERSION"
msg_ok "Setup MongoDB $MONGO_VERSION" msg_ok "Setup MongoDB $MONGO_VERSION"
@ -3028,11 +3130,11 @@ function setup_mysql() {
msg_info "Setup MySQL $MYSQL_VERSION" msg_info "Setup MySQL $MYSQL_VERSION"
fi fi
# Clean up ALL old MySQL repo configs and keyrings before setup # Prepare repository (cleanup + validation)
cleanup_old_repo_files "mysql" prepare_repository_setup "mysql" || {
rm -f /usr/share/keyrings/mysql*.gpg \ msg_error "Failed to prepare MySQL repository"
/etc/apt/keyrings/mysql*.gpg \ return 1
/etc/apt/trusted.gpg.d/mysql*.gpg 2>/dev/null || true }
# Debian 13+ Fix: MySQL 8.0 incompatible with libaio1t64, use 8.4 LTS # Debian 13+ Fix: MySQL 8.0 incompatible with libaio1t64, use 8.4 LTS
if [[ "$DISTRO_ID" == "debian" && "$DISTRO_CODENAME" =~ ^(trixie|forky|sid)$ ]]; then if [[ "$DISTRO_ID" == "debian" && "$DISTRO_CODENAME" =~ ^(trixie|forky|sid)$ ]]; then
@ -3057,11 +3159,12 @@ EOF
return 1 return 1
} }
if ! $STD apt install -y mysql-community-server mysql-community-client; then # Install with retry logic
if ! install_packages_with_retry "mysql-community-server" "mysql-community-client"; then
msg_warn "MySQL 8.4 LTS installation failed falling back to MariaDB" msg_warn "MySQL 8.4 LTS installation failed falling back to MariaDB"
cleanup_old_repo_files "mysql" cleanup_old_repo_files "mysql"
$STD apt update $STD apt update
$STD apt install -y mariadb-server mariadb-client || { install_packages_with_retry "mariadb-server" "mariadb-client" || {
msg_error "Failed to install database engine (MySQL/MariaDB fallback)" msg_error "Failed to install database engine (MySQL/MariaDB fallback)"
return 1 return 1
} }
@ -3094,18 +3197,18 @@ EOF
ensure_apt_working || return 1 ensure_apt_working || return 1
# Try multiple package names (mysql-server, mysql-community-server, mysql) # Try multiple package names with retry logic
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
local mysql_install_success=false local mysql_install_success=false
if apt-cache search "^mysql-server$" 2>/dev/null | grep -q . && if apt-cache search "^mysql-server$" 2>/dev/null | grep -q . &&
$STD apt install -y mysql-server mysql-client 2>/dev/null; then install_packages_with_retry "mysql-server" "mysql-client"; then
mysql_install_success=true mysql_install_success=true
elif apt-cache search "^mysql-community-server$" 2>/dev/null | grep -q . && elif apt-cache search "^mysql-community-server$" 2>/dev/null | grep -q . &&
$STD apt install -y mysql-community-server mysql-community-client 2>/dev/null; then install_packages_with_retry "mysql-community-server" "mysql-community-client"; then
mysql_install_success=true mysql_install_success=true
elif apt-cache search "^mysql$" 2>/dev/null | grep -q . && elif apt-cache search "^mysql$" 2>/dev/null | grep -q . &&
$STD apt install -y mysql 2>/dev/null; then install_packages_with_retry "mysql"; then
mysql_install_success=true mysql_install_success=true
fi fi
@ -3176,20 +3279,16 @@ function setup_nodejs() {
msg_info "Setup Node.js $NODE_VERSION" msg_info "Setup Node.js $NODE_VERSION"
fi fi
# Clean up any legacy nvm installations # Clean up legacy installations (nvm, etc.)
if [[ -d "$HOME/.nvm" ]]; then cleanup_legacy_install "nodejs"
msg_info "Removing legacy nvm installation"
rm -rf "$HOME/.nvm" "$HOME/.npm" "$HOME/.bower" "$HOME/.config/yarn" 2>/dev/null || true
sed -i '/NVM_DIR/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null || true
fi
ensure_dependencies curl ca-certificates gnupg ensure_dependencies curl ca-certificates gnupg
# Clean up ALL old NodeSource repository configurations to avoid conflicts # Prepare repository (cleanup + validation)
rm -f /etc/apt/sources.list.d/nodesource.list \ prepare_repository_setup "nodesource" || {
/etc/apt/sources.list.d/nodesource.sources \ msg_error "Failed to prepare Node.js repository"
/usr/share/keyrings/nodesource.gpg \ return 1
/etc/apt/keyrings/nodesource.gpg 2>/dev/null || true }
# Setup repository # Setup repository
manage_tool_repository "nodejs" "$NODE_VERSION" "https://deb.nodesource.com/node_${NODE_VERSION}.x" "https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key" || { manage_tool_repository "nodejs" "$NODE_VERSION" "https://deb.nodesource.com/node_${NODE_VERSION}.x" "https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key" || {
@ -3200,20 +3299,11 @@ function setup_nodejs() {
# Wait for repo to settle # Wait for repo to settle
sleep 2 sleep 2
# Install Node.js # Install Node.js with retry logic
if ! $STD apt update; then install_packages_with_retry "nodejs" || {
msg_warn "APT update failed retrying in 5s"
sleep 5
if ! $STD apt update; then
msg_error "Failed to update APT repositories after adding NodeSource"
return 1
fi
fi
if ! $STD apt install -y nodejs; then
msg_error "Failed to install Node.js ${NODE_VERSION} from NodeSource" msg_error "Failed to install Node.js ${NODE_VERSION} from NodeSource"
return 1 return 1
fi }
# Verify Node.js was installed correctly # Verify Node.js was installed correctly
if ! command -v node >/dev/null 2>&1; then if ! command -v node >/dev/null 2>&1; then
@ -3223,10 +3313,7 @@ function setup_nodejs() {
local INSTALLED_NODE_VERSION local INSTALLED_NODE_VERSION
INSTALLED_NODE_VERSION=$(node -v 2>/dev/null | grep -oP '^v\K[0-9]+' || echo "0") INSTALLED_NODE_VERSION=$(node -v 2>/dev/null | grep -oP '^v\K[0-9]+' || echo "0")
if [[ "$INSTALLED_NODE_VERSION" != "$NODE_VERSION" ]]; then verify_tool_version "Node.js" "$NODE_VERSION" "$INSTALLED_NODE_VERSION" || true
msg_error "Node.js version mismatch: expected $NODE_VERSION, got $INSTALLED_NODE_VERSION"
return 1
fi
# Update to latest npm (with version check to avoid incompatibility) # Update to latest npm (with version check to avoid incompatibility)
local NPM_VERSION local NPM_VERSION
@ -3380,22 +3467,18 @@ function setup_php() {
# Scenario 2: Different version installed - clean upgrade # Scenario 2: Different version installed - clean upgrade
if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" != "$PHP_VERSION" ]]; then if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
msg_info "Upgrade PHP from $CURRENT_PHP to $PHP_VERSION" msg_info "Upgrade PHP from $CURRENT_PHP to $PHP_VERSION"
# Stop and disable ALL PHP-FPM versions (not just current one) # Stop and disable ALL PHP-FPM versions
for fpm_service in $(systemctl list-units --type=service --all 2>/dev/null | grep -oE 'php[0-9]+\.[0-9]+-fpm' | sort -u); do stop_all_services "php.*-fpm"
$STD systemctl stop "$fpm_service" >/dev/null 2>&1 || true
$STD systemctl disable "$fpm_service" >/dev/null 2>&1 || true
done
remove_old_tool_version "php" remove_old_tool_version "php"
else else
msg_info "Setup PHP $PHP_VERSION" msg_info "Setup PHP $PHP_VERSION"
fi fi
# Clean up ALL old PHP repo configs and keyrings before setup # Prepare repository (cleanup + validation)
cleanup_old_repo_files "php" prepare_repository_setup "php" "deb.sury.org-php" || {
rm -f /usr/share/keyrings/deb.sury.org-php.gpg \ msg_error "Failed to prepare PHP repository"
/usr/share/keyrings/php*.gpg \ return 1
/etc/apt/keyrings/php*.gpg \ }
/etc/apt/trusted.gpg.d/php*.gpg 2>/dev/null || true
# Setup Sury repository # Setup Sury repository
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || { manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
@ -3421,15 +3504,15 @@ function setup_php() {
# install apache2 with PHP support if requested # install apache2 with PHP support if requested
if [[ "$PHP_APACHE" == "YES" ]]; then if [[ "$PHP_APACHE" == "YES" ]]; then
if ! dpkg -l 2>/dev/null | grep -q "libapache2-mod-php${PHP_VERSION}"; then if ! dpkg -l 2>/dev/null | grep -q "libapache2-mod-php${PHP_VERSION}"; then
$STD apt install -y apache2 libapache2-mod-php${PHP_VERSION} || { install_packages_with_retry "apache2" "libapache2-mod-php${PHP_VERSION}" || {
msg_error "Failed to install Apache with PHP module" msg_error "Failed to install Apache with PHP module"
return 1 return 1
} }
fi fi
fi fi
# Install PHP packages # Install PHP packages with retry logic
$STD apt install -y $MODULE_LIST || { install_packages_with_retry $MODULE_LIST || {
msg_error "Failed to install PHP packages" msg_error "Failed to install PHP packages"
return 1 return 1
} }
@ -3529,16 +3612,10 @@ function setup_postgresql() {
fi fi
# Scenario 3: Fresh install or after removal - setup repo and install # Scenario 3: Fresh install or after removal - setup repo and install
cleanup_old_repo_files "pgdg" prepare_repository_setup "pgdg" "postgresql" || {
cleanup_old_repo_files "postgresql" msg_error "Failed to prepare PostgreSQL repository"
return 1
# Clean up ALL old PostgreSQL repo configs and keyrings before setup }
rm -f /usr/share/keyrings/postgresql*.gpg \
/usr/share/keyrings/pgdg*.gpg \
/etc/apt/keyrings/postgresql*.gpg \
/etc/apt/keyrings/pgdg*.gpg \
/etc/apt/trusted.gpg.d/postgresql*.gpg \
/etc/apt/trusted.gpg.d/pgdg*.gpg 2>/dev/null || true
local SUITE local SUITE
case "$DISTRO_CODENAME" in case "$DISTRO_CODENAME" in
@ -3573,11 +3650,11 @@ function setup_postgresql() {
$STD apt install -y ssl-cert 2>/dev/null || true $STD apt install -y ssl-cert 2>/dev/null || true
fi fi
# Try multiple PostgreSQL package patterns # Try multiple PostgreSQL package patterns with retry logic
local pg_install_success=false local pg_install_success=false
if apt-cache search "^postgresql-${PG_VERSION}$" 2>/dev/null | grep -q . && if apt-cache search "^postgresql-${PG_VERSION}$" 2>/dev/null | grep -q . &&
$STD apt install -y "postgresql-${PG_VERSION}" "postgresql-client-${PG_VERSION}" 2>/dev/null; then install_packages_with_retry "postgresql-${PG_VERSION}" "postgresql-client-${PG_VERSION}"; then
pg_install_success=true pg_install_success=true
fi fi
@ -3888,7 +3965,7 @@ function setup_clickhouse() {
# Scenario 2: Different version - clean upgrade # Scenario 2: Different version - clean upgrade
if [[ -n "$CURRENT_VERSION" && "$CURRENT_VERSION" != "$CLICKHOUSE_VERSION" ]]; then if [[ -n "$CURRENT_VERSION" && "$CURRENT_VERSION" != "$CLICKHOUSE_VERSION" ]]; then
msg_info "Upgrade ClickHouse from $CURRENT_VERSION to $CLICKHOUSE_VERSION" msg_info "Upgrade ClickHouse from $CURRENT_VERSION to $CLICKHOUSE_VERSION"
$STD systemctl stop clickhouse-server >/dev/null 2>&1 || true stop_all_services "clickhouse-server"
remove_old_tool_version "clickhouse" remove_old_tool_version "clickhouse"
else else
msg_info "Setup ClickHouse $CLICKHOUSE_VERSION" msg_info "Setup ClickHouse $CLICKHOUSE_VERSION"
@ -3896,11 +3973,11 @@ function setup_clickhouse() {
ensure_dependencies apt-transport-https ca-certificates dirmngr gnupg ensure_dependencies apt-transport-https ca-certificates dirmngr gnupg
# Clean up ALL old ClickHouse repo configs and keyrings before setup # Prepare repository (cleanup + validation)
cleanup_old_repo_files "clickhouse" prepare_repository_setup "clickhouse" || {
rm -f /usr/share/keyrings/clickhouse*.gpg \ msg_error "Failed to prepare ClickHouse repository"
/etc/apt/keyrings/clickhouse*.gpg \ return 1
/etc/apt/trusted.gpg.d/clickhouse*.gpg 2>/dev/null || true }
# Setup repository (ClickHouse uses 'stable' suite) # Setup repository (ClickHouse uses 'stable' suite)
setup_deb822_repo \ setup_deb822_repo \
@ -3911,14 +3988,14 @@ function setup_clickhouse() {
"main" \ "main" \
"amd64 arm64" "amd64 arm64"
# Install packages # Install packages with retry logic
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
$STD apt update || { $STD apt update || {
msg_error "APT update failed for ClickHouse repository" msg_error "APT update failed for ClickHouse repository"
return 1 return 1
} }
$STD apt install -y clickhouse-server clickhouse-client || { install_packages_with_retry "clickhouse-server" "clickhouse-client" || {
msg_error "Failed to install ClickHouse packages" msg_error "Failed to install ClickHouse packages"
return 1 return 1
} }