1{ config, lib, pkgs, ... }:
2
3# TODO: test configuration when building nixexpr (use -t parameter)
4# TODO: support sqlite3 (it's deprecate?) and mysql
5
6with lib;
7
8let
9 libDir = "/var/lib/bacula";
10
11 fd_cfg = config.services.bacula-fd;
12 fd_conf = pkgs.writeText "bacula-fd.conf"
13 ''
14 Client {
15 Name = "${fd_cfg.name}";
16 FDPort = ${toString fd_cfg.port};
17 WorkingDirectory = "${libDir}";
18 Pid Directory = "/var/run";
19 ${fd_cfg.extraClientConfig}
20 }
21
22 ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
23 Director {
24 Name = "${name}";
25 Password = "${value.password}";
26 Monitor = "${value.monitor}";
27 }
28 '') fd_cfg.director)}
29
30 Messages {
31 Name = Standard;
32 syslog = all, !skipped, !restored
33 ${fd_cfg.extraMessagesConfig}
34 }
35 '';
36
37 sd_cfg = config.services.bacula-sd;
38 sd_conf = pkgs.writeText "bacula-sd.conf"
39 ''
40 Storage {
41 Name = "${sd_cfg.name}";
42 SDPort = ${toString sd_cfg.port};
43 WorkingDirectory = "${libDir}";
44 Pid Directory = "/var/run";
45 ${sd_cfg.extraStorageConfig}
46 }
47
48 ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
49 Device {
50 Name = "${name}";
51 Archive Device = "${value.archiveDevice}";
52 Media Type = "${value.mediaType}";
53 ${value.extraDeviceConfig}
54 }
55 '') sd_cfg.device)}
56
57 ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
58 Director {
59 Name = "${name}";
60 Password = "${value.password}";
61 Monitor = "${value.monitor}";
62 }
63 '') sd_cfg.director)}
64
65 Messages {
66 Name = Standard;
67 syslog = all, !skipped, !restored
68 ${sd_cfg.extraMessagesConfig}
69 }
70 '';
71
72 dir_cfg = config.services.bacula-dir;
73 dir_conf = pkgs.writeText "bacula-dir.conf"
74 ''
75 Director {
76 Name = "${dir_cfg.name}";
77 Password = "${dir_cfg.password}";
78 DirPort = ${toString dir_cfg.port};
79 Working Directory = "${libDir}";
80 Pid Directory = "/var/run/";
81 QueryFile = "${pkgs.bacula}/etc/query.sql";
82 ${dir_cfg.extraDirectorConfig}
83 }
84
85 Catalog {
86 Name = "PostgreSQL";
87 dbname = "bacula";
88 user = "bacula";
89 }
90
91 Messages {
92 Name = Standard;
93 syslog = all, !skipped, !restored
94 ${dir_cfg.extraMessagesConfig}
95 }
96
97 ${dir_cfg.extraConfig}
98 '';
99
100 # TODO: by default use this config
101 bconsole_conf = pkgs.writeText "bconsole.conf"
102 ''
103 Director {
104 Name = ${dir_cfg.name};
105 Address = "localhost";
106 DirPort = ${toString dir_cfg.port};
107 Password = "${dir_cfg.password}";
108 }
109 '';
110
111 directorOptions = {name, config, ...}:
112 {
113 options = {
114 password = mkOption {
115 # TODO: required?
116 description = ''
117 Specifies the password that must be supplied for a Director to b
118 '';
119 };
120
121 monitor = mkOption {
122 default = "no";
123 example = "yes";
124 description = ''
125 If Monitor is set to no (default), this director will have full
126 '';
127 };
128 };
129 };
130
131 deviceOptions = {name, config, ...}:
132 {
133 options = {
134 archiveDevice = mkOption {
135 # TODO: required?
136 description = ''
137 The specified name-string gives the system file name of the storage device managed by this storage daemon. This will usually be the device file name of a removable storage device (tape drive), for example " /dev/nst0" or "/dev/rmt/0mbn". For a DVD-writer, it will be for example /dev/hdc. It may also be a directory name if you are archiving to disk storage.
138 '';
139 };
140
141 mediaType = mkOption {
142 # TODO: required?
143 description = ''
144 The specified name-string names the type of media supported by this device, for example, "DLT7000". Media type names are arbitrary in that you set them to anything you want, but they must be known to the volume database to keep track of which storage daemons can read which volumes. In general, each different storage type should have a unique Media Type associated with it. The same name-string must appear in the appropriate Storage resource definition in the Director's configuration file.
145 '';
146 };
147
148 extraDeviceConfig = mkOption {
149 default = "";
150 description = ''
151 Extra configuration to be passed in Device directive.
152 '';
153 example = ''
154 LabelMedia = yes
155 Random Access = no
156 AutomaticMount = no
157 RemovableMedia = no
158 MaximumOpenWait = 60
159 AlwaysOpen = no
160 '';
161 };
162 };
163 };
164
165in {
166 options = {
167 services.bacula-fd = {
168 enable = mkOption {
169 type = types.bool;
170 default = false;
171 description = ''
172 Whether to enable the Bacula File Daemon.
173 '';
174 };
175
176 name = mkOption {
177 default = "${config.networking.hostName}-fd";
178 description = ''
179 The client name that must be used by the Director when connecting.
180 Generally, it is a good idea to use a name related to the machine
181 so that error messages can be easily identified if you have multiple
182 Clients. This directive is required.
183 '';
184 };
185
186 port = mkOption {
187 default = 9102;
188 type = types.int;
189 description = ''
190 This specifies the port number on which the Client listens for
191 Director connections. It must agree with the FDPort specified in
192 the Client resource of the Director's configuration file.
193 '';
194 };
195
196 director = mkOption {
197 default = {};
198 description = ''
199 This option defines director resources in Bacula File Daemon.
200 '';
201 type = with types; attrsOf (submodule directorOptions);
202 };
203
204 extraClientConfig = mkOption {
205 default = "";
206 description = ''
207 Extra configuration to be passed in Client directive.
208 '';
209 example = ''
210 Maximum Concurrent Jobs = 20;
211 Heartbeat Interval = 30;
212 '';
213 };
214
215 extraMessagesConfig = mkOption {
216 default = "";
217 description = ''
218 Extra configuration to be passed in Messages directive.
219 '';
220 example = ''
221 console = all
222 '';
223 };
224 };
225
226 services.bacula-sd = {
227 enable = mkOption {
228 type = types.bool;
229 default = false;
230 description = ''
231 Whether to enable Bacula Storage Daemon.
232 '';
233 };
234
235 name = mkOption {
236 default = "${config.networking.hostName}-sd";
237 description = ''
238 Specifies the Name of the Storage daemon.
239 '';
240 };
241
242 port = mkOption {
243 default = 9103;
244 type = types.int;
245 description = ''
246 Specifies port number on which the Storage daemon listens for Director connections. The default is 9103.
247 '';
248 };
249
250 director = mkOption {
251 default = {};
252 description = ''
253 This option defines Director resources in Bacula Storage Daemon.
254 '';
255 type = with types; attrsOf (submodule directorOptions);
256 };
257
258 device = mkOption {
259 default = {};
260 description = ''
261 This option defines Device resources in Bacula Storage Daemon.
262 '';
263 type = with types; attrsOf (submodule deviceOptions);
264 };
265
266 extraStorageConfig = mkOption {
267 default = "";
268 description = ''
269 Extra configuration to be passed in Storage directive.
270 '';
271 example = ''
272 Maximum Concurrent Jobs = 20;
273 Heartbeat Interval = 30;
274 '';
275 };
276
277 extraMessagesConfig = mkOption {
278 default = "";
279 description = ''
280 Extra configuration to be passed in Messages directive.
281 '';
282 example = ''
283 console = all
284 '';
285 };
286
287 };
288
289 services.bacula-dir = {
290 enable = mkOption {
291 type = types.bool;
292 default = false;
293 description = ''
294 Whether to enable Bacula Director Daemon.
295 '';
296 };
297
298 name = mkOption {
299 default = "${config.networking.hostName}-dir";
300 description = ''
301 The director name used by the system administrator. This directive is required.
302 '';
303 };
304
305 port = mkOption {
306 default = 9101;
307 type = types.int;
308 description = ''
309 Specify the port (a positive integer) on which the Director daemon will listen for Bacula Console connections. This same port number must be specified in the Director resource of the Console configuration file. The default is 9101, so normally this directive need not be specified. This directive should not be used if you specify DirAddresses (N.B plural) directive.
310 '';
311 };
312
313 password = mkOption {
314 # TODO: required?
315 description = ''
316 Specifies the password that must be supplied for a Director.
317 '';
318 };
319
320 extraMessagesConfig = mkOption {
321 default = "";
322 description = ''
323 Extra configuration to be passed in Messages directive.
324 '';
325 example = ''
326 console = all
327 '';
328 };
329
330 extraDirectorConfig = mkOption {
331 default = "";
332 description = ''
333 Extra configuration to be passed in Director directive.
334 '';
335 example = ''
336 Maximum Concurrent Jobs = 20;
337 Heartbeat Interval = 30;
338 '';
339 };
340
341 extraConfig = mkOption {
342 default = "";
343 type = types.lines;
344 description = ''
345 Extra configuration for Bacula Director Daemon.
346 '';
347 example = ''
348 TODO
349 '';
350 };
351 };
352 };
353
354 config = mkIf (fd_cfg.enable || sd_cfg.enable || dir_cfg.enable) {
355 systemd.services.bacula-fd = mkIf fd_cfg.enable {
356 after = [ "network.target" ];
357 description = "Bacula File Daemon";
358 wantedBy = [ "multi-user.target" ];
359 path = [ pkgs.bacula ];
360 serviceConfig.ExecStart = "${pkgs.bacula}/sbin/bacula-fd -f -u root -g bacula -c ${fd_conf}";
361 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
362 };
363
364 systemd.services.bacula-sd = mkIf sd_cfg.enable {
365 after = [ "network.target" ];
366 description = "Bacula Storage Daemon";
367 wantedBy = [ "multi-user.target" ];
368 path = [ pkgs.bacula ];
369 serviceConfig.ExecStart = "${pkgs.bacula}/sbin/bacula-sd -f -u bacula -g bacula -c ${sd_conf}";
370 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
371 };
372
373 services.postgresql.enable = dir_cfg.enable == true;
374
375 systemd.services.bacula-dir = mkIf dir_cfg.enable {
376 after = [ "network.target" "postgresql.service" ];
377 description = "Bacula Director Daemon";
378 wantedBy = [ "multi-user.target" ];
379 path = [ pkgs.bacula ];
380 serviceConfig.ExecStart = "${pkgs.bacula}/sbin/bacula-dir -f -u bacula -g bacula -c ${dir_conf}";
381 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
382 preStart = ''
383 if ! test -e "${libDir}/db-created"; then
384 ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole bacula
385 #${pkgs.postgresql}/bin/createdb --owner bacula bacula
386
387 # populate DB
388 ${pkgs.bacula}/etc/create_bacula_database postgresql
389 ${pkgs.bacula}/etc/make_bacula_tables postgresql
390 ${pkgs.bacula}/etc/grant_bacula_privileges postgresql
391 touch "${libDir}/db-created"
392 else
393 ${pkgs.bacula}/etc/update_bacula_tables postgresql || true
394 fi
395 '';
396 };
397
398 environment.systemPackages = [ pkgs.bacula ];
399
400 users.extraUsers.bacula = {
401 group = "bacula";
402 uid = config.ids.uids.bacula;
403 home = "${libDir}";
404 createHome = true;
405 description = "Bacula Daemons user";
406 shell = "${pkgs.bash}/bin/bash";
407 };
408
409 users.extraGroups.bacula.gid = config.ids.gids.bacula;
410 };
411}