From 217c8755f313e3b2cd4b72341d952df5fdcc9e10 Mon Sep 17 00:00:00 2001 From: Tobias Florek Date: Wed, 8 Apr 2026 10:27:19 +0200 Subject: [PATCH] add tds-fdw extension Closes #181 Signed-off-by: Tobias Florek --- .github/workflows/bake.yml | 4 + tds-fdw/Dockerfile | 70 ++++++++++++++++ tds-fdw/README.md | 89 +++++++++++++++++++++ tds-fdw/metadata.hcl | 47 +++++++++++ tds-fdw/system-libs/18-bookworm-os-libs.txt | 2 + tds-fdw/system-libs/18-trixie-os-libs.txt | 2 + 6 files changed, 214 insertions(+) create mode 100644 tds-fdw/Dockerfile create mode 100644 tds-fdw/README.md create mode 100644 tds-fdw/metadata.hcl create mode 100644 tds-fdw/system-libs/18-bookworm-os-libs.txt create mode 100644 tds-fdw/system-libs/18-trixie-os-libs.txt diff --git a/.github/workflows/bake.yml b/.github/workflows/bake.yml index efbbfb0..83c90b0 100644 --- a/.github/workflows/bake.yml +++ b/.github/workflows/bake.yml @@ -13,6 +13,7 @@ on: - postgis - pgaudit - pg-crash + - tds-fdw defaults: run: @@ -55,6 +56,9 @@ jobs: pg-crash: - 'pg-crash/**' - *shared + tds-fdw: + - 'tds-fdw/**' + - *shared # Compute a matrix containing the list of all extensions that have been modified - name: Compute matrix diff --git a/tds-fdw/Dockerfile b/tds-fdw/Dockerfile new file mode 100644 index 0000000..cd1cd67 --- /dev/null +++ b/tds-fdw/Dockerfile @@ -0,0 +1,70 @@ +ARG BASE=ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie +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 tds-fdw + apt-get update && \ + apt-get install -y --no-install-recommends \ + "postgresql-${PG_MAJOR}-tds-fdw=${EXT_VERSION}" + +# Gather tds-fdw system libraries and their licenses +RUN mkdir -p /system /licenses && \ + # Get libraries + ldd /usr/lib/postgresql/${PG_MAJOR}/lib/tds-fdw*.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 /licenses/ +COPY --from=builder \ + /usr/share/doc/postgresql-${PG_MAJOR}-tds-fdw/copyright \ + /licenses/postgresql-${PG_MAJOR}-tds-fdw/ + +# Libraries +COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/tds_fdw* /lib/ + +COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/bitcode/ /lib/bitcode/ + +# Share +COPY --from=builder \ + /usr/share/postgresql/${PG_MAJOR}/extension/tds_fdw* \ + /share/extension/ + +# System libs +COPY --from=builder /system /system/ + +USER 65532:65532 diff --git a/tds-fdw/README.md b/tds-fdw/README.md new file mode 100644 index 0000000..81547c6 --- /dev/null +++ b/tds-fdw/README.md @@ -0,0 +1,89 @@ +# TDS-FDW + +[TDS-FDW](https://github.com/tds-fdw/tds-fdw/) is a PostgreSQL foreign data +wrapper to connect to TDS databases (Sybase and Microsoft SQL Server). + +This image provides a convenient way to deploy and manage `tds-fdw` with +[CloudNativePG](https://cloudnative-pg.io/). + +## Usage + +### 1. Add the tds-fdw extension image to your Cluster + +Define the `tds-fdw` extension under the `postgresql.extensions` section of +your `Cluster` resource. For example: + +```yaml +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: cluster-tds-fdw +spec: + imageName: ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie + instances: 1 + + storage: + size: 1Gi + + postgresql: + extensions: + - name: tds-fdw + image: + # renovate: suite=trixie-pgdg depName=postgresql-18-tds-fdw + reference: ghcr.io/cloudnative-pg/tds-fdw-extension:3.6.2-18-trixie + ld_library_path: + - system + # Requires CloudNativePG 1.29 (or higher) + env: + - name: GDAL_DATA + value: ${image_root}/share/gdal + - name: PROJ_DATA + value: ${image_root}/share/proj +``` + +### 2. Enable the extension in a database + +You can install `tds-fdw` 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-tds-fdw-app +spec: + name: app + owner: app + cluster: + name: cluster-tds-fdw + extensions: + - name: tds-fdw + # renovate: suite=trixie-pgdg depName=postgresql-18-tds-fdw extractVersion=^(?\d+\.\d+\.\d+) + version: '2.0.5' +``` + +### 3. Verify installation + +Once the database is ready, connect to it with `psql` and run: + +```sql +\dx +``` + +You should see `tds_fdw` listed among the installed extensions. + + +### 4. Verify OS dependencies are properly satisfied + +TDS-FDW requires several OS dependencies that are being provided via the `system` directory. +CloudNativePG makes them available to PostgreSQL by adding the directory to LD_LIBRARY_PATH for the PostgreSQL process. + +To verify that all tds_fdw shared libraries requirements are being properly satisfied, +connect to the container and run: + +```bash +cd /extensions/tds_fdw/lib +LD_LIBRARY_PATH=/extensions/tds_fdw/system ldd tds_fdw* +``` + +Make sure there are no missing shared libraries. diff --git a/tds-fdw/metadata.hcl b/tds-fdw/metadata.hcl new file mode 100644 index 0000000..abb2a45 --- /dev/null +++ b/tds-fdw/metadata.hcl @@ -0,0 +1,47 @@ +metadata = { + name = "tds-fdw" + sql_name = "tds_fdw" + image_name = "tds-fdw-extension" + licenses = [ "GPL-2.0-or-later", "MIT", "LGPL-2.1-or-later", + "GPL-3.0-or-later", "Apache-2.0", "PostgreSQL", "Zlib" ] + shared_preload_libraries = [] + postgresql_parameters = {} + extension_control_path = [] + dynamic_library_path = [] + ld_library_path = ["system"] + bin_path = [] + env = { + "GDAL_DATA" = "$${image_root}/share/gdal", + "PROJ_DATA" = "$${image_root}/share/proj", + } + auto_update_os_libs = true + required_extensions = [] + create_extension = true + + versions = { + bookworm = { + "18" = { + // renovate: suite=bookworm-pgdg depName=postgresql-18-tds-fdw + package = "2.0.5-1.pgdg12+1" + // renovate: suite=bookworm-pgdg depName=postgresql-18-tds-fdw extractVersion=^(?\d+\.\d+\.\d+) + sql = "2.0.5" + } + } + trixie = { + "18" = { + // renovate: suite=trixie-pgdg depName=postgresql-18-tds-fdw + package = "2.0.5-1.pgdg13+1" + // renovate: suite=trixie-pgdg depName=postgresql-18-tds-fdw extractVersion=^(?\d+\.\d+\.\d+) + sql = "2.0.5" + } + } + } +} + +target "default" { + name = "${metadata.name}-${sanitize(getExtensionVersion(distro, pgVersion))}-${pgVersion}-${distro}" + matrix = { + pgVersion = pgVersions + distro = distributions + } +} diff --git a/tds-fdw/system-libs/18-bookworm-os-libs.txt b/tds-fdw/system-libs/18-bookworm-os-libs.txt new file mode 100644 index 0000000..e25d61a --- /dev/null +++ b/tds-fdw/system-libs/18-bookworm-os-libs.txt @@ -0,0 +1,2 @@ +freetds-common_1.3.17+ds-2_all.deb MD5Sum:cf0b6f1497041544e07c2811f436184c +libsybdb5_1.3.17+ds-2_amd64.deb MD5Sum:239206783945be0f1c7f97c19cd46ff8 diff --git a/tds-fdw/system-libs/18-trixie-os-libs.txt b/tds-fdw/system-libs/18-trixie-os-libs.txt new file mode 100644 index 0000000..a57a28e --- /dev/null +++ b/tds-fdw/system-libs/18-trixie-os-libs.txt @@ -0,0 +1,2 @@ +freetds-common_1.3.17+ds-2+deb13u1_all.deb MD5Sum:36e923199e94040883f33ea90f07f558 +libsybdb5_1.3.17+ds-2+deb13u1_amd64.deb MD5Sum:6b3f1f9d9362f7f5e7f0a1eef8cdb4df