Skip to content

Commit 704e04e

Browse files
jfrochesamrose
andauthored
feat: support multiple versions of the pgaudit extension (#1758)
* feat: multiple versions for the pgaudit extension Build multiple versions of the pgaudit extension on different PostgreSQL versions. Add test for the extensions and their upgrade on PostgreSQL 15 and 17. * chore: add release suffix for testing * feat: include migrations on newer version, for all previous * fix: postgres integration tests * fix: strip suffix on passthru * fix: just use the the name * fix: try without list * Fix pgaudit upgrade * fix: migration handling --------- Co-authored-by: Sam Rose <[email protected]>
1 parent d91e4d1 commit 704e04e

File tree

4 files changed

+266
-45
lines changed

4 files changed

+266
-45
lines changed

ansible/vars.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ postgres_major:
1010

1111
# Full version strings for each major version
1212
postgres_release:
13-
postgresorioledb-17: "17.5.1.060-orioledb"
14-
postgres17: "17.6.1.039"
15-
postgres15: "15.14.1.039"
13+
postgresorioledb-17: "17.5.1.061-orioledb"
14+
postgres17: "17.6.1.040"
15+
postgres15: "15.14.1.040"
1616

1717
# Non Postgres Extensions
1818
pgbouncer_release: 1.19.0

nix/ext/pgaudit.nix

Lines changed: 221 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,242 @@
11
{
22
lib,
33
stdenv,
4+
buildEnv,
45
fetchFromGitHub,
56
libkrb5,
67
openssl,
78
postgresql,
89
}:
910
#adapted from https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/sql/postgresql/ext/pgaudit.nix
1011
let
11-
source =
12-
{
13-
"17" = {
14-
version = "17.0";
15-
hash = "sha256-3ksq09wiudQPuBQI3dhEQi8IkXKLVIsPFgBnwLiicro=";
16-
};
17-
"16" = {
18-
version = "16.0";
19-
hash = "sha256-8+tGOl1U5y9Zgu+9O5UDDE4bec4B0JC/BQ6GLhHzQzc=";
12+
pname = "pgaudit";
13+
# Load version configuration from external file
14+
allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname};
15+
16+
# Filter versions compatible with current PostgreSQL version (these get libraries)
17+
supportedVersions = lib.filterAttrs (
18+
_: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql
19+
) allVersions;
20+
21+
# Derived version information
22+
# All versions sorted (for SQL migration files)
23+
allVersionsList = lib.naturalSort (lib.attrNames allVersions);
24+
# Supported versions sorted (for libraries)
25+
versions = lib.naturalSort (lib.attrNames supportedVersions);
26+
latestVersion = lib.last versions;
27+
numberOfVersions = builtins.length versions;
28+
29+
# Build packages only for supported versions (with libraries)
30+
packages = builtins.attrValues (
31+
lib.mapAttrs (name: value: build name value.hash) supportedVersions
32+
);
33+
34+
# Helper function to generate migration SQL file pairs
35+
# Returns a list of {from, to} pairs for sequential migrations
36+
generateMigrationPairs =
37+
versions:
38+
let
39+
indexed = lib.imap0 (i: v: {
40+
idx = i;
41+
version = v;
42+
}) versions;
43+
pairs = lib.filter (x: x.idx > 0) indexed;
44+
in
45+
map (curr: {
46+
from = (lib.elemAt versions (curr.idx - 1));
47+
to = curr.version;
48+
}) pairs;
49+
50+
# All migration pairs across all versions (sequential)
51+
allMigrationPairs = generateMigrationPairs allVersionsList;
52+
53+
# Get the first supported version for this PG major
54+
firstSupportedVersion = lib.head versions;
55+
56+
# Generate bridge migrations from unsupported versions to first supported version
57+
# These are needed when upgrading PostgreSQL major versions
58+
# Only include versions that come BEFORE the first supported version (no backwards migrations)
59+
unsupportedVersions = lib.filter (
60+
v: !(builtins.elem v versions) && (lib.versionOlder v firstSupportedVersion)
61+
) allVersionsList;
62+
bridgeMigrations = map (v: {
63+
from = v;
64+
to = firstSupportedVersion;
65+
}) unsupportedVersions;
66+
67+
# Build function for individual pgaudit versions
68+
build =
69+
version: hash:
70+
stdenv.mkDerivation {
71+
inherit pname version;
72+
73+
src = fetchFromGitHub {
74+
owner = "pgaudit";
75+
repo = "pgaudit";
76+
rev = version;
77+
inherit hash;
2078
};
21-
"15" = {
22-
version = "1.7.0";
23-
hash = "sha256-8pShPr4HJaJQPjW1iPJIpj3CutTx8Tgr+rOqoXtgCcw=";
79+
80+
buildInputs = [
81+
libkrb5
82+
openssl
83+
postgresql
84+
];
85+
86+
makeFlags = [ "USE_PGXS=1" ];
87+
88+
postBuild =
89+
lib.optionalString (version == "1.7.0") ''
90+
mv ${pname}--1.7.sql ${pname}--1.7.0.sql
91+
cp ${pname}--1.7.0.sql ${pname}--1.6.1--1.7.0.sql
92+
''
93+
+ lib.optionalString (version == "1.7.1") ''
94+
mv ${pname}--1.7--1.7.1.sql ${pname}--1.7.0--1.7.1.sql
95+
'';
96+
97+
installPhase = ''
98+
runHook preInstall
99+
100+
mkdir -p $out/{lib,share/postgresql/extension}
101+
102+
# Extract the actual default_version from the control file
103+
# This is what PostgreSQL will record in pg_extension, not necessarily the git tag
104+
controlVersion=$(grep "^default_version" ${pname}.control | sed "s/default_version = '\(.*\)'/\1/")
105+
echo "$controlVersion" > $out/control_version
106+
107+
# Install shared library with version suffix
108+
mv ${pname}${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix}
109+
110+
# Install SQL files with modifications
111+
sed -i '1s/^/DROP EVENT TRIGGER IF EXISTS pgaudit_ddl_command_end; \n/' *.sql
112+
sed -i '1s/^/DROP EVENT TRIGGER IF EXISTS pgaudit_sql_drop; \n/' *.sql
113+
sed -i 's/CREATE FUNCTION/CREATE OR REPLACE FUNCTION/' *.sql
114+
cp *.sql $out/share/postgresql/extension
115+
116+
# Create version-specific control file pointing to versioned library
117+
sed -e "/^default_version =/d" \
118+
-e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \
119+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
120+
121+
runHook postInstall
122+
'';
123+
124+
meta = with lib; {
125+
description = "Open Source PostgreSQL Audit Logging";
126+
homepage = "https://github.com/pgaudit/pgaudit";
127+
changelog = "https://github.com/pgaudit/pgaudit/releases/tag/${source.version}";
128+
license = licenses.postgresql;
129+
inherit (postgresql.meta) platforms;
24130
};
25-
}
26-
.${lib.versions.major postgresql.version}
27-
or (throw "Source for pgaudit is not available for ${postgresql.version}");
131+
};
28132
in
29-
stdenv.mkDerivation {
30-
pname = "pgaudit";
31-
inherit (source) version;
133+
buildEnv {
134+
name = pname;
135+
paths = packages;
136+
pathsToLink = [
137+
"/lib"
138+
"/share/postgresql/extension"
139+
];
140+
postBuild = ''
141+
# Create symlinks to latest version for library and control file
142+
ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
32143
33-
src = fetchFromGitHub {
34-
owner = "pgaudit";
35-
repo = "pgaudit";
36-
rev = source.version;
37-
hash = source.hash;
38-
};
144+
# Create default control file pointing to latest
145+
{
146+
echo "default_version = '${latestVersion}'"
147+
cat $out/share/postgresql/extension/${pname}--${latestVersion}.control
148+
} > $out/share/postgresql/extension/${pname}.control
39149
40-
buildInputs = [
41-
libkrb5
42-
openssl
43-
postgresql
44-
];
150+
# Generate cross-version migration SQL files
151+
# For each migration pair, if the target version's base SQL exists but we haven't
152+
# built that version (no library), we need to create migration files to bridge from
153+
# older versions to the first available version on this PG major
154+
${lib.concatMapStringsSep "\n" (pair: ''
155+
# Check if we need to create migration ${pair.from}--${pair.to}.sql
156+
if [[ ! -f "$out/share/postgresql/extension/${pname}--${pair.from}--${pair.to}.sql" ]]; then
157+
# If the target SQL file exists, create the migration by copying it
158+
if [[ -f "$out/share/postgresql/extension/${pname}--${pair.to}.sql" ]]; then
159+
cp "$out/share/postgresql/extension/${pname}--${pair.to}.sql" \
160+
"$out/share/postgresql/extension/${pname}--${pair.from}--${pair.to}.sql"
161+
fi
162+
fi
163+
'') allMigrationPairs}
164+
165+
# Generate bridge migrations from unsupported versions to first supported version
166+
# This handles cross-PostgreSQL-major-version upgrades
167+
${lib.concatMapStringsSep "\n" (pair: ''
168+
# Create bridge migration ${pair.from}--${pair.to}.sql if not already present
169+
if [[ ! -f "$out/share/postgresql/extension/${pname}--${pair.from}--${pair.to}.sql" ]]; then
170+
# The bridge migration is just a copy of the target version's base SQL
171+
if [[ -f "$out/share/postgresql/extension/${pname}--${pair.to}.sql" ]]; then
172+
cp "$out/share/postgresql/extension/${pname}--${pair.to}.sql" \
173+
"$out/share/postgresql/extension/${pname}--${pair.from}--${pair.to}.sql"
174+
fi
175+
fi
176+
'') bridgeMigrations}
177+
178+
# Read actual control file versions from each built package
179+
# This handles cases where git tag differs from control file default_version
180+
# (e.g., git tag 1.7.0 but control file says default_version = '1.7')
181+
${lib.concatMapStringsSep "\n" (pkg: ''
182+
if [[ -f "${pkg}/control_version" ]]; then
183+
controlVer=$(cat "${pkg}/control_version")
184+
echo "Found control version: $controlVer from package ${pkg}"
185+
186+
# Create migrations from control version to all supported versions on this PG major
187+
${
188+
lib.concatMapStringsSep "\n" (targetVer: ''
189+
# Skip if control version equals target version
190+
if [[ "$controlVer" != "${targetVer}" ]]; then
191+
# Skip if migration already exists
192+
if [[ ! -f "$out/share/postgresql/extension/${pname}--$controlVer--${targetVer}.sql" ]]; then
193+
# Create symlink to migration if target SQL exists
194+
if [[ -f "$out/share/postgresql/extension/${pname}--${targetVer}.sql" ]]; then
195+
echo "Creating migration symlink from control version $controlVer to ${targetVer}"
196+
ln -s "$out/share/postgresql/extension/${pname}--${targetVer}.sql" \
197+
"$out/share/postgresql/extension/${pname}--$controlVer--${targetVer}.sql"
198+
fi
199+
fi
200+
fi
201+
'') versions
202+
}
203+
fi
204+
'') packages}
205+
206+
# Special cross-major-version handling for pgaudit 1.7
207+
# Upstream pgaudit git tag 1.7.0 has control file with default_version = '1.7'
208+
# Users upgrading from PG 15 to PG 17 will have version 1.7 installed
209+
# We can't read the control file from PG 15 packages when building PG 17,
210+
# so we hardcode this known mismatch
211+
${lib.concatMapStringsSep "\n" (targetVer: ''
212+
if [[ ! -f "$out/share/postgresql/extension/${pname}--1.7--${targetVer}.sql" ]]; then
213+
if [[ -f "$out/share/postgresql/extension/${pname}--${targetVer}.sql" ]]; then
214+
echo "Creating cross-major migration symlink from pgaudit 1.7 to ${targetVer}"
215+
ln -s "$out/share/postgresql/extension/${pname}--${targetVer}.sql" \
216+
"$out/share/postgresql/extension/${pname}--1.7--${targetVer}.sql"
217+
fi
218+
fi
219+
'') versions}
45220
46-
makeFlags = [ "USE_PGXS=1" ];
221+
# Verify all expected library files are present (one per version + symlink)
222+
expectedFiles=${toString (numberOfVersions + 1)}
223+
actualFiles=$(ls -A $out/lib/${pname}*${postgresql.dlSuffix} | wc -l)
47224
48-
installPhase = ''
49-
install -D -t $out/lib pgaudit${postgresql.dlSuffix}
50-
install -D -t $out/share/postgresql/extension *.sql
51-
install -D -t $out/share/postgresql/extension *.control
225+
if [[ "$actualFiles" != "$expectedFiles" ]]; then
226+
echo "Error: Expected $expectedFiles library files, found $actualFiles"
227+
echo "Files found:"
228+
ls -la $out/lib/${pname}*${postgresql.dlSuffix} || true
229+
exit 1
230+
fi
52231
'';
53232

54-
meta = with lib; {
55-
description = "Open Source PostgreSQL Audit Logging";
56-
homepage = "https://github.com/pgaudit/pgaudit";
57-
changelog = "https://github.com/pgaudit/pgaudit/releases/tag/${source.version}";
58-
platforms = postgresql.meta.platforms;
59-
license = licenses.postgresql;
233+
passthru = {
234+
inherit versions numberOfVersions;
235+
pname = "${pname}-all";
236+
version =
237+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
238+
defaultSettings = {
239+
shared_preload_libraries = "pgaudit";
240+
};
60241
};
61242
}

nix/ext/tests/default.nix

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ let
9191
specialisation.postgresql17.configuration = {
9292
services.postgresql = {
9393
package = lib.mkForce psql_17;
94+
settings = (installedExtension "17").defaultSettings or { };
9495
};
9596

9697
systemd.services.postgresql-migrate = {
@@ -114,7 +115,13 @@ let
114115
install -d -m 0700 -o postgres -g postgres "${newDataDir}"
115116
${newPostgresql}/bin/initdb -D "${newDataDir}"
116117
${newPostgresql}/bin/pg_upgrade --old-datadir "${oldDataDir}" --new-datadir "${newDataDir}" \
117-
--old-bindir "${oldPostgresql}/bin" --new-bindir "${newPostgresql}/bin"
118+
--old-bindir "${oldPostgresql}/bin" --new-bindir "${newPostgresql}/bin" \
119+
${
120+
if config.services.postgresql.settings.shared_preload_libraries != null then
121+
" --old-options='-c shared_preload_libraries=${config.services.postgresql.settings.shared_preload_libraries}' --new-options='-c shared_preload_libraries=${config.services.postgresql.settings.shared_preload_libraries}'"
122+
else
123+
""
124+
}
118125
else
119126
echo "${newDataDir} already exists"
120127
fi
@@ -214,6 +221,7 @@ builtins.listToAttrs (
214221
"pg_graphql"
215222
"pg_jsonschema"
216223
"pg_net"
224+
"pgaudit"
217225
"vector"
218226
"wrappers"
219227
]

nix/ext/versions.json

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,39 @@
321321
"hash": "sha256-Cpi2iASi1QJoED0Qs1dANqg/BNZTsz5S+pw8iYyW03Y="
322322
}
323323
},
324-
"pgmq": {
324+
"pgaudit": {
325+
"1.6.1": {
326+
"postgresql": [
327+
"15"
328+
],
329+
"hash": "sha256-vxUDVq7nWkq7Qugy7HJLOXk4B61MSBIYQkzcbU6wSG8="
330+
},
331+
"1.7.0": {
332+
"postgresql": [
333+
"15"
334+
],
335+
"hash": "sha256-8pShPr4HJaJQPjW1iPJIpj3CutTx8Tgr+rOqoXtgCcw="
336+
},
337+
"1.7.1": {
338+
"postgresql": [
339+
"15"
340+
],
341+
"hash": "sha256-emwoTowT7WKFX0RQDqJXjIblrzqaUIUkzqSqBCHVKQ8="
342+
},
343+
"17.0": {
344+
"postgresql": [
345+
"17"
346+
],
347+
"hash": "sha256-3ksq09wiudQPuBQI3dhEQi8IkXKLVIsPFgBnwLiicro="
348+
},
349+
"17.1": {
350+
"postgresql": [
351+
"17"
352+
],
353+
"hash": "sha256-9St/ESPiFq2NiPKqbwHLwkIyATKUkOGxFcUrWgT+Iqo="
354+
}
355+
},
356+
"pgmq": {
325357
"1.4.4": {
326358
"postgresql": [
327359
"15"

0 commit comments

Comments
 (0)