Skip to content

Commit ce195c3

Browse files
committed
database: Add nixos module for null-db
The module includes a null-db service with argv and firewall options. Argv is made a freeform type to allow future flags not to require new options.
1 parent 8999b95 commit ce195c3

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

nix/module.nix

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
{ lib, pkgs, config, ... }:
2+
3+
# See https://nixos.org/manual/nixos/stable/#sec-writing-modules
4+
let
5+
cfg = config.services.null-db;
6+
in
7+
8+
{
9+
options.programs.null-db = {
10+
enable = lib.mkEnableOption "null-db" // {
11+
description = "Whether to install the null-db management cli";
12+
};
13+
};
14+
15+
options.services.null-db = {
16+
enable = lib.mkEnableOption "null-db" // {
17+
description = "Enable the only educational database with native htmx support";
18+
};
19+
20+
openFirewall = lib.mkOption {
21+
type = lib.types.bool;
22+
default = false;
23+
description = ''
24+
Whether to expose the api port specified in {option} `config.services.null-db.args.port`
25+
'';
26+
};
27+
28+
raft-port = lib.mkOption {
29+
type = lib.types.port;
30+
default = 3030;
31+
description = "gRPC port used for raft consensus";
32+
};
33+
34+
args = lib.mkOption {
35+
description = "Argv provided to null-db";
36+
type = lib.types.submodule {
37+
# freeformType should make this somewhat future-proof if new
38+
# cli args are added that are not listed here
39+
freeformType = lib.types.attrsOf (lib.types.oneOf [
40+
lib.types.bool
41+
lib.types.str
42+
lib.types.port
43+
(lib.types.nullOr (lib.types.listOf lib.types.str))
44+
]);
45+
46+
options = {
47+
compaction = lib.mkOption {
48+
type = lib.types.bool;
49+
default = false;
50+
description = "Whether to run compaction";
51+
};
52+
53+
dir = lib.mkOption {
54+
type = lib.types.str;
55+
# See https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#Specifiers
56+
defaultText = lib.literalExpression
57+
''"%S/''${config.services.null-db.user}"'';
58+
description = "Where to store database";
59+
};
60+
61+
roster = lib.mkOption {
62+
type = lib.types.nullOr (lib.types.listOf lib.types.str);
63+
default = null;
64+
example = lib.literalExpression ''[ "10.0.0.18:5050" "10.0.0.19:5151" ]'';
65+
description = ''
66+
If provided, the peers in raft configuration in hostaddr
67+
notation, comma separated
68+
'';
69+
};
70+
71+
port = lib.mkOption {
72+
type = lib.types.port;
73+
default = 8080;
74+
description = "Port to listen on";
75+
};
76+
77+
id = lib.mkOption {
78+
type = lib.types.str;
79+
defaultText = lib.literalExpression
80+
''"''${config.networking.fqdnOrHostName}:''${toString config.services.null-db.raft-port}"'';
81+
description = ''
82+
The candidate identifier of this node in raft
83+
configuration, in hostaddr notation
84+
'';
85+
example = lib.literalExpression ''"10.0.0.20:4040"'';
86+
};
87+
88+
encoding = lib.mkOption {
89+
type = lib.types.str;
90+
default = "html";
91+
description = "Database storage format";
92+
};
93+
};
94+
};
95+
};
96+
97+
user = lib.mkOption {
98+
type = lib.types.str;
99+
default = "nulldb";
100+
description = "Service user";
101+
};
102+
103+
group = lib.mkOption {
104+
type = lib.types.str;
105+
default = "nulldb";
106+
description = "Service group";
107+
};
108+
};
109+
110+
config = lib.mkMerge [
111+
{
112+
# Put defaults here that use `config` in some way - it is a bit
113+
# of a well-known wart that options referring to config can
114+
# cause infinite recursion when generating docs or other static
115+
# information about the available options.
116+
services.null-db.args = {
117+
id = lib.mkDefault
118+
"${config.networking.fqdnOrHostName}:${toString cfg.raft-port}";
119+
dir = "%S/${cfg.user}";
120+
};
121+
}
122+
123+
(lib.mkIf config.programs.null-db.enable {
124+
environment.defaultPackages = [ pkgs.null-db ];
125+
})
126+
127+
(lib.mkIf cfg.enable {
128+
networking.firewall.allowedTCPPorts = lib.mkMerge [
129+
(lib.mkIf cfg.openFirewall [ cfg.args.port ])
130+
(lib.mkIf (cfg.openFirewall && cfg.args.roster != null) [ cfg.raft-port ])
131+
];
132+
133+
users = {
134+
users.${cfg.user} = {
135+
isSystemUser = true;
136+
group = cfg.group;
137+
};
138+
139+
groups.${cfg.group} = { };
140+
};
141+
142+
systemd.services.null-db = {
143+
enable = true;
144+
description = "The only educational database with native htmx support";
145+
146+
wantedBy = [ "default.target" ];
147+
148+
wants = [ "network-online.target" ];
149+
after = [ "network-online.target" ];
150+
151+
serviceConfig = {
152+
ExecStart = "${pkgs.null-db}/libexec/null-db ${
153+
lib.cli.toGNUCommandLineShell {
154+
mkList = k: v:
155+
let key = if lib.stringLength k == 1 then "-${k}" else "--${k}"; in
156+
[ "--${k}" (lib.concatStringsSep "," v) ];
157+
}
158+
cfg.args
159+
}";
160+
161+
StateDirectory = cfg.user;
162+
163+
User = cfg.user;
164+
Group = cfg.group;
165+
};
166+
};
167+
})
168+
];
169+
}

0 commit comments

Comments
 (0)