From 5ea2bdbed7300d4cb31c513e18bbd86bd9e32bf9 Mon Sep 17 00:00:00 2001 From: support Date: Wed, 23 Sep 2026 17:19:50 +0200 Subject: [PATCH] 2026-09-23 15:19:50 --- PostgreSQL/build_rdbms_01/Readme.md | 196 ++++++++++++++++++ PostgreSQL/build_rdbms_01/install_common.sh | 83 ++++++++ PostgreSQL/build_rdbms_01/install_pg_cron.sh | 32 +++ .../build_rdbms_01/install_pg_repack.sh | 33 +++ .../build_rdbms_01/install_pg_stat_monitor.sh | 33 +++ .../install_pg_stat_statements.sh | 32 +++ PostgreSQL/build_rdbms_01/install_pgaudit.sh | 32 +++ .../build_rdbms_01/install_postgresql.sh | 43 ++++ .../install_postgresql_extensions.sh | 89 ++++++++ PostgreSQL/build_rdbms_01/install_set_user.sh | 32 +++ .../build_rdbms_01/install_timescaledb.sh | 36 ++++ PostgreSQL/build_rdbms_01/resume.txt | 1 + 12 files changed, 642 insertions(+) create mode 100644 PostgreSQL/build_rdbms_01/Readme.md create mode 100644 PostgreSQL/build_rdbms_01/install_common.sh create mode 100644 PostgreSQL/build_rdbms_01/install_pg_cron.sh create mode 100644 PostgreSQL/build_rdbms_01/install_pg_repack.sh create mode 100644 PostgreSQL/build_rdbms_01/install_pg_stat_monitor.sh create mode 100644 PostgreSQL/build_rdbms_01/install_pg_stat_statements.sh create mode 100644 PostgreSQL/build_rdbms_01/install_pgaudit.sh create mode 100644 PostgreSQL/build_rdbms_01/install_postgresql.sh create mode 100644 PostgreSQL/build_rdbms_01/install_postgresql_extensions.sh create mode 100644 PostgreSQL/build_rdbms_01/install_set_user.sh create mode 100644 PostgreSQL/build_rdbms_01/install_timescaledb.sh create mode 100644 PostgreSQL/build_rdbms_01/resume.txt diff --git a/PostgreSQL/build_rdbms_01/Readme.md b/PostgreSQL/build_rdbms_01/Readme.md new file mode 100644 index 0000000..da317d3 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/Readme.md @@ -0,0 +1,196 @@ +# PostgreSQL Source Installation Scripts + +These shell scripts build PostgreSQL from source and install PostgreSQL extensions into a versioned prefix: + +```text +/app/postgres/rdbms/ +``` + +The scripts use strict Bash error handling and require a working compiler and build environment. Sources are downloaded from the PostgreSQL FTP site and GitHub repositories. + +## Install everything + +Run the orchestrator with the PostgreSQL version to install: + +```bash +./install_postgresql_extensions.sh 18.6 +``` + +The orchestrator runs the installers in this order: + +1. PostgreSQL +2. pg_cron +3. TimescaleDB +4. pgAudit +5. set_user +6. pg_stat_statements +7. pg_repack +8. pg_stat_monitor + +After a successful run, the orchestrator: + +- Optionally updates `shared_preload_libraries` when `CONFIG_FILE` is set. +- Prints the installed PostgreSQL and extension versions. +- Creates `postgresql--engine.tar.gz` in the directory from which the command was launched. +- Writes the complete process log to `postgresql--process.log` in that same directory. + +## Individual installers + +Each component can also be installed independently. The PostgreSQL installation must already exist before running an extension installer. + +```bash +./install_postgresql.sh 18.6 +./install_pg_cron.sh 18.6 +./install_timescaledb.sh 18.6 +./install_pgaudit.sh 18.6 +./install_set_user.sh 18.6 +./install_pg_stat_statements.sh 18.6 +./install_pg_repack.sh 18.6 +./install_pg_stat_monitor.sh 18.6 +``` + +`install_postgresql.sh` recreates both the staging directory and the versioned PostgreSQL prefix before downloading sources. Extension installers recreate only the staging directory and preserve the PostgreSQL prefix. + +## Script descriptions + +### `install_postgresql_extensions.sh` + +All-in-one entry point. It invokes every installer, applies optional configuration changes, prints a product summary, writes a process log, and packages the installed PostgreSQL prefix. + +### `install_postgresql.sh` + +Downloads, configures, builds, and installs PostgreSQL. The build uses: + +```text +--with-ssl=openssl +--with-lz4 +``` + +### `install_pg_cron.sh` + +Builds and installs `pg_cron` against the selected PostgreSQL installation. + +### `install_timescaledb.sh` + +Bootstraps and builds TimescaleDB with CMake, installing it into the selected PostgreSQL prefix. + +### `install_pgaudit.sh` + +Builds and installs pgAudit using PostgreSQL PGXS. It selects a tag matching the PostgreSQL major version when possible. + +### `install_set_user.sh` + +Builds and installs the `set_user` extension using the selected PostgreSQL `pg_config`. + +### `install_pg_stat_statements.sh` + +Downloads the matching PostgreSQL source tree and builds `pg_stat_statements` from `contrib` using PGXS. + +### `install_pg_repack.sh` + +Builds and installs the `pg_repack` extension and its `pg_repack` command-line utility. + +### `install_pg_stat_monitor.sh` + +Builds and installs Percona's `pg_stat_monitor` extension. + +### `install_common.sh` + +Shared helper functions used by the installers, including: + +- Required-command checks +- PostgreSQL version validation +- GitHub release/tag lookup +- Source download and extraction +- Staging-directory reset +- PostgreSQL-prefix validation + +## Configuration + +The following environment variables can override defaults: + +| Variable | Default | Purpose | +| --- | --- | --- | +| `POSTGRES_ROOT` | `/app/postgres/rdbms` | Root directory for versioned PostgreSQL installations | +| `STAGING_DIR` | `/app/staging_area/copilot/tmp` | Temporary source and build directory | +| `JOBS` | `nproc` result | Parallel build job count | +| `CONFIG_FILE` | unset | PostgreSQL configuration file to update | +| `PG_CRON_TAG` | Latest compatible release/tag | pg_cron source tag | +| `TIMESCALEDB_TAG` | Latest release/tag | TimescaleDB source tag | +| `PGAUDIT_TAG` | PostgreSQL-major-compatible tag | pgAudit source tag | +| `SET_USER_TAG` | Latest release/tag | set_user source tag | +| `PG_REPACK_TAG` | Latest release/tag | pg_repack source tag | +| `PG_STAT_MONITOR_TAG` | Latest release/tag | pg_stat_monitor source tag | + +Repository variables can also be overridden when using a custom mirror: + +```bash +PG_CRON_REPOSITORY=owner/repository +TIMESCALEDB_REPOSITORY=owner/repository +PGAUDIT_REPOSITORY=owner/repository +SET_USER_REPOSITORY=owner/repository +PG_REPACK_REPOSITORY=owner/repository +PG_STAT_MONITOR_REPOSITORY=owner/repository +``` + +Example: + +```bash +JOBS=8 \ +PG_CRON_TAG=v1.6.5 \ +TIMESCALEDB_TAG=2.19.3 \ +PGAUDIT_TAG=17.1 \ +SET_USER_TAG=REL4_2_0 \ +./install_postgresql_extensions.sh 17.11 +``` + +When `CONFIG_FILE` is supplied, the orchestrator adds the extensions that require server startup loading: + +```conf +shared_preload_libraries = 'pg_cron,timescaledb,pgaudit,pg_stat_statements,pg_stat_monitor' +``` + +`pg_repack` and `set_user` do not require `shared_preload_libraries`. `pg_stat_activity` is a PostgreSQL system view and is not installed as an extension. + +## Prerequisites + +The scripts check for the tools needed by each build. The complete procedure requires: + +- Bash +- `curl` +- `tar` +- `make` +- `gcc` +- `cmake` +- `python3` when `CONFIG_FILE` is used +- Standard PostgreSQL build dependencies, including OpenSSL and LZ4 development libraries + +## Validation + +Validate all shell scripts: + +```bash +for script in install_*.sh; do + bash -n "$script" +done +``` + +Check an installed PostgreSQL version: + +```bash +/app/postgres/rdbms/18.6/bin/postgres --version +/app/postgres/rdbms/18.6/bin/pg_config --version +``` + +Check installed extension files: + +```bash +ls \ + /app/postgres/rdbms/18.6/lib/pg_cron.so \ + /app/postgres/rdbms/18.6/lib/timescaledb.so \ + /app/postgres/rdbms/18.6/lib/pgaudit.so \ + /app/postgres/rdbms/18.6/lib/set_user.so \ + /app/postgres/rdbms/18.6/lib/pg_stat_monitor.so +``` + +The extension SQL objects still need to be created in each target database with PostgreSQL's `CREATE EXTENSION` command. diff --git a/PostgreSQL/build_rdbms_01/install_common.sh b/PostgreSQL/build_rdbms_01/install_common.sh new file mode 100644 index 0000000..d6349d1 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_common.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +die() { + printf 'ERROR: %s\n' "$*" >&2 + exit 1 +} + +require_tools() { + local tool + for tool in "$@"; do + command -v "$tool" >/dev/null || die "$tool is required" + done +} + +validate_postgresql_version() { + local version="$1" + [[ "$version" =~ ^[0-9]+\.[0-9]+([.][0-9]+)?$ ]] || + die "invalid PostgreSQL version: $version" +} + +latest_tag() { + local repository="$1" + local tag + + tag="$( + curl -fsSL "https://api.github.com/repos/$repository/releases/latest" | + sed -nE 's/^[[:space:]]*"tag_name":[[:space:]]*"([^"]+)".*/\1/p' | + head -n 1 || true + )" + if [[ -n "$tag" ]]; then + printf '%s\n' "$tag" + return + fi + + curl -fsSL "https://api.github.com/repos/$repository/tags?per_page=1" | + sed -nE 's/^[[:space:]]*"name":[[:space:]]*"([^"]+)".*/\1/p' | + head -n 1 || true +} + +latest_pgaudit_tag() { + local repository="$1" + local major="$2" + local tag + + tag="$( + curl -fsSL "https://api.github.com/repos/$repository/tags?per_page=100" | + sed -nE 's/^[[:space:]]*"name":[[:space:]]*"([^"]+)".*/\1/p' | + grep -E "^${major//./\\.}\." | + head -n 1 || true + )" + printf '%s\n' "${tag:-$(latest_tag "$repository")}" +} + +reset_staging_dir() { + local staging_dir="$1" + [[ "$staging_dir" != "/" ]] || die "STAGING_DIR must not be the filesystem root" + rm -rf -- "$staging_dir" + mkdir -p "$staging_dir" +} + +require_postgresql_installation() { + local prefix="$1" + local pg_config="$prefix/bin/pg_config" + [[ "$prefix" != "/" ]] || die "PREFIX must not be the filesystem root" + [[ -x "$pg_config" ]] || die "PostgreSQL is not installed at $prefix" +} + +download_source() { + local staging_dir="$1" + local repository="$2" + local tag="$3" + local archive_name="$4" + local source_dir="$5" + local archive="$staging_dir/$archive_name" + + curl -fL --retry 3 --retry-delay 2 \ + -o "$archive" \ + "https://github.com/$repository/archive/refs/tags/$tag.tar.gz" + tar -xzf "$archive" -C "$staging_dir" + [[ -d "$source_dir" ]] || die "source directory was not created: $source_dir" +} diff --git a/PostgreSQL/build_rdbms_01/install_pg_cron.sh b/PostgreSQL/build_rdbms_01/install_pg_cron.sh new file mode 100644 index 0000000..4c05c12 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_pg_cron.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=install_common.sh +source "$SCRIPT_DIR/install_common.sh" + +readonly STAGING_DIR="${STAGING_DIR:-/app/staging_area/copilot/tmp}" +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" +readonly PG_CRON_REPOSITORY="${PG_CRON_REPOSITORY:-citusdata/pg_cron}" + +[[ $# -eq 1 ]] || die "Usage: $0 " +readonly POSTGRES_VERSION="$1" +validate_postgresql_version "$POSTGRES_VERSION" +require_tools curl tar make +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly PG_CONFIG="$PREFIX/bin/pg_config" +require_postgresql_installation "$PREFIX" +reset_staging_dir "$STAGING_DIR" + +readonly PG_CRON_TAG="${PG_CRON_TAG:-$(latest_tag "$PG_CRON_REPOSITORY")}" +[[ -n "$PG_CRON_TAG" ]] || die "could not determine the latest pg_cron release" +readonly PG_CRON_DIR="$STAGING_DIR/pg_cron-${PG_CRON_TAG#v}" + +printf 'Building pg_cron %s\n' "$PG_CRON_TAG" +download_source "$STAGING_DIR" "$PG_CRON_REPOSITORY" "$PG_CRON_TAG" \ + "pg_cron-${PG_CRON_TAG#v}.tar.gz" "$PG_CRON_DIR" +cd "$PG_CRON_DIR" +make -j"${JOBS:-$(nproc)}" PG_CONFIG="$PG_CONFIG" +make install PG_CONFIG="$PG_CONFIG" +test -x "$PREFIX/lib/pg_cron.so" diff --git a/PostgreSQL/build_rdbms_01/install_pg_repack.sh b/PostgreSQL/build_rdbms_01/install_pg_repack.sh new file mode 100644 index 0000000..4c24796 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_pg_repack.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=install_common.sh +source "$SCRIPT_DIR/install_common.sh" + +readonly STAGING_DIR="${STAGING_DIR:-/app/staging_area/copilot/tmp}" +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" +readonly PG_REPACK_REPOSITORY="${PG_REPACK_REPOSITORY:-reorg/pg_repack}" + +[[ $# -eq 1 ]] || die "Usage: $0 " +readonly POSTGRES_VERSION="$1" +validate_postgresql_version "$POSTGRES_VERSION" +require_tools curl tar make +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly PG_CONFIG="$PREFIX/bin/pg_config" +require_postgresql_installation "$PREFIX" +reset_staging_dir "$STAGING_DIR" + +readonly PG_REPACK_TAG="${PG_REPACK_TAG:-$(latest_tag "$PG_REPACK_REPOSITORY")}" +[[ -n "$PG_REPACK_TAG" ]] || die "could not determine the latest pg_repack release" +readonly PG_REPACK_DIR="$STAGING_DIR/pg_repack-${PG_REPACK_TAG}" + +printf 'Building pg_repack %s\n' "$PG_REPACK_TAG" +download_source "$STAGING_DIR" "$PG_REPACK_REPOSITORY" "$PG_REPACK_TAG" \ + "pg_repack-${PG_REPACK_TAG}.tar.gz" "$PG_REPACK_DIR" +cd "$PG_REPACK_DIR" +make -j"${JOBS:-$(nproc)}" PG_CONFIG="$PG_CONFIG" +make install PG_CONFIG="$PG_CONFIG" +test -x "$PREFIX/bin/pg_repack" +test -f "$PREFIX/share/extension/pg_repack.control" diff --git a/PostgreSQL/build_rdbms_01/install_pg_stat_monitor.sh b/PostgreSQL/build_rdbms_01/install_pg_stat_monitor.sh new file mode 100644 index 0000000..b41f768 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_pg_stat_monitor.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=install_common.sh +source "$SCRIPT_DIR/install_common.sh" + +readonly STAGING_DIR="${STAGING_DIR:-/app/staging_area/copilot/tmp}" +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" +readonly PG_STAT_MONITOR_REPOSITORY="${PG_STAT_MONITOR_REPOSITORY:-percona/pg_stat_monitor}" + +[[ $# -eq 1 ]] || die "Usage: $0 " +readonly POSTGRES_VERSION="$1" +validate_postgresql_version "$POSTGRES_VERSION" +require_tools curl tar make +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly PG_CONFIG="$PREFIX/bin/pg_config" +require_postgresql_installation "$PREFIX" +reset_staging_dir "$STAGING_DIR" + +readonly PG_STAT_MONITOR_TAG="${PG_STAT_MONITOR_TAG:-$(latest_tag "$PG_STAT_MONITOR_REPOSITORY")}" +[[ -n "$PG_STAT_MONITOR_TAG" ]] || die "could not determine the latest pg_stat_monitor release" +readonly PG_STAT_MONITOR_DIR="$STAGING_DIR/pg_stat_monitor-${PG_STAT_MONITOR_TAG#v}" + +printf 'Building pg_stat_monitor %s\n' "$PG_STAT_MONITOR_TAG" +download_source "$STAGING_DIR" "$PG_STAT_MONITOR_REPOSITORY" "$PG_STAT_MONITOR_TAG" \ + "pg_stat_monitor-${PG_STAT_MONITOR_TAG#v}.tar.gz" "$PG_STAT_MONITOR_DIR" +cd "$PG_STAT_MONITOR_DIR" +make -j"${JOBS:-$(nproc)}" PG_CONFIG="$PG_CONFIG" +make install PG_CONFIG="$PG_CONFIG" +test -x "$PREFIX/lib/pg_stat_monitor.so" +test -f "$PREFIX/share/extension/pg_stat_monitor.control" diff --git a/PostgreSQL/build_rdbms_01/install_pg_stat_statements.sh b/PostgreSQL/build_rdbms_01/install_pg_stat_statements.sh new file mode 100644 index 0000000..a7415b5 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_pg_stat_statements.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=install_common.sh +source "$SCRIPT_DIR/install_common.sh" + +readonly STAGING_DIR="${STAGING_DIR:-/app/staging_area/copilot/tmp}" +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" + +[[ $# -eq 1 ]] || die "Usage: $0 " +readonly POSTGRES_VERSION="$1" +validate_postgresql_version "$POSTGRES_VERSION" +require_tools curl tar make +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly PG_CONFIG="$PREFIX/bin/pg_config" +require_postgresql_installation "$PREFIX" +reset_staging_dir "$STAGING_DIR" + +printf 'Building pg_stat_statements from PostgreSQL %s\n' "$POSTGRES_VERSION" +readonly POSTGRES_ARCHIVE="$STAGING_DIR/postgresql-$POSTGRES_VERSION.tar.gz" +readonly POSTGRES_SOURCE="$STAGING_DIR/postgresql-$POSTGRES_VERSION" +curl -fL --retry 3 --retry-delay 2 \ + -o "$POSTGRES_ARCHIVE" \ + "https://ftp.postgresql.org/pub/source/v$POSTGRES_VERSION/postgresql-$POSTGRES_VERSION.tar.gz" +tar -xzf "$POSTGRES_ARCHIVE" -C "$STAGING_DIR" +make -C "$POSTGRES_SOURCE/contrib/pg_stat_statements" \ + -j"${JOBS:-$(nproc)}" USE_PGXS=1 PG_CONFIG="$PG_CONFIG" +make -C "$POSTGRES_SOURCE/contrib/pg_stat_statements" \ + install USE_PGXS=1 PG_CONFIG="$PG_CONFIG" +grep -E '^default_version' "$PREFIX/share/extension/pg_stat_statements.control" diff --git a/PostgreSQL/build_rdbms_01/install_pgaudit.sh b/PostgreSQL/build_rdbms_01/install_pgaudit.sh new file mode 100644 index 0000000..be2e7c4 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_pgaudit.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=install_common.sh +source "$SCRIPT_DIR/install_common.sh" + +readonly STAGING_DIR="${STAGING_DIR:-/app/staging_area/copilot/tmp}" +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" +readonly PGAUDIT_REPOSITORY="${PGAUDIT_REPOSITORY:-pgaudit/pgaudit}" + +[[ $# -eq 1 ]] || die "Usage: $0 " +readonly POSTGRES_VERSION="$1" +validate_postgresql_version "$POSTGRES_VERSION" +require_tools curl tar make +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly PG_CONFIG="$PREFIX/bin/pg_config" +require_postgresql_installation "$PREFIX" +reset_staging_dir "$STAGING_DIR" + +readonly PGAUDIT_TAG="${PGAUDIT_TAG:-$(latest_pgaudit_tag "$PGAUDIT_REPOSITORY" "${POSTGRES_VERSION%%.*}")}" +[[ -n "$PGAUDIT_TAG" ]] || die "could not determine the latest pgAudit release" +readonly PGAUDIT_DIR="$STAGING_DIR/pgaudit-${PGAUDIT_TAG#v}" + +printf 'Building pgAudit %s\n' "$PGAUDIT_TAG" +download_source "$STAGING_DIR" "$PGAUDIT_REPOSITORY" "$PGAUDIT_TAG" \ + "pgaudit-${PGAUDIT_TAG#v}.tar.gz" "$PGAUDIT_DIR" +cd "$PGAUDIT_DIR" +make -j"${JOBS:-$(nproc)}" USE_PGXS=1 PG_CONFIG="$PG_CONFIG" +make install USE_PGXS=1 PG_CONFIG="$PG_CONFIG" +test -x "$PREFIX/lib/pgaudit.so" diff --git a/PostgreSQL/build_rdbms_01/install_postgresql.sh b/PostgreSQL/build_rdbms_01/install_postgresql.sh new file mode 100644 index 0000000..2f968b3 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_postgresql.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=install_common.sh +source "$SCRIPT_DIR/install_common.sh" + +readonly STAGING_DIR="${STAGING_DIR:-/app/staging_area/copilot/tmp}" +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" + +[[ $# -eq 1 ]] || die "Usage: $0 " +readonly POSTGRES_VERSION="$1" +validate_postgresql_version "$POSTGRES_VERSION" +require_tools curl tar make gcc + +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly PG_BIN="$PREFIX/bin" +readonly PG_CONFIG="$PG_BIN/pg_config" +[[ "$PREFIX" != "/" ]] || die "PREFIX must not be the filesystem root" +reset_staging_dir "$STAGING_DIR" +rm -rf -- "$PREFIX" +mkdir -p "$STAGING_DIR" "$PREFIX" + +printf 'Building PostgreSQL %s\n' "$POSTGRES_VERSION" +readonly POSTGRES_ARCHIVE="$STAGING_DIR/postgresql-$POSTGRES_VERSION.tar.gz" +readonly POSTGRES_SOURCE="$STAGING_DIR/postgresql-$POSTGRES_VERSION" +curl -fL --retry 3 --retry-delay 2 \ + -o "$POSTGRES_ARCHIVE" \ + "https://ftp.postgresql.org/pub/source/v$POSTGRES_VERSION/postgresql-$POSTGRES_VERSION.tar.gz" +tar -xzf "$POSTGRES_ARCHIVE" -C "$STAGING_DIR" + +cd "$POSTGRES_SOURCE" +./configure \ + --prefix="$PREFIX" \ + --with-ssl=openssl \ + --with-lz4 +make -j"${JOBS:-$(nproc)}" +make install + +printf '\nVerification:\n' +"$PG_BIN/postgres" --version +"$PG_CONFIG" --version diff --git a/PostgreSQL/build_rdbms_01/install_postgresql_extensions.sh b/PostgreSQL/build_rdbms_01/install_postgresql_extensions.sh new file mode 100644 index 0000000..f0a9a66 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_postgresql_extensions.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +readonly INVOCATION_DIR="$PWD" + +[[ $# -eq 1 ]] || { + printf 'Usage: %s \n' "$0" >&2 + exit 2 +} +readonly POSTGRES_VERSION="$1" +readonly PROCESS_LOG="$INVOCATION_DIR/postgresql-$POSTGRES_VERSION-process.log" +readonly ENGINE_ARCHIVE="$INVOCATION_DIR/postgresql-$POSTGRES_VERSION-engine.tar.gz" + +exec > >(tee "$PROCESS_LOG") 2>&1 + +printf 'Installation started: %s\n' "$(date -Is)" +printf 'Invocation directory: %s\n' "$INVOCATION_DIR" + +"$SCRIPT_DIR/install_postgresql.sh" "$POSTGRES_VERSION" +"$SCRIPT_DIR/install_pg_cron.sh" "$POSTGRES_VERSION" +"$SCRIPT_DIR/install_timescaledb.sh" "$POSTGRES_VERSION" +"$SCRIPT_DIR/install_pgaudit.sh" "$POSTGRES_VERSION" +"$SCRIPT_DIR/install_set_user.sh" "$POSTGRES_VERSION" +"$SCRIPT_DIR/install_pg_stat_statements.sh" "$POSTGRES_VERSION" +"$SCRIPT_DIR/install_pg_repack.sh" "$POSTGRES_VERSION" +"$SCRIPT_DIR/install_pg_stat_monitor.sh" "$POSTGRES_VERSION" + +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly CONFIG_FILE="${CONFIG_FILE:-}" +readonly SHARED_PRELOAD_LIBRARIES="pg_cron,timescaledb,pgaudit,pg_stat_statements,pg_stat_monitor" + +if [[ -n "$CONFIG_FILE" ]]; then + [[ -f "$CONFIG_FILE" ]] || { + printf 'ERROR: configuration file does not exist: %s\n' "$CONFIG_FILE" >&2 + exit 1 + } + python3 - "$CONFIG_FILE" <<'PY' +import pathlib +import re +import sys + +path = pathlib.Path(sys.argv[1]) +text = path.read_text() +pattern = r"(?m)^[ \t]*(#?)[ \t]*shared_preload_libraries[ \t]*=[ \t]*'([^']*)'[^\n]*$" +match = re.search(pattern, text) +required = ("pg_cron", "timescaledb", "pgaudit", "pg_stat_statements", "pg_stat_monitor") +if match: + libraries = [item.strip() for item in match.group(2).split(",") if item.strip()] + for library in required: + if library not in libraries: + libraries.append(library) + line = "shared_preload_libraries = '" + ",".join(libraries) + "'\\t# (change requires restart)" + text = re.sub(pattern, line, text, count=1) +else: + text = text.rstrip("\n") + "\n\nshared_preload_libraries = '" + ",".join(required) + "'\\t# (change requires restart)\n" +path.write_text(text) +PY +fi + +printf 'Installed PostgreSQL and extensions in %s\n' "$PREFIX" +if [[ -n "$CONFIG_FILE" ]]; then + grep -E '^[[:space:]]*shared_preload_libraries[[:space:]]*=' "$CONFIG_FILE" +fi + +extension_version() { + local extension="$1" + awk -F"'" '/^[[:space:]]*default_version[[:space:]]*=/{print $2; exit}' \ + "$PREFIX/share/extension/$extension.control" +} + +printf '\nInstalled products and extensions:\n' +printf ' PostgreSQL: %s\n' "$("$PREFIX/bin/pg_config" --version | sed 's/^PostgreSQL //')" +printf ' pg_cron: %s\n' "$(extension_version pg_cron)" +printf ' TimescaleDB: %s\n' "$(extension_version timescaledb)" +printf ' pgaudit: %s\n' "$(extension_version pgaudit)" +printf ' set_user: %s\n' "$(extension_version set_user)" +printf ' pg_stat_statements: %s\n' "$(extension_version pg_stat_statements)" +printf ' pg_repack: %s\n' "$(extension_version pg_repack)" +printf ' pg_stat_monitor: %s\n' "$(extension_version pg_stat_monitor)" +printf " shared_preload_libraries = '%s'\n" "$SHARED_PRELOAD_LIBRARIES" + +rm -f -- "$ENGINE_ARCHIVE" +tar -czf "$ENGINE_ARCHIVE" -C "$POSTGRES_ROOT" "$POSTGRES_VERSION" +printf '\nCreated engine archive: %s\n' "$ENGINE_ARCHIVE" +printf 'Archive size: %s\n' "$(du -h "$ENGINE_ARCHIVE" | awk '{print $1}')" +printf 'Installation completed: %s\n' "$(date -Is)" diff --git a/PostgreSQL/build_rdbms_01/install_set_user.sh b/PostgreSQL/build_rdbms_01/install_set_user.sh new file mode 100644 index 0000000..01c6d55 --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_set_user.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=install_common.sh +source "$SCRIPT_DIR/install_common.sh" + +readonly STAGING_DIR="${STAGING_DIR:-/app/staging_area/copilot/tmp}" +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" +readonly SET_USER_REPOSITORY="${SET_USER_REPOSITORY:-pgaudit/set_user}" + +[[ $# -eq 1 ]] || die "Usage: $0 " +readonly POSTGRES_VERSION="$1" +validate_postgresql_version "$POSTGRES_VERSION" +require_tools curl tar make +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly PG_CONFIG="$PREFIX/bin/pg_config" +require_postgresql_installation "$PREFIX" +reset_staging_dir "$STAGING_DIR" + +readonly SET_USER_TAG="${SET_USER_TAG:-$(latest_tag "$SET_USER_REPOSITORY")}" +[[ -n "$SET_USER_TAG" ]] || die "could not determine the latest set_user release" +readonly SET_USER_DIR="$STAGING_DIR/set_user-${SET_USER_TAG#v}" + +printf 'Building set_user %s\n' "$SET_USER_TAG" +download_source "$STAGING_DIR" "$SET_USER_REPOSITORY" "$SET_USER_TAG" \ + "set_user-${SET_USER_TAG#v}.tar.gz" "$SET_USER_DIR" +cd "$SET_USER_DIR" +make -j"${JOBS:-$(nproc)}" PG_CONFIG="$PG_CONFIG" +make install PG_CONFIG="$PG_CONFIG" +test -x "$PREFIX/lib/set_user.so" diff --git a/PostgreSQL/build_rdbms_01/install_timescaledb.sh b/PostgreSQL/build_rdbms_01/install_timescaledb.sh new file mode 100644 index 0000000..7379d0f --- /dev/null +++ b/PostgreSQL/build_rdbms_01/install_timescaledb.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=install_common.sh +source "$SCRIPT_DIR/install_common.sh" + +readonly STAGING_DIR="${STAGING_DIR:-/app/staging_area/copilot/tmp}" +readonly POSTGRES_ROOT="${POSTGRES_ROOT:-/app/postgres/rdbms}" +readonly TIMESCALEDB_REPOSITORY="${TIMESCALEDB_REPOSITORY:-timescale/timescaledb}" + +[[ $# -eq 1 ]] || die "Usage: $0 " +readonly POSTGRES_VERSION="$1" +validate_postgresql_version "$POSTGRES_VERSION" +require_tools curl tar cmake +readonly PREFIX="$POSTGRES_ROOT/$POSTGRES_VERSION" +readonly PG_CONFIG="$PREFIX/bin/pg_config" +require_postgresql_installation "$PREFIX" +reset_staging_dir "$STAGING_DIR" + +readonly TIMESCALEDB_TAG="${TIMESCALEDB_TAG:-$(latest_tag "$TIMESCALEDB_REPOSITORY")}" +[[ -n "$TIMESCALEDB_TAG" ]] || die "could not determine the latest TimescaleDB release" +readonly TIMESCALEDB_DIR="$STAGING_DIR/timescaledb-${TIMESCALEDB_TAG#v}" + +printf 'Building TimescaleDB %s\n' "$TIMESCALEDB_TAG" +download_source "$STAGING_DIR" "$TIMESCALEDB_REPOSITORY" "$TIMESCALEDB_TAG" \ + "timescaledb-${TIMESCALEDB_TAG#v}.tar.gz" "$TIMESCALEDB_DIR" +cd "$TIMESCALEDB_DIR" +./bootstrap \ + -DPG_CONFIG="$PG_CONFIG" \ + -DCMAKE_INSTALL_PREFIX="$PREFIX" \ + -DCMAKE_BUILD_TYPE=Release +cmake --build build --parallel "${JOBS:-$(nproc)}" +cmake --install build +test -x "$PREFIX/lib/timescaledb.so" diff --git a/PostgreSQL/build_rdbms_01/resume.txt b/PostgreSQL/build_rdbms_01/resume.txt new file mode 100644 index 0000000..a7afe9e --- /dev/null +++ b/PostgreSQL/build_rdbms_01/resume.txt @@ -0,0 +1 @@ +copilot --resume=810fde45-db5c-4a88-8abf-550ae7a485e4