#!/bin/bash set -euo pipefail # Upgrade alternatywnej instancji MariaDB instalowanej z oficjalnego tarballa. TARGET_MARIADB_VERSION="${TARGET_MARIADB_VERSION:-11.8}" MARIADB_DIR="${MARIADB_DIR:-/usr/local/mariadb-$TARGET_MARIADB_VERSION}" DATADIR="${DATADIR:-/var/lib/mariadb_data}" SERVICE_NAME="${SERVICE_NAME:-alt-mariadb}" INSTANCE_CNF="${INSTANCE_CNF:-/etc/alt-mariadb.cnf}" ALT_MY_CNF="${ALT_MY_CNF:-/usr/local/directadmin/conf/alt-my.cnf}" ALT_MYSQL_CONF="${ALT_MYSQL_CONF:-/usr/local/directadmin/conf/alt-mysql.conf}" ALT_METADATA_ENV="${ALT_METADATA_ENV:-/usr/local/directadmin/conf/alt-mariadb.env}" DOWNLOAD_DIR="${DOWNLOAD_DIR:-/usr/local/src}" MARIADB_TARBALL_URL="${MARIADB_TARBALL_URL:-}" FORCE_UPGRADE="${FORCE_UPGRADE:-no}" PORT="${PORT:-}" SOCKET="${SOCKET:-}" CURRENT_MARIADB_DIR="" RESOLVED_MARIADB_RELEASE="" DOWNLOAD_URL="" TARBALL_PATH="" TMP_DIR="" TARGET_BACKUP_DIR="" INSTANCE_CNF_BACKUP="" UPGRADE_EXTRACTED=0 UPGRADE_COMMITTED=0 SERVICE_WAS_ACTIVE=0 log() { printf '[INFO] %s\n' "$*" } warn() { printf '[UWAGA] %s\n' "$*" >&2 } die() { printf '[BŁĄD] %s\n' "$*" >&2 exit 1 } cleanup() { if [ -n "${TMP_DIR:-}" ] && [ -d "$TMP_DIR" ]; then rm -rf "$TMP_DIR" fi } trap cleanup EXIT rollback_upgrade() { local code="$1" if [ "$code" -eq 0 ] || [ "$UPGRADE_COMMITTED" -eq 1 ]; then cleanup return 0 fi warn "Upgrade nie zakończył się poprawnie, uruchamiam rollback." if [ -n "$INSTANCE_CNF_BACKUP" ] && [ -r "$INSTANCE_CNF_BACKUP" ]; then cp -a "$INSTANCE_CNF_BACKUP" "$INSTANCE_CNF" || true warn "RESTORED_INSTANCE_CNF: $INSTANCE_CNF" fi if [ "$UPGRADE_EXTRACTED" -eq 1 ] && [ -d "$MARIADB_DIR" ]; then if [ -n "$TARGET_BACKUP_DIR" ] && [ -d "$TARGET_BACKUP_DIR" ]; then rm -rf "$MARIADB_DIR" || true elif [ "$MARIADB_DIR" != "$CURRENT_MARIADB_DIR" ]; then rm -rf "$MARIADB_DIR" || true fi fi if [ -n "$TARGET_BACKUP_DIR" ] && [ -d "$TARGET_BACKUP_DIR" ] && [ ! -e "$MARIADB_DIR" ]; then mv "$TARGET_BACKUP_DIR" "$MARIADB_DIR" || true warn "RESTORED_PREVIOUS_DIR: $MARIADB_DIR" fi if [ "$SERVICE_WAS_ACTIVE" -eq 1 ]; then if command -v systemctl >/dev/null 2>&1; then systemctl daemon-reload || true systemctl restart "$SERVICE_NAME" || true fi fi cleanup } trap 'code=$?; rollback_upgrade "$code"' EXIT require_root() { if [ "${EUID:-$(id -u)}" -ne 0 ]; then die "Ten skrypt musi być uruchomiony jako root." fi } validate_version() { case "$TARGET_MARIADB_VERSION" in 10.11|11.4|11.8) log "Wybrano docelową wersję MariaDB: $TARGET_MARIADB_VERSION." ;; *) die "Nieobsługiwana wersja MariaDB: $TARGET_MARIADB_VERSION. Dozwolone wartości: 10.11, 11.4, 11.8." ;; esac } detect_architecture() { case "$(uname -m)" in x86_64|amd64) printf 'x86_64\n' ;; *) die "Nieobsługiwana architektura: $(uname -m). Skrypt obsługuje automatycznie tylko x86_64/amd64." ;; esac } detect_current_mariadb_dir() { if [ -r "$INSTANCE_CNF" ]; then CURRENT_MARIADB_DIR="$(awk -F= ' /^[[:space:]]*basedir[[:space:]]*=/ { value=$2 gsub(/^[[:space:]]+|[[:space:]]+$/, "", value) print value exit } ' "$INSTANCE_CNF")" DATADIR="$(awk -F= ' /^[[:space:]]*datadir[[:space:]]*=/ { value=$2 gsub(/^[[:space:]]+|[[:space:]]+$/, "", value) print value exit } ' "$INSTANCE_CNF")" PORT="$(awk -F= ' /^[[:space:]]*port[[:space:]]*=/ { value=$2 gsub(/^[[:space:]]+|[[:space:]]+$/, "", value) print value exit } ' "$INSTANCE_CNF")" SOCKET="$(awk -F= ' /^[[:space:]]*socket[[:space:]]*=/ { value=$2 gsub(/^[[:space:]]+|[[:space:]]+$/, "", value) print value exit } ' "$INSTANCE_CNF")" fi if [ -z "$CURRENT_MARIADB_DIR" ] && systemctl cat "$SERVICE_NAME" >/dev/null 2>&1; then CURRENT_MARIADB_DIR="$(systemctl cat "$SERVICE_NAME" \ | awk '/ExecStart=/ { sub(/^.*ExecStart=/, "") sub(/\/bin\/mariadbd.*$/, "") print exit }')" fi [ -n "$CURRENT_MARIADB_DIR" ] || die "Nie udało się wykryć bieżącego katalogu MariaDB." [ -x "$CURRENT_MARIADB_DIR/bin/mariadbd" ] || die "Bieżący katalog MariaDB nie zawiera bin/mariadbd: $CURRENT_MARIADB_DIR." [ -n "$DATADIR" ] || die "Nie udało się wykryć katalogu danych z $INSTANCE_CNF." log "Wykryto bieżący katalog MariaDB: $CURRENT_MARIADB_DIR." } resolve_latest_release_from_archive() { local series="$1" local listing="" local release="" listing="$(curl -fsSL "https://archive.mariadb.org/" || true)" release="$(printf '%s\n' "$listing" \ | grep -Eo "mariadb-${series//./\\.}\.[0-9]+/" \ | sed 's#^mariadb-##; s#/$##' \ | sort -V \ | tail -n 1)" [ -n "$release" ] || return 1 printf '%s\n' "$release" } resolve_tarball_from_directory() { local release="$1" local arch="$2" local dir_url="https://archive.mariadb.org/mariadb-${release}/bintar-linux-systemd-${arch}/" local listing="" local file="" listing="$(curl -fsSL "$dir_url" || true)" file="$(printf '%s\n' "$listing" \ | grep -Eo "mariadb-${release}-linux-systemd-${arch}\.tar\.(gz|xz)" \ | head -n 1)" [ -n "$file" ] || return 1 printf '%s%s\n' "$dir_url" "$file" } resolve_download_url() { local arch="" arch="$(detect_architecture)" if [ -n "$MARIADB_TARBALL_URL" ]; then DOWNLOAD_URL="$MARIADB_TARBALL_URL" log "Używam ręcznie ustawionego adresu tarballa MariaDB." return 0 fi RESOLVED_MARIADB_RELEASE="$(resolve_latest_release_from_archive "$TARGET_MARIADB_VERSION" || true)" [ -n "$RESOLVED_MARIADB_RELEASE" ] || die "Nie udało się wykryć najnowszego wydania dla gałęzi $TARGET_MARIADB_VERSION." DOWNLOAD_URL="$(resolve_tarball_from_directory "$RESOLVED_MARIADB_RELEASE" "$arch" || true)" [ -n "$DOWNLOAD_URL" ] || die "Nie udało się automatycznie ustalić URL tarballa. Ustaw MARIADB_TARBALL_URL." log "Wykryto tarball MariaDB $RESOLVED_MARIADB_RELEASE." } download_tarball() { local filename="" install -d -m 0755 "$DOWNLOAD_DIR" filename="$(basename "${DOWNLOAD_URL%%\?*}")" TARBALL_PATH="$DOWNLOAD_DIR/$filename" log "Pobieram tarball MariaDB do $TARBALL_PATH." curl -fL --retry 3 --connect-timeout 20 -o "$TARBALL_PATH" "$DOWNLOAD_URL" [ -s "$TARBALL_PATH" ] || die "Pobrany tarball jest pusty albo nie istnieje: $TARBALL_PATH." } extract_tarball() { local extracted_dir="" local backup_dir="" if [ -d "$MARIADB_DIR" ] && [ -n "$(find "$MARIADB_DIR" -mindepth 1 -maxdepth 1 -print -quit)" ]; then if [ "$FORCE_UPGRADE" != "yes" ]; then die "Katalog docelowy $MARIADB_DIR już istnieje. Ustaw FORCE_UPGRADE=yes, aby zastąpić go po kopii." fi TARGET_BACKUP_DIR="${MARIADB_DIR}.pre-upgrade.$(date +%Y%m%d%H%M%S)" log "Tworzę kopię istniejącego katalogu docelowego: $TARGET_BACKUP_DIR." mv "$MARIADB_DIR" "$TARGET_BACKUP_DIR" fi TMP_DIR="$(mktemp -d)" tar -xf "$TARBALL_PATH" -C "$TMP_DIR" extracted_dir="$(find "$TMP_DIR" -mindepth 1 -maxdepth 1 -type d -print -quit)" [ -n "$extracted_dir" ] || die "Tarball nie zawiera oczekiwanego katalogu MariaDB." mv "$extracted_dir" "$MARIADB_DIR" chown -R root:root "$MARIADB_DIR" UPGRADE_EXTRACTED=1 log "Nowe binaria MariaDB są w $MARIADB_DIR." } rewrite_instance_basedir() { local backup="" [ -r "$INSTANCE_CNF" ] || die "Brak konfiguracji instancji: $INSTANCE_CNF." backup="${INSTANCE_CNF}.pre-upgrade.$(date +%Y%m%d%H%M%S)" cp -a "$INSTANCE_CNF" "$backup" INSTANCE_CNF_BACKUP="$backup" sed -i "s#^[[:space:]]*basedir[[:space:]]*=.*#basedir=$MARIADB_DIR#" "$INSTANCE_CNF" sed -i "s#^[[:space:]]*plugin-dir[[:space:]]*=.*#plugin-dir=$MARIADB_DIR/lib/plugin#" "$INSTANCE_CNF" log "Zaktualizowano basedir i plugin-dir w $INSTANCE_CNF. Kopia: $backup." } restart_service() { log "Restartuję usługę $SERVICE_NAME." systemctl daemon-reload systemctl restart "$SERVICE_NAME" sleep 5 systemctl is-active --quiet "$SERVICE_NAME" || { systemctl status "$SERVICE_NAME" --no-pager || true die "Usługa $SERVICE_NAME nie uruchomiła się po upgrade." } } run_mariadb_upgrade() { local upgrade_bin="" if [ -x "$MARIADB_DIR/bin/mariadb-upgrade" ]; then upgrade_bin="$MARIADB_DIR/bin/mariadb-upgrade" elif [ -x "$MARIADB_DIR/bin/mysql_upgrade" ]; then upgrade_bin="$MARIADB_DIR/bin/mysql_upgrade" else warn "Nie znaleziono mariadb-upgrade ani mysql_upgrade, pomijam etap aktualizacji tabel systemowych." return 0 fi [ -r "$ALT_MY_CNF" ] || die "Brak pliku klienta alternatywnej instancji: $ALT_MY_CNF." log "Uruchamiam aktualizację tabel systemowych MariaDB." "$upgrade_bin" --defaults-extra-file="$ALT_MY_CNF" } credential_group() { if getent group diradmin >/dev/null 2>&1; then printf 'diradmin\n' else printf 'root\n' fi } sh_single_quote() { local value="$1" value="${value//\'/\'\\\'\'}" printf "'%s'" "$value" } write_alt_metadata_env() { local group_name metadata_mode tmp_file group_name="$(credential_group)" metadata_mode="0600" if [ "$group_name" = "diradmin" ]; then metadata_mode="0640" fi tmp_file="$(mktemp)" cat > "$tmp_file" <