Skip to content

Commit dd54146

Browse files
jfrochesamrose
andauthored
feat: multiple versions for the pgsodium extension (#1660)
* feat: multiple versions for the pgsodium extension Build multiple versions of the pgsodium extension on different PostgreSQL versions. Add test for the extensions and their upgrade on PostgreSQL 15 and 17. * fix: cleanup after rebase * feat: multiversion pgsodium * fix: update package name in test * chore: bump version for release --------- Co-authored-by: Sam Rose <[email protected]> Co-authored-by: samrose <[email protected]>
1 parent c6002c4 commit dd54146

File tree

4 files changed

+293
-28
lines changed

4 files changed

+293
-28
lines changed

ansible/vars.yml

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

1010
# Full version strings for each major version
1111
postgres_release:
12-
postgresorioledb-17: "17.5.1.028-orioledb"
13-
postgres17: "17.6.1.007"
14-
postgres15: "15.14.1.007"
12+
postgresorioledb-17: "17.5.1.029"
13+
postgres17: "17.6.1.008"
14+
postgres15: "15.14.1.008"
1515

1616
# Non Postgres Extensions
1717
pgbouncer_release: "1.19.0"

nix/ext/pgsodium.nix

Lines changed: 94 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,109 @@
11
{
2+
pkgs,
23
lib,
34
stdenv,
45
fetchFromGitHub,
5-
libsodium,
66
postgresql,
7+
libsodium,
78
}:
8-
9-
stdenv.mkDerivation rec {
9+
let
1010
pname = "pgsodium";
11-
version = "3.1.8";
1211

13-
buildInputs = [
14-
libsodium
15-
postgresql
16-
];
12+
# Load version configuration from external file
13+
allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname};
1714

18-
src = fetchFromGitHub {
19-
owner = "michelp";
20-
repo = pname;
21-
rev = "refs/tags/v${version}";
22-
hash = "sha256-j5F1PPdwfQRbV8XJ8Mloi8FvZF0MTl4eyIJcBYQy1E4=";
23-
};
15+
# Filter versions compatible with current PostgreSQL version
16+
supportedVersions = lib.filterAttrs (
17+
_: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql
18+
) allVersions;
19+
20+
# Derived version information
21+
versions = lib.naturalSort (lib.attrNames supportedVersions);
22+
latestVersion = lib.last versions;
23+
numberOfVersions = builtins.length versions;
24+
packages = builtins.attrValues (
25+
lib.mapAttrs (name: value: build name value.hash) supportedVersions
26+
);
27+
28+
# Build function for individual pgsodium versions
29+
build =
30+
version: hash:
31+
stdenv.mkDerivation rec {
32+
inherit pname version;
33+
34+
buildInputs = [
35+
libsodium
36+
postgresql
37+
];
38+
39+
src = fetchFromGitHub {
40+
owner = "michelp";
41+
repo = pname;
42+
rev = "refs/tags/v${version}";
43+
inherit hash;
44+
};
45+
46+
installPhase = ''
47+
runHook preInstall
48+
49+
mkdir -p $out/{lib,share/postgresql/extension}
50+
51+
# Install shared library with version suffix
52+
mv ${pname}${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix}
53+
54+
# Create version-specific control file
55+
sed -e "/^default_version =/d" \
56+
-e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \
57+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
58+
59+
# For the latest version, create default control file and symlink
60+
if [[ "${version}" == "${latestVersion}" ]]; then
61+
# sql/pgsodium--3.1.5--3.1.6.sql isn't a proper upgrade sql file
62+
cp sql/pgsodium--3.1.4--3.1.5.sql sql/pgsodium--3.1.5--3.1.6.sql
63+
cp sql/*.sql $out/share/postgresql/extension
64+
{
65+
echo "default_version = '${latestVersion}'"
66+
cat $out/share/postgresql/extension/${pname}--${latestVersion}.control
67+
} > $out/share/postgresql/extension/${pname}.control
68+
ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
69+
fi
70+
71+
runHook postInstall
72+
'';
73+
74+
meta = with lib; {
75+
description = "Modern cryptography for PostgreSQL";
76+
homepage = "https://github.com/michelp/${pname}";
77+
platforms = postgresql.meta.platforms;
78+
license = licenses.postgresql;
79+
};
80+
};
81+
in
82+
pkgs.buildEnv {
83+
name = pname;
84+
paths = packages;
85+
pathsToLink = [
86+
"/lib"
87+
"/share/postgresql/extension"
88+
];
2489

25-
installPhase = ''
26-
mkdir -p $out/{lib,share/postgresql/extension}
90+
postBuild = ''
91+
# Verify all expected library files are present
92+
expectedFiles=${toString (numberOfVersions + 1)}
93+
actualFiles=$(ls -A $out/lib/${pname}*${postgresql.dlSuffix} | wc -l)
2794
28-
cp *${postgresql.dlSuffix} $out/lib
29-
cp sql/*.sql $out/share/postgresql/extension
30-
cp *.control $out/share/postgresql/extension
95+
if [[ "$actualFiles" != "$expectedFiles" ]]; then
96+
echo "Error: Expected $expectedFiles library files, found $actualFiles"
97+
echo "Files found:"
98+
ls -la $out/lib/${pname}*${postgresql.dlSuffix} || true
99+
exit 1
100+
fi
31101
'';
32102

33-
meta = with lib; {
34-
description = "Modern cryptography for PostgreSQL";
35-
homepage = "https://github.com/michelp/${pname}";
36-
platforms = postgresql.meta.platforms;
37-
license = licenses.postgresql;
103+
passthru = {
104+
inherit versions numberOfVersions;
105+
pname = "${pname}-all";
106+
version =
107+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
38108
};
39109
}

nix/ext/tests/pgsodium.nix

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
{ self, pkgs }:
2+
let
3+
pname = "pgsodium";
4+
inherit (pkgs) lib;
5+
installedExtension =
6+
postgresMajorVersion: self.packages.${pkgs.system}."psql_${postgresMajorVersion}/exts/${pname}-all";
7+
versions = postgresqlMajorVersion: (installedExtension postgresqlMajorVersion).versions;
8+
postgresqlWithExtension =
9+
postgresql:
10+
let
11+
majorVersion = lib.versions.major postgresql.version;
12+
pkg = pkgs.buildEnv {
13+
name = "postgresql-${majorVersion}-${pname}";
14+
paths = [
15+
postgresql
16+
postgresql.lib
17+
(installedExtension majorVersion)
18+
self.packages.${pkgs.system}."psql_${majorVersion}/exts/hypopg-all"
19+
];
20+
passthru = {
21+
inherit (postgresql) version psqlSchema;
22+
lib = pkg;
23+
withPackages = _: pkg;
24+
};
25+
nativeBuildInputs = [ pkgs.makeWrapper ];
26+
pathsToLink = [
27+
"/"
28+
"/bin"
29+
"/lib"
30+
];
31+
postBuild = ''
32+
wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
33+
wrapProgram $out/bin/pg_ctl --set NIX_PGLIBDIR $out/lib
34+
wrapProgram $out/bin/pg_upgrade --set NIX_PGLIBDIR $out/lib
35+
'';
36+
};
37+
in
38+
pkg;
39+
pgsodiumGetKey = lib.getExe (
40+
pkgs.writeShellScriptBin "pgsodium-getkey" ''
41+
echo 0000000000000000000000000000000000000000000000000000000000000000
42+
''
43+
);
44+
in
45+
self.inputs.nixpkgs.lib.nixos.runTest {
46+
name = pname;
47+
hostPkgs = pkgs;
48+
nodes.server =
49+
{ config, ... }:
50+
{
51+
virtualisation = {
52+
forwardPorts = [
53+
{
54+
from = "host";
55+
host.port = 13022;
56+
guest.port = 22;
57+
}
58+
];
59+
};
60+
61+
services.postgresql = {
62+
enable = true;
63+
package = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15;
64+
settings = {
65+
"shared_preload_libraries" = pname;
66+
"pgsodium.getkey_script" = pgsodiumGetKey;
67+
};
68+
};
69+
70+
specialisation.postgresql17.configuration = {
71+
services.postgresql = {
72+
package = lib.mkForce (postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17);
73+
};
74+
75+
systemd.services.postgresql-migrate = {
76+
serviceConfig = {
77+
Type = "oneshot";
78+
RemainAfterExit = true;
79+
User = "postgres";
80+
Group = "postgres";
81+
StateDirectory = "postgresql";
82+
WorkingDirectory = "${builtins.dirOf config.services.postgresql.dataDir}";
83+
};
84+
script =
85+
let
86+
oldPostgresql = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15;
87+
newPostgresql = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17;
88+
oldDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${oldPostgresql.psqlSchema}";
89+
newDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${newPostgresql.psqlSchema}";
90+
in
91+
''
92+
if [[ ! -d ${newDataDir} ]]; then
93+
install -d -m 0700 -o postgres -g postgres "${newDataDir}"
94+
${newPostgresql}/bin/initdb -D "${newDataDir}"
95+
echo "shared_preload_libraries = '${pname}'" >> "${newDataDir}/postgresql.conf"
96+
echo "pgsodium.getkey_script = '${pgsodiumGetKey}'" >> "${newDataDir}/postgresql.conf";
97+
${newPostgresql}/bin/pg_upgrade --old-datadir "${oldDataDir}" --new-datadir "${newDataDir}" \
98+
--old-bindir "${oldPostgresql}/bin" --new-bindir "${newPostgresql}/bin"
99+
else
100+
echo "${newDataDir} already exists"
101+
fi
102+
'';
103+
};
104+
105+
systemd.services.postgresql = {
106+
after = [ "postgresql-migrate.service" ];
107+
requires = [ "postgresql-migrate.service" ];
108+
};
109+
};
110+
};
111+
testScript =
112+
{ nodes, ... }:
113+
let
114+
pg17-configuration = "${nodes.server.system.build.toplevel}/specialisation/postgresql17";
115+
in
116+
''
117+
versions = {
118+
"15": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "15"))}],
119+
"17": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "17"))}],
120+
}
121+
122+
def run_sql(query):
123+
return server.succeed(f"""sudo -u postgres psql -t -A -F\",\" -c \"{query}\" """).strip()
124+
125+
def check_upgrade_path(pg_version):
126+
with subtest("Check ${pname} upgrade path"):
127+
firstVersion = versions[pg_version][0]
128+
server.succeed("sudo -u postgres psql -c 'DROP EXTENSION IF EXISTS ${pname};'")
129+
run_sql(f"""CREATE EXTENSION ${pname} WITH VERSION '{firstVersion}' CASCADE;""")
130+
installed_version = run_sql(r"""SELECT extversion FROM pg_extension WHERE extname = '${pname}';""")
131+
assert installed_version == firstVersion, f"Expected ${pname} version {firstVersion}, but found {installed_version}"
132+
for version in versions[pg_version][1:]:
133+
run_sql(f"""ALTER EXTENSION ${pname} UPDATE TO '{version}';""")
134+
installed_version = run_sql(r"""SELECT extversion FROM pg_extension WHERE extname = '${pname}';""")
135+
assert installed_version == version, f"Expected ${pname} version {version}, but found {installed_version}"
136+
137+
start_all()
138+
139+
server.wait_for_unit("multi-user.target")
140+
server.wait_for_unit("postgresql.service")
141+
142+
check_upgrade_path("15")
143+
144+
with subtest("Check ${pname} latest extension version"):
145+
server.succeed("sudo -u postgres psql -c 'DROP EXTENSION ${pname};'")
146+
server.succeed("sudo -u postgres psql -c 'CREATE EXTENSION ${pname} CASCADE;'")
147+
installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension;""")
148+
latestVersion = versions["15"][-1]
149+
assert f"${pname},{latestVersion}" in installed_extensions
150+
151+
with subtest("switch to postgresql 17"):
152+
server.succeed(
153+
"${pg17-configuration}/bin/switch-to-configuration test >&2"
154+
)
155+
156+
check_upgrade_path("17")
157+
'';
158+
}

nix/ext/versions.json

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,44 @@
131131
"hash": "sha256-Cpi2iASi1QJoED0Qs1dANqg/BNZTsz5S+pw8iYyW03Y="
132132
}
133133
},
134-
"rum": {
134+
"pgsodium": {
135+
"3.0.4": {
136+
"postgresql": [
137+
"15",
138+
"17"
139+
],
140+
"hash": "sha256-GbUUkSbQe05x7JssSyCdMrP6Uk9ix0JmO+JB1MsFMSg="
141+
},
142+
"3.1.5": {
143+
"postgresql": [
144+
"15",
145+
"17"
146+
],
147+
"hash": "sha256-Rv7y0gPEDHeZ+KLD+M/pUQI8Ye5GdaV144Xq05z29Sk="
148+
},
149+
"3.1.6": {
150+
"postgresql": [
151+
"15",
152+
"17"
153+
],
154+
"hash": "sha256-D07r/yF50JNihvG/0X7R+1bXnlK1z0dt+/Xbic6W1Hs="
155+
},
156+
"3.1.7": {
157+
"postgresql": [
158+
"15",
159+
"17"
160+
],
161+
"hash": "sha256-0QOh21kKtoM1L38pvkVumr4dyMdINaaMLI6z1RE8540="
162+
},
163+
"3.1.8": {
164+
"postgresql": [
165+
"15",
166+
"17"
167+
],
168+
"hash": "sha256-j5F1PPdwfQRbV8XJ8Mloi8FvZF0MTl4eyIJcBYQy1E4="
169+
}
170+
},
171+
"rum": {
135172
"1.3": {
136173
"postgresql": [
137174
"15",

0 commit comments

Comments
 (0)