Skip to content

Commit 1be8e77

Browse files
committed
feat: multiple versions for the pg_tle extension
Build multiple versions of the pg_tle extension on different PostgreSQL versions. Add test for the extensions and their upgrade on PostgreSQL 15 and 17.
1 parent a3e960f commit 1be8e77

File tree

5 files changed

+293
-25
lines changed

5 files changed

+293
-25
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ __pycache__/
1717
result*
1818
.env-local
1919
.history
20+
.nixos-test-history
2021

2122

2223
#IDE

flake.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,7 @@
13811381
psql_15 = makeCheckHarness basePackages.psql_15.bin;
13821382
psql_17 = makeCheckHarness basePackages.psql_17.bin;
13831383
psql_orioledb-17 = makeCheckHarness basePackages.psql_orioledb-17.bin;
1384+
pg_tle = import ./nix/tests/pg_tle.nix { inherit self; inherit pkgs; };
13841385
};
13851386

13861387
# Apps is a list of names of things that can be executed with 'nix run';

nix/ext/pg_tle.nix

Lines changed: 98 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,108 @@
1-
{ lib, stdenv, fetchFromGitHub, postgresql, flex, openssl, libkrb5 }:
2-
3-
stdenv.mkDerivation rec {
1+
{
2+
pkgs,
3+
lib,
4+
stdenv,
5+
fetchFromGitHub,
6+
postgresql,
7+
flex,
8+
openssl,
9+
libkrb5,
10+
}:
11+
let
412
pname = "pg_tle";
5-
version = "1.4.0";
13+
build =
14+
version: hash:
15+
stdenv.mkDerivation rec {
16+
inherit pname version;
617

7-
nativeBuildInputs = [ flex ];
8-
buildInputs = [ openssl postgresql libkrb5 ];
18+
nativeBuildInputs = [ flex ];
19+
buildInputs = [
20+
openssl
21+
postgresql
22+
libkrb5
23+
];
924

10-
src = fetchFromGitHub {
11-
owner = "aws";
12-
repo = pname;
13-
rev = "refs/tags/v${version}";
14-
hash = "sha256-crxj5R9jblIv0h8lpqddAoYe2UqgUlnvbOajKTzVces=";
15-
};
25+
src = fetchFromGitHub {
26+
owner = "aws";
27+
repo = pname;
28+
rev = "refs/tags/v${version}";
29+
inherit hash;
30+
};
31+
32+
makeFlags = [ "FLEX=flex" ];
33+
34+
installPhase = ''
35+
36+
mkdir -p $out/{lib,share/postgresql/extension}
37+
38+
mv ${pname}${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix}
39+
40+
create_sql_files() {
41+
if test -f ${pname}--${version}.sql; then
42+
cp ${pname}--${version}.sql $out/share/postgresql/extension
43+
fi
44+
echo "Creating SQL files for previous versions..."
45+
if [[ "${version}" == "${latestVersion}" ]]; then
46+
cp *.sql $out/share/postgresql/extension
47+
fi
48+
}
49+
50+
create_control_files() {
51+
sed -e "/^default_version =/d" \
52+
-e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \
53+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
1654
17-
18-
makeFlags = [ "FLEX=flex" ];
55+
if [[ "${version}" == "${latestVersion}" ]]; then
56+
{
57+
echo "default_version = '${latestVersion}'"
58+
cat $out/share/postgresql/extension/${pname}--${latestVersion}.control
59+
} > $out/share/postgresql/extension/${pname}.control
60+
ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
61+
fi
62+
}
1963
20-
21-
installPhase = ''
22-
mkdir -p $out/{lib,share/postgresql/extension}
64+
create_sql_files
65+
create_control_files
66+
'';
2367

24-
cp *${postgresql.dlSuffix} $out/lib
25-
cp *.sql $out/share/postgresql/extension
26-
cp *.control $out/share/postgresql/extension
68+
meta = with lib; {
69+
description = "Framework for 'Trusted Language Extensions' in PostgreSQL";
70+
homepage = "https://github.com/aws/${pname}";
71+
license = licenses.postgresql;
72+
inherit (postgresql.meta) platforms;
73+
};
74+
};
75+
allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname};
76+
supportedVersions = lib.filterAttrs (
77+
_: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql
78+
) allVersions;
79+
versions = lib.naturalSort (lib.attrNames supportedVersions);
80+
latestVersion = lib.last versions;
81+
numberOfVersions = builtins.length versions;
82+
packages = builtins.attrValues (
83+
lib.mapAttrs (name: value: build name value.hash) supportedVersions
84+
);
85+
in
86+
pkgs.buildEnv {
87+
name = pname;
88+
paths = packages;
89+
pathsToLink = [
90+
"/lib"
91+
"/share/postgresql/extension"
92+
];
93+
postBuild = ''
94+
# checks
95+
(set -x
96+
test "$(ls -A $out/lib/${pname}*${postgresql.dlSuffix} | wc -l)" = "${
97+
toString (numberOfVersions + 1)
98+
}"
99+
)
27100
'';
28101

29-
meta = with lib; {
30-
description = "Framework for 'Trusted Language Extensions' in PostgreSQL";
31-
homepage = "https://github.com/aws/${pname}";
32-
platforms = postgresql.meta.platforms;
33-
license = licenses.postgresql;
102+
passthru = {
103+
inherit versions numberOfVersions;
104+
pname = "${pname}-all";
105+
version =
106+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
34107
};
35108
}

nix/ext/versions.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"pg_tle": {
3+
"1.0.1": {
4+
"postgresql": [
5+
"15"
6+
],
7+
"hash": "sha256-yAe37nIgObjs0kZY1A0QBGMP/s45sC1HVRwxVRaXwXs="
8+
},
9+
"1.0.4": {
10+
"postgresql": [
11+
"15",
12+
"17"
13+
],
14+
"hash": "sha256-W/7pLy/27VatCdzUh1NZ4K2FRMD1erfHiFV2eY2x2W0="
15+
},
16+
"1.3.0": {
17+
"postgresql": [
18+
"15",
19+
"17"
20+
],
21+
"hash": "sha256-Q4D4+eYPBONd8IKlDVfQa8wI4PJyKHkMPPqONqEWFLE="
22+
},
23+
"1.4.0": {
24+
"postgresql": [
25+
"15",
26+
"17"
27+
],
28+
"hash": "sha256-crxj5R9jblIv0h8lpqddAoYe2UqgUlnvbOajKTzVces="
29+
}
30+
}
31+
}

nix/tests/pg_tle.nix

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

0 commit comments

Comments
 (0)