From f30729eb9c14a0ef127b4a6715abe1431e9cf3b1 Mon Sep 17 00:00:00 2001 From: Nicolas Bigler Date: Wed, 18 Mar 2026 16:11:40 +0100 Subject: [PATCH] Add new plpython3u extension for cnpg Signed-off-by: Nicolas Bigler --- .github/workflows/bake.yml | 5 ++- Justfile | 2 +- plpython3u/Dockerfile | 64 +++++++++++++++++++++++++++++++++++++ plpython3u/README.md | 65 ++++++++++++++++++++++++++++++++++++++ plpython3u/metadata.hcl | 26 +++++++++++++++ 5 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 plpython3u/Dockerfile create mode 100644 plpython3u/README.md create mode 100644 plpython3u/metadata.hcl diff --git a/.github/workflows/bake.yml b/.github/workflows/bake.yml index a85bf87..dbcb100 100644 --- a/.github/workflows/bake.yml +++ b/.github/workflows/bake.yml @@ -11,7 +11,7 @@ on: defaults: run: - shell: 'bash -Eeuo pipefail -x {0}' + shell: "bash -Eeuo pipefail -x {0}" permissions: {} @@ -38,6 +38,9 @@ jobs: pg_repack: - 'pg_repack/**' - *shared + plpython3u: + - 'plpython3u/**' + - *shared - name: Compute matrix id: get-matrix diff --git a/Justfile b/Justfile index b81749c..4514c9d 100644 --- a/Justfile +++ b/Justfile @@ -11,7 +11,7 @@ build ext: docker buildx bake \ -f {{ ext }}/metadata.hcl \ -f docker-bake.hcl \ - --set "*.platforms=linux/{{ arch }}" \ + --set "*.platform=linux/{{ arch }}" \ --load # Build and push to local OCI registry (multi-platform) diff --git a/plpython3u/Dockerfile b/plpython3u/Dockerfile new file mode 100644 index 0000000..4e72030 --- /dev/null +++ b/plpython3u/Dockerfile @@ -0,0 +1,64 @@ +ARG BASE=ghcr.io/cloudnative-pg/postgresql:18-minimal-bookworm +FROM $BASE AS builder + +ARG PG_MAJOR +ARG EXT_VERSION + +USER 0 + +RUN set -eux && \ + # Initial system libraries + ldconfig -p | awk '{print $NF}' | grep '^/' | sort | uniq > /tmp/base-image-libs.out && \ + + # Install PL/Python3 + apt-get update && apt-get install -y --no-install-recommends \ + "postgresql-plpython3-${PG_MAJOR}=${EXT_VERSION}" && \ + rm -rf /var/lib/apt/lists/* + +# Gather PL/Python3 system libraries and their licenses +RUN mkdir -p /system /licenses && \ + # Get libraries + ldd /usr/lib/postgresql/${PG_MAJOR}/lib/plpython3.so \ + | awk '{print $3}' | grep '^/' | sort | uniq > /tmp/all-deps.out && \ + # Extract all the libs that aren't already part of the base image + comm -13 /tmp/base-image-libs.out /tmp/all-deps.out > /tmp/libraries.out && \ + while read -r lib; do \ + resolved=$(readlink -f "$lib"); \ + dir=$(dirname "$lib"); \ + base=$(basename "$lib"); \ + # Copy the real file + cp -a "$resolved" /system/; \ + # Reconstruct all its symlinks + for file in "$dir"/"${base%.so*}.so"*; do \ + [ -e "$file" ] || continue; \ + # If it's a symlink and it resolves to the same real file, we reconstruct it + if [ -L "$file" ] && [ "$(readlink -f "$file")" = "$resolved" ]; then \ + ln -sf "$(basename "$resolved")" "/system/$(basename "$file")"; \ + fi; \ + done; \ + done < /tmp/libraries.out && \ + # Get licenses + for lib in $(find /system -maxdepth 1 -type f -name '*.so*'); do \ + # Get the name of the pkg that installed the library + pkg=$(dpkg -S "$(basename "$lib")" | grep -v "diversion by" | awk -F: '/:/{print $1; exit}'); \ + [ -z "$pkg" ] && continue; \ + mkdir -p "/licenses/$pkg" && cp -a "/usr/share/doc/$pkg/copyright" "/licenses/$pkg/copyright"; \ + done + +FROM scratch +ARG PG_MAJOR + +# Licenses +COPY --from=builder /licenses /licences/ +COPY --from=builder /usr/share/doc/postgresql-plpython3-${PG_MAJOR}/copyright /licenses/postgresql-plpython3-${PG_MAJOR}/ + +# Libraries +COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/plpython3* /lib/ + +# Share +COPY --from=builder /usr/share/postgresql/${PG_MAJOR}/extension/plpython3u* /share/extension/ + +# System libs +COPY --from=builder /system /system + +USER 65532:65532 diff --git a/plpython3u/README.md b/plpython3u/README.md new file mode 100644 index 0000000..340bf18 --- /dev/null +++ b/plpython3u/README.md @@ -0,0 +1,65 @@ +# Plpython3u + +The `plpython3u` PostgreSQL extension allows writing functions and stored procedures in Python 3. +It is the untrusted variant of PL/Python, meaning it can access the file system and network from within the database. +For more information, see the [official documentation](https://www.postgresql.org/docs/current/plpython.html). + +## Usage + +### 1. Add the Plpython3u extension image to your Cluster + +Define the `plpython3u` extension under the `postgresql.extensions` section of +your `Cluster` resource. For example: + +```yaml +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: cluster-plpython3u +spec: + imageName: ghcr.io/cloudnative-pg/postgresql:18-minimal-bookworm + instances: 1 + + storage: + size: 1Gi + + postgresql: + extensions: + - name: plpython3u + image: + # renovate: suite=bookworm-pgdg depName=postgresql-plpython3-18 + reference: ghcr.io/vshn/plpython3u:1.0-18-bookworm + ld_library_path: + - system +``` + +### 2. Enable the extension in a database + +You can install `plpython3u` in a specific database by creating or updating a +`Database` resource. For example, to enable it in the `app` database: + +```yaml +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: cluster-plpython3u-app +spec: + name: app + owner: app + cluster: + name: cluster-plpython3u + extensions: + - name: plpython3u + # renovate: suite=bookworm-pgdg depName=postgresql-plpython3-18 + version: '1.0' +``` + +### 3. Verify installation + +Once the database is ready, connect to it with `psql` and run: + +```sql +\dx +``` + +You should see `plpython3u` listed among the installed extensions. diff --git a/plpython3u/metadata.hcl b/plpython3u/metadata.hcl new file mode 100644 index 0000000..51f0874 --- /dev/null +++ b/plpython3u/metadata.hcl @@ -0,0 +1,26 @@ +metadata = { + name = "plpython3u" + sql_name = "plpython3u" + image_name = "plpython3u" + licenses = [ "BSD-2-clause", "BSD-3-Clause", "Custom-Unicode", + "Custom-pg_dump", "Custom-regex", "PostgreSQL", + "Tcl", "double-metaphone", "nagaysau-ishii" ] + shared_preload_libraries = [] + extension_control_path = [] + dynamic_library_path = [] + ld_library_path = ["system"] + auto_update_os_libs = true + required_extensions = [] + create_extension = true + + versions = { + bookworm = { + // renovate: suite=bookworm-pgdg depName=postgresql-plpython3-18 + "18" = "18.3-1.pgdg12+1" + } + trixie = { + // renovate: suite=trixie-pgdg depName=postgresql-plpython3-18 + "18" = "18.3-1.pgdg13+1" + } + } +}