Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion nixos/modules/services/databases/postgresql.nix
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ let

groupAccessAvailable = versionAtLeast postgresql.version "11.0";

upgradeScript = new: old:
assert lib.versionOlder old.package.version new.package.version;
pkgs.writeShellApplication {
name = "upgrade.sh";
runtimeInputs = [];
text = ''
# There is no old version to upgrade from - noop
[[ -d "${old.dataDir}" ]] || exit 0

if [[ -f "${old.dataDir}/.upgraded" ]]; then
echo "Old data dir found, but was already migrated. Please remove the old path '${old.dataDir}' to suppress this message." >&2
exit 0
fi

pushd "${old.dataDir}"
${new.package}/bin/pg_upgrade ${lib.cli.toGNUCommandLineShell {} {
old-datadir = old.dataDir;
new-datadir = new.dataDir;
old-bindir = "${old.package}/bin";
new-bindir = "${new.package}/bin";
}}
popd
touch "${new.dataDir}/.post_upgrade" "${old.dataDir}/.upgraded"
'';
};

in

{
Expand Down Expand Up @@ -269,7 +295,35 @@ in
PostgreSQL superuser account to use for various operations. Internal since changing
this value would lead to breakage while setting up databases.
'';
};
};

upgradeFrom = mkOption {
type = types.listOf (types.submodule {
options = {
package = mkOption {
type = types.package;
description = "Package to upgrade from";
};
dataDir = mkOption {
type = types.str;
example = "/var/lib/postgresql/11";
description = "Usually in format `/var/lib/postgresql/<version>`";
};
};
});
default = [];
description =
"List of postgres versions we support upgrading from";
};

analyzeAfterUpgrade = mkOption {
type = types.bool;
default = true;
description = ''
Will run `vacuumdb --all --analyze-in-stages` after
successful upgrade as postgresql suggests.
'';
};
};

};
Expand Down Expand Up @@ -346,6 +400,12 @@ in
# Initialise the database.
initdb -U ${cfg.superUser} ${concatStringsSep " " cfg.initdbArgs}

${lib.concatMapStrings
(upgrade: let app = upgradeScript cfg upgrade; in ''
${app}/bin/${app.meta.mainProgram}
'')
cfg.upgradeFrom}

# See postStart!
touch "${cfg.dataDir}/.first_startup"
fi
Expand All @@ -368,6 +428,13 @@ in
done

if test -e "${cfg.dataDir}/.first_startup"; then
if test -e "${cfg.dataDir}/.post_upgrade"; then
${optionalString cfg.analyzeAfterUpgrade ''
vacuumdb --port=${toString cfg.port} --all --analyze-in-stages
''}
rm "${cfg.dataDir}/.post_upgrade"
fi

${optionalString (cfg.initialScript != null) ''
$PSQL -f "${cfg.initialScript}" -d postgres
''}
Expand Down
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ in
postfixadmin = handleTest ./postfixadmin.nix {};
postgis = handleTest ./postgis.nix {};
postgresql = handleTest ./postgresql.nix {};
postgresql-upgrade = handleTest ./postgresql-upgrade.nix {};
postgresql-wal-receiver = handleTest ./postgresql-wal-receiver.nix {};
powerdns = handleTest ./powerdns.nix {};
powerdns-admin = handleTest ./powerdns-admin.nix {};
Expand Down
140 changes: 140 additions & 0 deletions nixos/tests/postgresql-upgrade.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{ system ? builtins.currentSystem
, config ? { }
, pkgs ? import ../.. { inherit system config; }
}:

let
lib = pkgs.lib;

inherit (import ../lib/testing-python.nix { inherit system pkgs; })
makeTest;

pgPackages = lib.sort (x: y: lib.versionOlder x.version y.version)
(lib.attrValues (import ../../pkgs/servers/sql/postgresql pkgs));

start = lib.head pgPackages;

end = lib.last pgPackages;

insert = pkgs.writeShellApplication {
name = "insert";
runtimeInputs = [ start pkgs.gnugrep ];
text = ''
run_sql() {
su -c 'psql testdb -At -v ON_ERROR_STOP=1' postgres
}

run_sql <<- 'QUERY'
CREATE TABLE books (
title text,
author text,
year int
);

INSERT INTO books (title, author, year) VALUES
('Do Androids Dream Of Electric Sheep?', 'Philip K. Dick', 1968),
('Neuromancer', 'William Gibson', 1984),
('Cryptonomicon', 'Neal Stephenson', 1999),
('Accelerando', 'Charles Stross', 2005);
QUERY
'';
};

verify = pkgs.writeShellApplication {
name = "verify";
runtimeInputs = [ end pkgs.gnugrep ];
text = ''
run_sql() {
su -c 'psql testdb -At -v ON_ERROR_STOP=1' postgres
}

die() {
echo "$1" >&2 && exit 1
}

run_sql <<- 'QUERY' | grep 't' || die 'No author found 1'
SELECT exists(SELECT * FROM books WHERE author = 'Philip K. Dick');
QUERY

run_sql <<- 'QUERY' | grep 't' || die 'No title found'
SELECT exists(SELECT * FROM books WHERE title = 'Neuromancer');
QUERY

run_sql <<- 'QUERY' | grep 't' || die 'No year found'
SELECT exists(SELECT * FROM books WHERE year = 1999);
QUERY

run_sql <<- 'QUERY' | grep 't' || die 'No author found 2'
SELECT exists(SELECT * FROM books WHERE author = 'Charles Stross');
QUERY
'';
};

dropLast = n: l:
lib.reverseList (lib.drop n (lib.reverseList l));

nodes = {
start = {
services.postgresql = {
enable = true;

package = start;

dataDir = "/var/lib/postgresql/${start.psqlSchema}";

ensureDatabases = [ "testdb" ];
};
};
end = {
services.postgresql = {
enable = true;

package = end;

dataDir = "/var/lib/postgresql/${end.psqlSchema}";

upgradeFrom = lib.forEach (dropLast 1 pgPackages) (package: {
inherit package;

dataDir = "/var/lib/postgresql/${package.psqlSchema}";
});

analyzeAfterUpgrade = true;
};

# We want the service to start after the data directory has been copied.
systemd.services.postgresql.wantedBy = lib.mkForce [ ];
};
};
in
makeTest {
name = "postgresql-upgrade";

meta.maintainers = [ lib.maintainers.jsoo1 ];

inherit nodes;

testScript = ''
import os
import tempfile

with tempfile.TemporaryDirectory(dir=os.getenv("out")) as tmp:
start.wait_for_unit("postgresql.service")
start.succeed("${insert}/bin/insert")
start.succeed("systemctl stop postgresql.service")
start.copy_from_vm(
source="${nodes.start.services.postgresql.dataDir}",
target_dir=tmp,
)

end.copy_from_host(
source=tmp,
target="${builtins.dirOf nodes.end.services.postgresql.dataDir}",
)
end.succeed("systemctl start postgresql.service")
end.succeed("${verify}/bin/verify")

end.succeed("systemctl restart postgresql.service")
end.succeed("${verify}/bin/verify")
'';
}
6 changes: 4 additions & 2 deletions pkgs/servers/sql/postgresql/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,10 @@ let
}
this.pkgs;

tests.postgresql = nixosTests.postgresql-wal-receiver.${thisAttr};
};
tests = {
postgresql = nixosTests.postgresql-wal-receiver.${thisAttr};
upgrade = nixosTests.postgresql-upgrade;
};

meta = with lib; {
homepage = "https://www.postgresql.org";
Expand Down