Skip to content

Commit 615752f

Browse files
committed
feat: multiple versions for the pgjwt extension
Build multiple versions of the pgjwt extension on different PostgreSQL versions. Add test for the extensions and their upgrade on PostgreSQL 15 and 17.
1 parent 4b77682 commit 615752f

File tree

4 files changed

+235
-25
lines changed

4 files changed

+235
-25
lines changed

flake.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,6 +1383,8 @@
13831383
inherit (basePackages) wal-g-2 wal-g-3;
13841384
} // pkgs.lib.optionalAttrs (system == "aarch64-linux") {
13851385
inherit (basePackages) postgresql_15_debug postgresql_15_src postgresql_orioledb-17_debug postgresql_orioledb-17_src postgresql_17_debug postgresql_17_src;
1386+
} // pkgs.lib.optionalAttrs (system == "x86_64-linux") {
1387+
pgjwt = import ./nix/ext/tests/pgjwt.nix { inherit self; inherit pkgs; };
13861388
};
13871389

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

nix/ext/pgjwt.nix

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,78 @@
1-
{ lib, stdenv, fetchFromGitHub, postgresql, unstableGitUpdater }:
2-
3-
stdenv.mkDerivation rec {
1+
{ pkgs, lib, stdenv, fetchFromGitHub, postgresql, unstableGitUpdater }:
2+
let
43
pname = "pgjwt";
5-
version = "9742dab1b2f297ad3811120db7b21451bca2d3c9";
4+
allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname};
5+
supportedVersions = lib.filterAttrs (
6+
_: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql
7+
) allVersions;
8+
versions = lib.naturalSort (lib.attrNames supportedVersions);
9+
latestVersion = lib.last versions;
10+
numberOfVersions = builtins.trace "Versions: ${toString (builtins.length versions)}" (builtins.length versions);
11+
build =
12+
version: hash: revision:
13+
stdenv.mkDerivation {
14+
inherit pname version;
615

7-
src = fetchFromGitHub {
8-
owner = "michelp";
9-
repo = "pgjwt";
10-
rev = "${version}";
11-
hash = "sha256-Hw3R9bMGDmh+dMzjmqZSy/rT4mX8cPU969OJiARFg10=";
12-
};
16+
src = fetchFromGitHub {
17+
owner = "michelp";
18+
repo = "pgjwt";
19+
rev = revision;
20+
inherit hash;
21+
};
22+
23+
dontBuild = true;
24+
installPhase = ''
25+
mkdir -p $out/share/postgresql/extension
26+
create_sql_files() {
27+
echo "Creating SQL files for previous versions..."
28+
if [[ "${version}" == "${latestVersion}" ]]; then
29+
cp *.sql $out/share/postgresql/extension
30+
fi
31+
}
32+
33+
create_control_files() {
34+
sed -e "/^default_version =/d" \
35+
-e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \
36+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
37+
38+
if [[ "${version}" == "${latestVersion}" ]]; then
39+
{
40+
echo "default_version = '${latestVersion}'"
41+
cat $out/share/postgresql/extension/${pname}--${latestVersion}.control
42+
} > $out/share/postgresql/extension/${pname}.control
43+
fi
44+
}
45+
46+
create_sql_files
47+
create_control_files
48+
'';
49+
50+
passthru.updateScript = unstableGitUpdater { };
51+
52+
meta = with lib; {
53+
description = "PostgreSQL implementation of JSON Web Tokens";
54+
longDescription = ''
55+
sign() and verify() functions to create and verify JSON Web Tokens.
56+
'';
57+
license = licenses.mit;
58+
platforms = postgresql.meta.platforms;
59+
};
60+
};
61+
packages = builtins.attrValues (
62+
lib.mapAttrs (name: value: build name value.hash value.revision) supportedVersions
63+
);
64+
in
65+
pkgs.buildEnv {
66+
name = pname;
67+
paths = packages;
68+
pathsToLink = [
69+
"/share/postgresql/extension"
70+
];
1371

14-
dontBuild = true;
15-
installPhase = ''
16-
mkdir -p $out/share/postgresql/extension
17-
cp pg*sql *.control $out/share/postgresql/extension
18-
'';
19-
20-
passthru.updateScript = unstableGitUpdater { };
21-
22-
meta = with lib; {
23-
description = "PostgreSQL implementation of JSON Web Tokens";
24-
longDescription = ''
25-
sign() and verify() functions to create and verify JSON Web Tokens.
26-
'';
27-
license = licenses.mit;
28-
platforms = postgresql.meta.platforms;
72+
passthru = {
73+
inherit versions numberOfVersions;
74+
pname = "${pname}-all";
75+
version =
76+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
2977
};
3078
}

nix/ext/tests/pgjwt.nix

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

nix/ext/versions.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"pgjwt": {
3+
"0.2.0": {
4+
"revision": "f3d82fd30151e754e19ce5d6a06c71c20689ce3d",
5+
"postgresql": [
6+
"15",
7+
"17"
8+
],
9+
"hash": "sha256-nDZEDf5+sFc1HDcG2eBNQj+kGcdAYRXJseKi9oww+JU="
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)