Files
pg18-1C_for_deb13/install_pg1c.sh

405 lines
12 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="${ENV_FILE:-${SCRIPT_DIR}/.env}"
log() {
printf '[%s] %s\n' "$(date '+%F %T')" "$*"
}
fail() {
printf 'ERROR: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "Не найдена команда: $1"
}
bool_norm() {
case "${1:-}" in
1|true|TRUE|yes|YES|on|ON) echo "true" ;;
0|false|FALSE|no|NO|off|OFF) echo "false" ;;
*) fail "Неверное булево значение: ${1:-<empty>}" ;;
esac
}
require_root() {
[[ "$(id -u)" -eq 0 ]] || fail "Скрипт нужно запускать от root"
}
sql_escape_literal() {
printf "%s" "$1" | sed "s/'/''/g"
}
load_env() {
[[ -f "$ENV_FILE" ]] || fail "Файл окружения не найден: $ENV_FILE"
set -a
# shellcheck disable=SC1090
. "$ENV_FILE"
set +a
: "${REPO_ADD_URL:?В .env должна быть переменная REPO_ADD_URL}"
: "${PGPRO_BIN_DIR:?В .env должна быть переменная PGPRO_BIN_DIR}"
: "${SERVICE_NAME:?В .env должна быть переменная SERVICE_NAME}"
: "${PACKAGE_STANDALONE:?В .env должна быть переменная PACKAGE_STANDALONE}"
: "${PACKAGE_PARALLEL:?В .env должна быть переменная PACKAGE_PARALLEL}"
: "${PG_ADMIN_USER:?В .env должна быть переменная PG_ADMIN_USER}"
: "${PG_ADMIN_PASSWORD:?В .env должна быть переменная PG_ADMIN_PASSWORD}"
INSTALL_MODE="${INSTALL_MODE:-standalone}"
PG_ADMIN_SUPERUSER="$(bool_norm "${PG_ADMIN_SUPERUSER:-true}")"
PG_CREATE_DB="$(bool_norm "${PG_CREATE_DB:-true}")"
PG_SERVICE_ENABLE="$(bool_norm "${PG_SERVICE_ENABLE:-true}")"
PG_SERVICE_START="$(bool_norm "${PG_SERVICE_START:-true}")"
ENFORCE_PASSWORD_AUTH="$(bool_norm "${ENFORCE_PASSWORD_AUTH:-true}")"
CREATE_HBA_BACKUP="$(bool_norm "${CREATE_HBA_BACKUP:-true}")"
PRESERVE_POSTGRES_PEER_LOCAL="$(bool_norm "${PRESERVE_POSTGRES_PEER_LOCAL:-true}")"
SET_POSTGRES_ROLE_PASSWORD="$(bool_norm "${SET_POSTGRES_ROLE_PASSWORD:-false}")"
POSTGRES_ROLE_PASSWORD="${POSTGRES_ROLE_PASSWORD:-}"
POSTGRES_SOCKET_DIR="${POSTGRES_SOCKET_DIR:-/var/run/postgresql}"
PG_DB_NAME="${PG_DB_NAME:-}"
REPO_ADD_TMP="${REPO_ADD_TMP:-/tmp/pgpro-repo-add.sh}"
PG_CLUSTER_DIR="${PG_CLUSTER_DIR:-/var/lib/pgpro/1c-18/data}"
APP_LOCAL_AUTH_METHOD="${APP_LOCAL_AUTH_METHOD:-scram-sha-256}"
APP_HOST_AUTH_METHOD="${APP_HOST_AUTH_METHOD:-scram-sha-256}"
APP_HOST_IPV4_CIDR="${APP_HOST_IPV4_CIDR:-127.0.0.1/32}"
APP_HOST_IPV6_CIDR="${APP_HOST_IPV6_CIDR:-::1/128}"
case "$INSTALL_MODE" in
standalone|parallel) ;;
*) fail "INSTALL_MODE должен быть standalone или parallel" ;;
esac
case "$APP_LOCAL_AUTH_METHOD" in
scram-sha-256|md5|password|trust|peer) ;;
*) fail "APP_LOCAL_AUTH_METHOD должен быть scram-sha-256, md5, password, trust или peer" ;;
esac
case "$APP_HOST_AUTH_METHOD" in
scram-sha-256|md5|password|trust) ;;
*) fail "APP_HOST_AUTH_METHOD должен быть scram-sha-256, md5, password или trust" ;;
esac
if [[ "$PG_CREATE_DB" == "true" && -z "$PG_DB_NAME" ]]; then
fail "Если PG_CREATE_DB=true, нужно указать PG_DB_NAME"
fi
if [[ "$SET_POSTGRES_ROLE_PASSWORD" == "true" && -z "$POSTGRES_ROLE_PASSWORD" ]]; then
fail "Если SET_POSTGRES_ROLE_PASSWORD=true, нужно указать POSTGRES_ROLE_PASSWORD"
fi
PSQL="${PGPRO_BIN_DIR}/psql"
PGSETUP="${PGPRO_BIN_DIR}/pg-setup"
PG_ISREADY="${PGPRO_BIN_DIR}/pg_isready"
}
check_os() {
[[ -f /etc/os-release ]] || fail "Не найден /etc/os-release"
# shellcheck disable=SC1091
. /etc/os-release
[[ "${ID:-}" == "debian" ]] || fail "Скрипт рассчитан на Debian. Найдено: ${ID:-unknown}"
[[ "${VERSION_ID:-}" == "13" ]] || fail "Скрипт рассчитан на Debian 13. Найдено: ${VERSION_ID:-unknown}"
}
ensure_base_packages() {
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y wget ca-certificates gnupg apt-transport-https sed grep coreutils gawk
}
ensure_repo() {
if [[ -f /etc/apt/sources.list.d/postgresql-1c-18.list ]]; then
log "Репозиторий PostgreSQL for 1C 18 уже добавлен"
apt-get update
return
fi
log "Скачиваю vendor-скрипт добавления репозитория"
wget -O "$REPO_ADD_TMP" "$REPO_ADD_URL"
chmod +x "$REPO_ADD_TMP"
sh "$REPO_ADD_TMP"
rm -f "$REPO_ADD_TMP"
}
install_pgpro() {
export DEBIAN_FRONTEND=noninteractive
if [[ "$INSTALL_MODE" == "standalone" ]]; then
log "Устанавливаю пакет ${PACKAGE_STANDALONE}"
apt-get install -y "$PACKAGE_STANDALONE"
else
log "Устанавливаю пакет ${PACKAGE_PARALLEL} для параллельной установки"
apt-get install -y "$PACKAGE_PARALLEL"
[[ -x "$PGSETUP" ]] || fail "Не найден $PGSETUP"
if [[ ! -d "${PG_CLUSTER_DIR}/base" ]]; then
log "Инициализирую новый кластер Postgres Pro 1C 18"
"$PGSETUP" initdb
else
log "Кластер уже инициализирован, initdb пропускаю"
fi
fi
}
service_unit_exists() {
systemctl list-unit-files --type=service --no-legend 2>/dev/null | awk '{print $1}' | grep -Fxq "${SERVICE_NAME}.service"
}
service_enable() {
if [[ -x "$PGSETUP" ]]; then
"$PGSETUP" service enable
else
systemctl enable "$SERVICE_NAME"
fi
}
service_start() {
if [[ -x "$PGSETUP" ]]; then
"$PGSETUP" service start
else
systemctl start "$SERVICE_NAME"
fi
}
service_restart() {
if [[ -x "$PGSETUP" ]]; then
if "$PGSETUP" service condrestart >/dev/null 2>&1; then
return 0
fi
fi
systemctl restart "$SERVICE_NAME"
}
enable_and_start_service() {
if ! service_unit_exists; then
fail "Не найден unit-файл ${SERVICE_NAME}.service"
fi
if [[ "$PG_SERVICE_ENABLE" == "true" ]]; then
log "Включаю автозапуск ${SERVICE_NAME}"
service_enable
fi
if [[ "$PG_SERVICE_START" == "true" ]]; then
log "Запускаю ${SERVICE_NAME}"
service_start
fi
}
wait_for_postgres() {
[[ -x "$PG_ISREADY" ]] || fail "Не найден $PG_ISREADY"
log "Жду готовности PostgreSQL"
local i
for i in {1..60}; do
if runuser -u postgres -- "$PG_ISREADY" -h "$POSTGRES_SOCKET_DIR" -d postgres >/dev/null 2>&1; then
return 0
fi
sleep 1
done
systemctl status "$SERVICE_NAME" --no-pager || true
fail "PostgreSQL не поднялся за ожидаемое время"
}
psql_postgres() {
runuser -u postgres -- "$PSQL" -v ON_ERROR_STOP=1 -h "$POSTGRES_SOCKET_DIR" -d postgres "$@"
}
configure_role() {
[[ -x "$PSQL" ]] || fail "Не найден $PSQL"
log "Создаю или обновляю роль ${PG_ADMIN_USER}"
local role_attr="LOGIN"
if [[ "$PG_ADMIN_SUPERUSER" == "true" ]]; then
role_attr+=" SUPERUSER"
else
role_attr+=" NOSUPERUSER"
fi
local safe_user safe_pass
safe_user="$(sql_escape_literal "$PG_ADMIN_USER")"
safe_pass="$(sql_escape_literal "$PG_ADMIN_PASSWORD")"
psql_postgres <<SQL
DO \$do\$
BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${safe_user}') THEN
EXECUTE format('ALTER ROLE %I WITH ${role_attr} PASSWORD %L', '${safe_user}', '${safe_pass}');
ELSE
EXECUTE format('CREATE ROLE %I WITH ${role_attr} PASSWORD %L', '${safe_user}', '${safe_pass}');
END IF;
END
\$do\$;
SQL
}
configure_postgres_role_password_if_needed() {
[[ "$SET_POSTGRES_ROLE_PASSWORD" == "true" ]] || return 0
log "Устанавливаю пароль для роли postgres"
local safe_pass
safe_pass="$(sql_escape_literal "$POSTGRES_ROLE_PASSWORD")"
psql_postgres <<SQL
ALTER ROLE postgres WITH PASSWORD '${safe_pass}';
SQL
}
configure_database() {
[[ "$PG_CREATE_DB" == "true" ]] || return 0
log "Создаю базу ${PG_DB_NAME}, если она отсутствует"
local safe_db safe_user
safe_db="$(sql_escape_literal "$PG_DB_NAME")"
safe_user="$(sql_escape_literal "$PG_ADMIN_USER")"
psql_postgres <<SQL
SELECT 'CREATE DATABASE "' || replace('${safe_db}', '"', '""') || '" OWNER "' || replace('${safe_user}', '"', '""') || '"'
WHERE NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = '${safe_db}')
\gexec
SQL
}
detect_hba_file() {
psql_postgres -Atqc "SHOW hba_file;"
}
backup_hba_if_needed() {
local hba_file="$1"
if [[ "$CREATE_HBA_BACKUP" == "true" ]]; then
local backup_file="${hba_file}.bak.$(date +%Y%m%d_%H%M%S)"
cp -a "$hba_file" "$backup_file"
log "Создан бэкап pg_hba.conf: $backup_file"
fi
}
strip_managed_hba_block() {
local hba_file="$1"
local tmp_file
tmp_file="$(mktemp)"
awk '
BEGIN { skip=0 }
/^# BEGIN MANAGED BY install_pg1c\.sh$/ { skip=1; next }
/^# END MANAGED BY install_pg1c\.sh$/ { skip=0; next }
skip == 0 { print }
' "$hba_file" > "$tmp_file"
cat "$tmp_file" > "$hba_file"
rm -f "$tmp_file"
}
prepend_managed_hba_block() {
local hba_file="$1"
local tmp_file
tmp_file="$(mktemp)"
{
echo "# BEGIN MANAGED BY install_pg1c.sh"
if [[ "$PRESERVE_POSTGRES_PEER_LOCAL" == "true" ]]; then
echo "local all postgres peer"
fi
printf 'local all %s %s\n' "$PG_ADMIN_USER" "$APP_LOCAL_AUTH_METHOD"
printf 'host all %s %s %s\n' "$PG_ADMIN_USER" "$APP_HOST_IPV4_CIDR" "$APP_HOST_AUTH_METHOD"
printf 'host all %s %s %s\n' "$PG_ADMIN_USER" "$APP_HOST_IPV6_CIDR" "$APP_HOST_AUTH_METHOD"
echo "# END MANAGED BY install_pg1c.sh"
echo
cat "$hba_file"
} > "$tmp_file"
cat "$tmp_file" > "$hba_file"
rm -f "$tmp_file"
}
configure_pg_hba() {
[[ "$ENFORCE_PASSWORD_AUTH" == "true" ]] || {
log "Правка pg_hba.conf отключена: ENFORCE_PASSWORD_AUTH=false"
return 0
}
local hba_file
hba_file="$(detect_hba_file)"
[[ -n "$hba_file" ]] || fail "Не удалось определить путь к pg_hba.conf"
[[ -f "$hba_file" ]] || fail "Файл pg_hba.conf не найден: $hba_file"
log "Настраиваю точечные правила парольной аутентификации в $hba_file"
backup_hba_if_needed "$hba_file"
strip_managed_hba_block "$hba_file"
prepend_managed_hba_block "$hba_file"
log "Перезапускаю ${SERVICE_NAME} после правки pg_hba.conf"
service_restart
wait_for_postgres
}
show_summary() {
cat <<EOF
Готово.
Что сделано:
- добавлен репозиторий PostgreSQL for 1C 18;
- установлен пакет в режиме: ${INSTALL_MODE};
- сервис: ${SERVICE_NAME};
- роль БД: ${PG_ADMIN_USER};
- суперпользователь: ${PG_ADMIN_SUPERUSER};
- база создана: ${PG_CREATE_DB}${PG_DB_NAME:+ (${PG_DB_NAME})};
- точечные правила в pg_hba.conf: ${ENFORCE_PASSWORD_AUTH};
- сохранён local peer для postgres: ${PRESERVE_POSTGRES_PEER_LOCAL};
- пароль роли postgres задан: ${SET_POSTGRES_ROLE_PASSWORD}.
Проверки:
systemctl status ${SERVICE_NAME}
sudo -u postgres ${PSQL} -h ${POSTGRES_SOCKET_DIR} -d postgres -c "\\du"
sudo -u postgres ${PSQL} -h ${POSTGRES_SOCKET_DIR} -d postgres -c "\\l"
Подключение под новым пользователем:
${PSQL} -h 127.0.0.1 -U ${PG_ADMIN_USER} -d ${PG_DB_NAME:-postgres} -W
Повторный запуск скрипта безопасен:
- блок в pg_hba.conf обновляется адресно;
- доступ sudo -u postgres не теряется, если PRESERVE_POSTGRES_PEER_LOCAL=true.
EOF
}
main() {
require_root
need_cmd systemctl
need_cmd runuser
need_cmd apt-get
need_cmd wget
need_cmd awk
need_cmd sed
load_env
check_os
ensure_base_packages
ensure_repo
install_pgpro
enable_and_start_service
wait_for_postgres
configure_role
configure_postgres_role_password_if_needed
configure_database
configure_pg_hba
show_summary
}
main "$@"