add postgresql module with tests
This commit is contained in:
parent
66a3af7f0d
commit
cc57b1ced7
6 changed files with 278 additions and 23 deletions
|
@ -117,7 +117,7 @@ First, some common configuration:
|
|||
|
||||
```nix
|
||||
imports = [
|
||||
selfhostblocks.nixosModules.default
|
||||
selfhostblocks.nixosModules.x86_64-linux.default
|
||||
sops-nix.nixosModules.default
|
||||
]
|
||||
|
||||
|
|
50
flake.lock
50
flake.lock
|
@ -1,5 +1,38 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-flake-tests": {
|
||||
"locked": {
|
||||
"lastModified": 1677844186,
|
||||
"narHash": "sha256-ErJZ/Gs1rxh561CJeWP5bohA2IcTq1rDneu1WT6CVII=",
|
||||
"owner": "antifuchs",
|
||||
"repo": "nix-flake-tests",
|
||||
"rev": "bbd9216bd0f6495bb961a8eb8392b7ef55c67afb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "antifuchs",
|
||||
"repo": "nix-flake-tests",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1687412861,
|
||||
|
@ -50,6 +83,8 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-flake-tests": "nix-flake-tests",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"sops-nix": "sops-nix"
|
||||
}
|
||||
|
@ -72,6 +107,21 @@
|
|||
"repo": "sops-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
|
60
flake.nix
60
flake.nix
|
@ -4,29 +4,45 @@
|
|||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
sops-nix.url = "github:Mic92/sops-nix";
|
||||
nix-flake-tests.url = "github:antifuchs/nix-flake-tests";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = inputs@{ self, nixpkgs, sops-nix, ... }: {
|
||||
nixosModules.default = { config, ... }: {
|
||||
imports = [
|
||||
modules/arr.nix
|
||||
modules/authelia.nix
|
||||
modules/backup.nix
|
||||
modules/deluge.nix
|
||||
modules/davfs.nix
|
||||
modules/hledger.nix
|
||||
modules/home-assistant.nix
|
||||
modules/jellyfin.nix
|
||||
modules/ldap.nix
|
||||
modules/monitoring.nix
|
||||
modules/nextcloud-server.nix
|
||||
modules/nginx.nix
|
||||
modules/ssl.nix
|
||||
modules/tinyproxy.nix
|
||||
modules/vpn.nix
|
||||
];
|
||||
};
|
||||
outputs = inputs@{ self, nixpkgs, sops-nix, nix-flake-tests, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
nixosModules.default = { config, ... }: {
|
||||
imports = [
|
||||
modules/arr.nix
|
||||
modules/authelia.nix
|
||||
modules/backup.nix
|
||||
modules/deluge.nix
|
||||
modules/davfs.nix
|
||||
modules/hledger.nix
|
||||
modules/home-assistant.nix
|
||||
modules/jellyfin.nix
|
||||
modules/ldap.nix
|
||||
modules/monitoring.nix
|
||||
modules/nextcloud-server.nix
|
||||
modules/nginx.nix
|
||||
modules/postgresql.nix
|
||||
modules/ssl.nix
|
||||
modules/tinyproxy.nix
|
||||
modules/vpn.nix
|
||||
];
|
||||
};
|
||||
|
||||
# templates.default = {}; Would be nice to have a template
|
||||
};
|
||||
checks = {
|
||||
tests = nix-flake-tests.lib.check {
|
||||
inherit pkgs;
|
||||
tests = import ./test/default.nix {
|
||||
inherit (pkgs) lib;
|
||||
};
|
||||
};
|
||||
};
|
||||
# templates.default = {}; Would be nice to have a template
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
88
modules/postgresql.nix
Normal file
88
modules/postgresql.nix
Normal file
|
@ -0,0 +1,88 @@
|
|||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.shb.postgresql;
|
||||
in
|
||||
{
|
||||
options.shb.postgresql = {
|
||||
tcpIPPort = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.port;
|
||||
description = "Enable TCP/IP connection on given port.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
passwords = lib.mkOption {
|
||||
type = lib.types.listOf (lib.types.submodule {
|
||||
options = {
|
||||
username = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Postgres user name.";
|
||||
};
|
||||
|
||||
database = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Postgres database.";
|
||||
};
|
||||
|
||||
passwordFile = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Password file for the postgres user.";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
tcpConfig = port: {
|
||||
services.postgresql.enableTCPIP = true;
|
||||
services.postgresql.port = port;
|
||||
services.postgresql.authentication = lib.mkOverride 10 ''
|
||||
#type database DBuser origin-address auth-method
|
||||
# ipv4
|
||||
host all all 127.0.0.1/32 trust
|
||||
# ipv6
|
||||
host all all ::1/128 trust
|
||||
'';
|
||||
};
|
||||
|
||||
dbConfig = passwordCfgs: {
|
||||
services.postgresql.enable = (builtins.length passwordCfgs) > 0;
|
||||
services.postgresql.ensureDatabases = map ({ database, ... }: database) passwordCfgs;
|
||||
services.postgresql.Users = map ({ username, database, ... }: {
|
||||
name = username;
|
||||
ensurePermissions = {
|
||||
"DATABASE ${database}" = "ALL PRIVILEGES";
|
||||
};
|
||||
ensureClauses = {
|
||||
"login" = true;
|
||||
};
|
||||
}) passwordCfgs;
|
||||
};
|
||||
|
||||
pwdConfig = passwordCfgs: {
|
||||
systemd.services.postgresql.postStart =
|
||||
let
|
||||
script = { username, passwordFile, ... }: ''
|
||||
$PSQL -tA <<'EOF'
|
||||
DO $$
|
||||
DECLARE password TEXT;
|
||||
BEGIN
|
||||
password := trim(both from replace(pg_read_file('${passwordFile}'), E'\n', '''));
|
||||
EXECUTE format('ALTER ROLE ${username} WITH PASSWORD '''%s''';', password);
|
||||
END $$;
|
||||
EOF
|
||||
'';
|
||||
in
|
||||
lib.concatStringsSep "\n" (map script passwordCfgs);
|
||||
};
|
||||
in
|
||||
lib.mkMerge (
|
||||
[
|
||||
(dbConfig cfg.passwords)
|
||||
(pwdConfig cfg.passwords)
|
||||
(lib.mkIf (!(isNull cfg.tcpIPPort)) (tcpConfig cfg.tcpIPPort))
|
||||
]
|
||||
);
|
||||
}
|
2
test/default.nix
Normal file
2
test/default.nix
Normal file
|
@ -0,0 +1,2 @@
|
|||
{ lib }:
|
||||
import ./modules/postgresql.nix { inherit lib; }
|
99
test/modules/postgresql.nix
Normal file
99
test/modules/postgresql.nix
Normal file
|
@ -0,0 +1,99 @@
|
|||
{ lib }:
|
||||
let
|
||||
anyOpt = default: lib.mkOption {
|
||||
type = lib.types.anything;
|
||||
inherit default;
|
||||
};
|
||||
|
||||
testConfig = m:
|
||||
let
|
||||
cfg = (lib.evalModules {
|
||||
modules = [
|
||||
{
|
||||
options = {
|
||||
services = anyOpt {};
|
||||
systemd = anyOpt {};
|
||||
};
|
||||
}
|
||||
../../modules/postgresql.nix
|
||||
m
|
||||
];
|
||||
}).config;
|
||||
in {
|
||||
inherit (cfg) systemd services;
|
||||
};
|
||||
in
|
||||
{
|
||||
testPostgresNoOptions = {
|
||||
expected = {
|
||||
services.postgresql = {
|
||||
enable = false;
|
||||
Users = [];
|
||||
ensureDatabases = [];
|
||||
};
|
||||
systemd.services.postgresql.postStart = "";
|
||||
};
|
||||
expr = testConfig {};
|
||||
};
|
||||
|
||||
testPostgresOnePassword = {
|
||||
expected = {
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
Users = [{
|
||||
name = "myuser";
|
||||
ensurePermissions = {
|
||||
"DATABASE mydatabase" = "ALL PRIVILEGES";
|
||||
};
|
||||
ensureClauses = {
|
||||
"login" = true;
|
||||
};
|
||||
}];
|
||||
ensureDatabases = ["mydatabase"];
|
||||
};
|
||||
systemd.services.postgresql.postStart = ''
|
||||
$PSQL -tA <<'EOF'
|
||||
DO $$
|
||||
DECLARE password TEXT;
|
||||
BEGIN
|
||||
password := trim(both from replace(pg_read_file('/my/file'), E'\n', '''));
|
||||
EXECUTE format('ALTER ROLE myuser WITH PASSWORD '''%s''';', password);
|
||||
END $$;
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
expr = testConfig {
|
||||
shb.postgresql.passwords = [
|
||||
{
|
||||
username = "myuser";
|
||||
database = "mydatabase";
|
||||
passwordFile = "/my/file";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testPostgresTCPIP = {
|
||||
expected = {
|
||||
services.postgresql = {
|
||||
enable = false;
|
||||
Users = [];
|
||||
ensureDatabases = [];
|
||||
|
||||
enableTCPIP = true;
|
||||
port = 1234;
|
||||
authentication = ''
|
||||
#type database DBuser origin-address auth-method
|
||||
# ipv4
|
||||
host all all 127.0.0.1/32 trust
|
||||
# ipv6
|
||||
host all all ::1/128 trust
|
||||
'';
|
||||
};
|
||||
systemd.services.postgresql.postStart = "";
|
||||
};
|
||||
expr = testConfig {
|
||||
shb.postgresql.tcpIPPort = 1234;
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue