tools.func Implement PostgreSQL setup and upgrade function

Added setup_postgresql function to install or upgrade PostgreSQL, including optional modules and backup restoration.
This commit is contained in:
CanbiZ (MickLesk)
2026-03-18 16:25:24 +01:00
committed by GitHub
parent 8b4f0f60e1
commit be10f822e5

View File

@@ -6926,6 +6926,263 @@ function setup_postgresql() {
fi
}
# ------------------------------------------------------------------------------
# Installs or upgrades PostgreSQL and optional extensions/modules.
#
# Description:
# - By default uses distro repository (Debian/Ubuntu apt) for stability
# - Optionally uses official PGDG repository for specific versions
# - Detects existing PostgreSQL version
# - Dumps all databases before upgrade
# - Installs optional PG_MODULES (e.g. postgis, contrib)
# - Restores dumped data post-upgrade
#
# Variables:
# USE_PGDG_REPO - Set to "true" to use official PGDG repository
# (default: false, uses distro packages)
# PG_VERSION - Major PostgreSQL version (e.g. 15, 16) (default: 16)
# PG_MODULES - Comma-separated list of modules (e.g. "postgis,contrib")
#
# Examples:
# setup_postgresql # Uses distro package (recommended)
# USE_PGDG_REPO=true setup_postgresql # Uses official PGDG repo
# USE_PGDG_REPO=true PG_VERSION="17" setup_postgresql # Specific version from PGDG
# PG_VERSION="17" PG_MODULES="cron" setup_postgresql # With pg_cron module
# ------------------------------------------------------------------------------
# Internal helper: Configure shared_preload_libraries for pg_cron
_configure_pg_cron_preload() {
local modules="${1:-}"
[[ -z "$modules" ]] && return 0
if [[ ",$modules," == *",cron,"* ]]; then
local current_libs
current_libs=$(sudo -u postgres psql -tAc "SHOW shared_preload_libraries;" 2>/dev/null || echo "")
if [[ "$current_libs" != *"pg_cron"* ]]; then
local new_libs="${current_libs:+${current_libs},}pg_cron"
$STD sudo -u postgres psql -c "ALTER SYSTEM SET shared_preload_libraries = '${new_libs}';"
$STD systemctl restart postgresql
fi
fi
}
function setup_postgresql() {
local PG_VERSION="${PG_VERSION:-16}"
local PG_MODULES="${PG_MODULES:-}"
local USE_PGDG_REPO="${USE_PGDG_REPO:-false}"
local DISTRO_ID DISTRO_CODENAME
DISTRO_ID=$(awk -F= '/^ID=/{print $2}' /etc/os-release | tr -d '"')
DISTRO_CODENAME=$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)
# Ensure non-interactive mode for all apt operations
export DEBIAN_FRONTEND=noninteractive
export NEEDRESTART_MODE=a
export NEEDRESTART_SUSPEND=1
# Get currently installed version
local CURRENT_PG_VERSION=""
if command -v psql >/dev/null; then
CURRENT_PG_VERSION="$(psql -V 2>/dev/null | awk '{print $3}' | cut -d. -f1)"
fi
# Scenario 1: Use distro repository (default, most stable)
if [[ "$USE_PGDG_REPO" != "true" && "$USE_PGDG_REPO" != "TRUE" && "$USE_PGDG_REPO" != "1" ]]; then
msg_info "Setup PostgreSQL (distro package)"
# If already installed, just update
if [[ -n "$CURRENT_PG_VERSION" ]]; then
msg_info "Update PostgreSQL $CURRENT_PG_VERSION"
ensure_apt_working || return 1
upgrade_packages_with_retry "postgresql" "postgresql-client" || true
cache_installed_version "postgresql" "$CURRENT_PG_VERSION"
msg_ok "Update PostgreSQL $CURRENT_PG_VERSION"
# Still install modules if specified
if [[ -n "$PG_MODULES" ]]; then
IFS=',' read -ra MODULES <<<"$PG_MODULES"
for module in "${MODULES[@]}"; do
$STD apt install -y "postgresql-${CURRENT_PG_VERSION}-${module}" 2>/dev/null || true
done
fi
_configure_pg_cron_preload "$PG_MODULES"
return 0
fi
# Fresh install from distro repo
ensure_apt_working || return 1
export DEBIAN_FRONTEND=noninteractive
install_packages_with_retry "postgresql" "postgresql-client" || {
msg_error "Failed to install PostgreSQL from distro repository"
return 1
}
# Get installed version
local INSTALLED_VERSION=""
if command -v psql >/dev/null; then
INSTALLED_VERSION="$(psql -V 2>/dev/null | awk '{print $3}' | cut -d. -f1)"
fi
$STD systemctl enable --now postgresql 2>/dev/null || true
# Add PostgreSQL binaries to PATH
if [[ -n "$INSTALLED_VERSION" ]] && ! grep -q '/usr/lib/postgresql' /etc/environment 2>/dev/null; then
echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/'"${INSTALLED_VERSION}"'/bin"' >/etc/environment
fi
cache_installed_version "postgresql" "${INSTALLED_VERSION:-distro}"
msg_ok "Setup PostgreSQL ${INSTALLED_VERSION:-from distro}"
# Install optional modules
if [[ -n "$PG_MODULES" && -n "$INSTALLED_VERSION" ]]; then
IFS=',' read -ra MODULES <<<"$PG_MODULES"
for module in "${MODULES[@]}"; do
$STD apt install -y "postgresql-${INSTALLED_VERSION}-${module}" 2>/dev/null || true
done
fi
_configure_pg_cron_preload "$PG_MODULES"
return 0
fi
# Scenario 2: Use official PGDG repository (USE_PGDG_REPO=true)
# Scenario 2a: Already at correct version
if [[ "$CURRENT_PG_VERSION" == "$PG_VERSION" ]]; then
msg_info "Update PostgreSQL $PG_VERSION"
ensure_apt_working || return 1
# Perform upgrade with retry logic (non-fatal if fails)
upgrade_packages_with_retry "postgresql-${PG_VERSION}" "postgresql-client-${PG_VERSION}" 2>/dev/null || true
cache_installed_version "postgresql" "$PG_VERSION"
msg_ok "Update PostgreSQL $PG_VERSION"
# Still install modules if specified
if [[ -n "$PG_MODULES" ]]; then
IFS=',' read -ra MODULES <<<"$PG_MODULES"
for module in "${MODULES[@]}"; do
$STD apt install -y "postgresql-${PG_VERSION}-${module}" 2>/dev/null || true
done
fi
_configure_pg_cron_preload "$PG_MODULES"
return 0
fi
# Scenario 2: Different version - backup, remove old, install new
if [[ -n "$CURRENT_PG_VERSION" ]]; then
msg_info "Upgrade PostgreSQL from $CURRENT_PG_VERSION to $PG_VERSION"
msg_info "Creating backup of PostgreSQL $CURRENT_PG_VERSION databases..."
local PG_BACKUP_FILE="/var/lib/postgresql/backup_$(date +%F)_v${CURRENT_PG_VERSION}.sql"
$STD runuser -u postgres -- pg_dumpall >"$PG_BACKUP_FILE" || {
msg_error "Failed to backup PostgreSQL databases"
return 1
}
$STD systemctl stop postgresql || true
$STD apt purge -y "postgresql-${CURRENT_PG_VERSION}" "postgresql-client-${CURRENT_PG_VERSION}" 2>/dev/null || true
else
msg_info "Setup PostgreSQL $PG_VERSION"
fi
# Scenario 3: Fresh install or after removal - setup repo and install
prepare_repository_setup "pgdg" "postgresql" || {
msg_error "Failed to prepare PostgreSQL repository"
return 1
}
local SUITE
case "$DISTRO_CODENAME" in
trixie | forky | sid)
if verify_repo_available "https://apt.postgresql.org/pub/repos/apt" "trixie-pgdg"; then
SUITE="trixie-pgdg"
else
SUITE="bookworm-pgdg"
fi
;;
*)
SUITE=$(get_fallback_suite "$DISTRO_ID" "$DISTRO_CODENAME" "https://apt.postgresql.org/pub/repos/apt")
SUITE="${SUITE}-pgdg"
;;
esac
setup_deb822_repo \
"pgdg" \
"https://www.postgresql.org/media/keys/ACCC4CF8.asc" \
"https://apt.postgresql.org/pub/repos/apt" \
"$SUITE" \
"main"
if ! $STD apt update; then
msg_error "APT update failed for PostgreSQL repository"
return 1
fi
# Install ssl-cert dependency if available
if apt-cache search "^ssl-cert$" 2>/dev/null | grep -q .; then
$STD apt install -y ssl-cert 2>/dev/null || true
fi
# Try multiple PostgreSQL package patterns with retry logic
local pg_install_success=false
if apt-cache search "^postgresql-${PG_VERSION}$" 2>/dev/null | grep -q . &&
install_packages_with_retry "postgresql-${PG_VERSION}" "postgresql-client-${PG_VERSION}"; then
pg_install_success=true
fi
if [[ "$pg_install_success" == false ]] &&
apt-cache search "^postgresql-server-${PG_VERSION}$" 2>/dev/null | grep -q . &&
$STD apt install -y "postgresql-server-${PG_VERSION}" "postgresql-client-${PG_VERSION}" 2>/dev/null; then
pg_install_success=true
fi
if [[ "$pg_install_success" == false ]] &&
apt-cache search "^postgresql$" 2>/dev/null | grep -q . &&
$STD apt install -y postgresql postgresql-client 2>/dev/null; then
pg_install_success=true
fi
if [[ "$pg_install_success" == false ]]; then
msg_error "PostgreSQL package not available for suite ${SUITE}"
return 1
fi
if ! command -v psql >/dev/null 2>&1; then
msg_error "PostgreSQL installed but psql command not found"
return 1
fi
# Restore database backup if we upgraded from previous version
if [[ -n "$CURRENT_PG_VERSION" && -n "${PG_BACKUP_FILE:-}" && -f "${PG_BACKUP_FILE}" ]]; then
msg_info "Restoring PostgreSQL databases from backup..."
$STD runuser -u postgres -- psql <"$PG_BACKUP_FILE" 2>/dev/null || {
msg_warn "Failed to restore database backup - this may be expected for major version upgrades"
}
fi
$STD systemctl enable --now postgresql 2>/dev/null || {
msg_warn "Failed to enable/start PostgreSQL service"
}
# Add PostgreSQL binaries to PATH
if ! grep -q '/usr/lib/postgresql' /etc/environment 2>/dev/null; then
echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/'"${PG_VERSION}"'/bin"' >/etc/environment
fi
cache_installed_version "postgresql" "$PG_VERSION"
msg_ok "Setup PostgreSQL $PG_VERSION"
# Install optional modules
if [[ -n "$PG_MODULES" ]]; then
IFS=',' read -ra MODULES <<<"$PG_MODULES"
for module in "${MODULES[@]}"; do
$STD apt install -y "postgresql-${PG_VERSION}-${module}" 2>/dev/null || {
msg_warn "Failed to install PostgreSQL module: ${module}"
}
done
fi
_configure_pg_cron_preload "$PG_MODULES"
}
# ------------------------------------------------------------------------------
# Creates PostgreSQL database with user and optional extensions
#
@@ -6942,6 +7199,7 @@ function setup_postgresql() {
# PG_DB_NAME="immich" PG_DB_USER="immich" PG_DB_EXTENSIONS="pgvector" setup_postgresql_db
# PG_DB_NAME="ghostfolio" PG_DB_USER="ghostfolio" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
# PG_DB_NAME="adventurelog" PG_DB_USER="adventurelog" PG_DB_EXTENSIONS="postgis" setup_postgresql_db
# PG_DB_NAME="splitpro" PG_DB_USER="splitpro" PG_DB_EXTENSIONS="pg_cron" setup_postgresql_db
#
# Variables:
# PG_DB_NAME - Database name (required)
@@ -6973,6 +7231,13 @@ function setup_postgresql_db() {
$STD sudo -u postgres psql -c "CREATE ROLE $PG_DB_USER WITH LOGIN PASSWORD '$PG_DB_PASS';"
$STD sudo -u postgres psql -c "CREATE DATABASE $PG_DB_NAME WITH OWNER $PG_DB_USER ENCODING 'UTF8' TEMPLATE template0;"
# Configure pg_cron database BEFORE creating the extension (must be set before pg_cron loads)
if [[ -n "${PG_DB_EXTENSIONS:-}" ]] && [[ ",${PG_DB_EXTENSIONS//[[:space:]]/}," == *",pg_cron,"* ]]; then
$STD sudo -u postgres psql -c "ALTER SYSTEM SET cron.database_name = '${PG_DB_NAME}';"
$STD sudo -u postgres psql -c "ALTER SYSTEM SET cron.timezone = 'UTC';"
$STD systemctl restart postgresql
fi
# Install extensions (comma-separated)
if [[ -n "${PG_DB_EXTENSIONS:-}" ]]; then
IFS=',' read -ra EXT_LIST <<<"${PG_DB_EXTENSIONS:-}"
@@ -6982,6 +7247,12 @@ function setup_postgresql_db() {
done
fi
# Grant pg_cron schema permissions to DB user
if [[ -n "${PG_DB_EXTENSIONS:-}" ]] && [[ ",${PG_DB_EXTENSIONS//[[:space:]]/}," == *",pg_cron,"* ]]; then
$STD sudo -u postgres psql -d "$PG_DB_NAME" -c "GRANT USAGE ON SCHEMA cron TO ${PG_DB_USER};"
$STD sudo -u postgres psql -d "$PG_DB_NAME" -c "GRANT ALL ON ALL TABLES IN SCHEMA cron TO ${PG_DB_USER};"
fi
# ALTER ROLE settings for Django/Rails compatibility (unless skipped)
if [[ "${PG_DB_SKIP_ALTER_ROLE:-}" != "true" ]]; then
$STD sudo -u postgres psql -c "ALTER ROLE $PG_DB_USER SET client_encoding TO 'utf8';"
@@ -7023,7 +7294,6 @@ function setup_postgresql_db() {
export PG_DB_USER
export PG_DB_PASS
}
# ------------------------------------------------------------------------------
# Installs rbenv and ruby-build, installs Ruby and optionally Rails.
#