1
0
Fork 0

add postgresql module with tests

This commit is contained in:
ibizaman 2023-11-04 20:30:17 -07:00
parent 66a3af7f0d
commit cc57b1ced7
6 changed files with 278 additions and 23 deletions

View file

@ -117,7 +117,7 @@ First, some common configuration:
```nix ```nix
imports = [ imports = [
selfhostblocks.nixosModules.default selfhostblocks.nixosModules.x86_64-linux.default
sops-nix.nixosModules.default sops-nix.nixosModules.default
] ]

View file

@ -1,5 +1,38 @@
{ {
"nodes": { "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": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1687412861, "lastModified": 1687412861,
@ -50,6 +83,8 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils",
"nix-flake-tests": "nix-flake-tests",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"sops-nix": "sops-nix" "sops-nix": "sops-nix"
} }
@ -72,6 +107,21 @@
"repo": "sops-nix", "repo": "sops-nix",
"type": "github" "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", "root": "root",

View file

@ -4,29 +4,45 @@
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
sops-nix.url = "github:Mic92/sops-nix"; 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, ... }: { outputs = inputs@{ self, nixpkgs, sops-nix, nix-flake-tests, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system:
nixosModules.default = { config, ... }: { let
imports = [ pkgs = nixpkgs.legacyPackages.${system};
modules/arr.nix in
modules/authelia.nix {
modules/backup.nix nixosModules.default = { config, ... }: {
modules/deluge.nix imports = [
modules/davfs.nix modules/arr.nix
modules/hledger.nix modules/authelia.nix
modules/home-assistant.nix modules/backup.nix
modules/jellyfin.nix modules/deluge.nix
modules/ldap.nix modules/davfs.nix
modules/monitoring.nix modules/hledger.nix
modules/nextcloud-server.nix modules/home-assistant.nix
modules/nginx.nix modules/jellyfin.nix
modules/ssl.nix modules/ldap.nix
modules/tinyproxy.nix modules/monitoring.nix
modules/vpn.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
View 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
View file

@ -0,0 +1,2 @@
{ lib }:
import ./modules/postgresql.nix { inherit lib; }

View 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;
};
};
}