1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8# openafsBin, openafsSrv, mkCellServDB
9with import ./lib.nix { inherit config lib pkgs; };
10
11let
12 inherit (lib)
13 concatStringsSep
14 literalExpression
15 mkIf
16 mkOption
17 mkEnableOption
18 mkPackageOption
19 optionalString
20 types
21 ;
22
23 bosConfig = pkgs.writeText "BosConfig" (
24 ''
25 restrictmode 1
26 restarttime 16 0 0 0 0
27 checkbintime 3 0 5 0 0
28 ''
29 + (optionalString cfg.roles.database.enable ''
30 bnode simple vlserver 1
31 parm ${openafsSrv}/libexec/openafs/vlserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.vlserverArgs}
32 end
33 bnode simple ptserver 1
34 parm ${openafsSrv}/libexec/openafs/ptserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.ptserverArgs}
35 end
36 '')
37 + (optionalString cfg.roles.fileserver.enable ''
38 bnode dafs dafs 1
39 parm ${openafsSrv}/libexec/openafs/dafileserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.fileserverArgs}
40 parm ${openafsSrv}/libexec/openafs/davolserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.volserverArgs}
41 parm ${openafsSrv}/libexec/openafs/salvageserver ${cfg.roles.fileserver.salvageserverArgs}
42 parm ${openafsSrv}/libexec/openafs/dasalvager ${cfg.roles.fileserver.salvagerArgs}
43 end
44 '')
45 + (optionalString
46 (cfg.roles.database.enable && cfg.roles.backup.enable && (!cfg.roles.backup.enableFabs))
47 ''
48 bnode simple buserver 1
49 parm ${openafsSrv}/libexec/openafs/buserver ${cfg.roles.backup.buserverArgs} ${optionalString useBuCellServDB "-cellservdb /etc/openafs/backup/"}
50 end
51 ''
52 )
53 + (optionalString
54 (cfg.roles.database.enable && cfg.roles.backup.enable && cfg.roles.backup.enableFabs)
55 ''
56 bnode simple buserver 1
57 parm ${lib.getBin pkgs.fabs}/bin/fabsys server --config ${fabsConfFile} ${cfg.roles.backup.fabsArgs}
58 end
59 ''
60 )
61 );
62
63 netInfo =
64 if (cfg.advertisedAddresses != [ ]) then
65 pkgs.writeText "NetInfo" ((concatStringsSep "\nf " cfg.advertisedAddresses) + "\n")
66 else
67 null;
68
69 buCellServDB = pkgs.writeText "backup-cellServDB-${cfg.cellName}" (
70 mkCellServDB cfg.cellName cfg.roles.backup.cellServDB
71 );
72
73 useBuCellServDB = (cfg.roles.backup.cellServDB != [ ]) && (!cfg.roles.backup.enableFabs);
74
75 cfg = config.services.openafsServer;
76
77 udpSizeStr = toString cfg.udpPacketSize;
78
79 fabsConfFile = pkgs.writeText "fabs.yaml" (
80 builtins.toJSON (
81 {
82 afs = {
83 aklog = cfg.package + "/bin/aklog";
84 cell = cfg.cellName;
85 dumpscan = cfg.package + "/bin/afsdump_scan";
86 fs = cfg.package + "/bin/fs";
87 pts = cfg.package + "/bin/pts";
88 vos = cfg.package + "/bin/vos";
89 };
90 k5start.command = (lib.getBin pkgs.kstart) + "/bin/k5start";
91 }
92 // cfg.roles.backup.fabsExtraConfig
93 )
94 );
95
96in
97{
98
99 options = {
100
101 services.openafsServer = {
102
103 enable = mkOption {
104 default = false;
105 type = types.bool;
106 description = ''
107 Whether to enable the OpenAFS server. An OpenAFS server needs a
108 complex setup. So, be aware that enabling this service and setting
109 some options does not give you a turn-key-ready solution. You need
110 at least a running Kerberos 5 setup, as OpenAFS relies on it for
111 authentication. See the Guide "QuickStartUnix" coming with
112 `pkgs.openafs.doc` for complete setup
113 instructions.
114 '';
115 };
116
117 advertisedAddresses = mkOption {
118 type = types.listOf types.str;
119 default = [ ];
120 description = "List of IP addresses this server is advertised under. See {manpage}`NetInfo(5)`";
121 };
122
123 cellName = mkOption {
124 default = "";
125 type = types.str;
126 description = "Cell name, this server will serve.";
127 example = "grand.central.org";
128 };
129
130 cellServDB = mkOption {
131 default = [ ];
132 type = with types; listOf (submodule [ { options = cellServDBConfig; } ]);
133 description = "Definition of all cell-local database server machines.";
134 };
135
136 package = mkPackageOption pkgs "openafs" { };
137
138 roles = {
139 fileserver = {
140 enable = mkOption {
141 default = true;
142 type = types.bool;
143 description = "Fileserver role, serves files and volumes from its local storage.";
144 };
145
146 fileserverArgs = mkOption {
147 default = "-vattachpar 128 -vhashsize 11 -L -rxpck 400 -cb 1000000";
148 type = types.str;
149 description = "Arguments to the dafileserver process. See its man page.";
150 };
151
152 volserverArgs = mkOption {
153 default = "";
154 type = types.str;
155 description = "Arguments to the davolserver process. See its man page.";
156 example = "-sync never";
157 };
158
159 salvageserverArgs = mkOption {
160 default = "";
161 type = types.str;
162 description = "Arguments to the salvageserver process. See its man page.";
163 example = "-showlog";
164 };
165
166 salvagerArgs = mkOption {
167 default = "";
168 type = types.str;
169 description = "Arguments to the dasalvager process. See its man page.";
170 example = "-showlog -showmounts";
171 };
172 };
173
174 database = {
175 enable = mkOption {
176 default = true;
177 type = types.bool;
178 description = ''
179 Database server role, maintains the Volume Location Database,
180 Protection Database (and Backup Database, see
181 `backup` role). There can be multiple
182 servers in the database role for replication, which then need
183 reliable network connection to each other.
184
185 Servers in this role appear in AFSDB DNS records or the
186 CellServDB.
187 '';
188 };
189
190 vlserverArgs = mkOption {
191 default = "";
192 type = types.str;
193 description = "Arguments to the vlserver process. See its man page.";
194 example = "-rxbind";
195 };
196
197 ptserverArgs = mkOption {
198 default = "";
199 type = types.str;
200 description = "Arguments to the ptserver process. See its man page.";
201 example = "-restricted -default_access S---- S-M---";
202 };
203 };
204
205 backup = {
206 enable = mkEnableOption ''
207 the backup server role. When using OpenAFS built-in buserver, use in conjunction with the
208 `database` role to maintain the Backup
209 Database. Normally only used in conjunction with tape storage
210 or IBM's Tivoli Storage Manager.
211
212 For a modern backup server, enable this role and see
213 {option}`enableFabs`
214 '';
215
216 enableFabs = mkEnableOption ''
217 FABS, the flexible AFS backup system. It stores volumes as dump files, relying on other
218 pre-existing backup solutions for handling them
219 '';
220
221 buserverArgs = mkOption {
222 default = "";
223 type = types.str;
224 description = "Arguments to the buserver process. See its man page.";
225 example = "-p 8";
226 };
227
228 cellServDB = mkOption {
229 default = [ ];
230 type = with types; listOf (submodule [ { options = cellServDBConfig; } ]);
231 description = ''
232 Definition of all cell-local backup database server machines.
233 Use this when your cell uses less backup database servers than
234 other database server machines.
235 '';
236 };
237
238 fabsArgs = mkOption {
239 default = "";
240 type = types.str;
241 description = ''
242 Arguments to the fabsys process. See
243 {manpage}`fabsys_server(1)` and
244 {manpage}`fabsys_config(1)`.
245 '';
246 };
247
248 fabsExtraConfig = mkOption {
249 default = { };
250 type = types.attrs;
251 description = ''
252 Additional configuration parameters for the FABS backup server.
253 '';
254 example = literalExpression ''
255 {
256 afs.localauth = true;
257 afs.keytab = config.sops.secrets.fabsKeytab.path;
258 }
259 '';
260 };
261 };
262 };
263
264 dottedPrincipals = mkOption {
265 default = false;
266 type = types.bool;
267 description = ''
268 If enabled, allow principal names containing (.) dots. Enabling
269 this has security implications!
270 '';
271 };
272
273 udpPacketSize = mkOption {
274 default = 1310720;
275 type = types.int;
276 description = ''
277 UDP packet size to use in Bytes. Higher values can speed up
278 communications. The default of 1 MB is a sufficient in most
279 cases. Make sure to increase the kernel's UDP buffer size
280 accordingly via `net.core(w|r|opt)mem_max`
281 sysctl.
282 '';
283 };
284
285 };
286
287 };
288
289 config = mkIf cfg.enable {
290
291 assertions = [
292 {
293 assertion = cfg.cellServDB != [ ];
294 message = "You must specify all cell-local database servers in config.services.openafsServer.cellServDB.";
295 }
296 {
297 assertion = cfg.cellName != "";
298 message = "You must specify the local cell name in config.services.openafsServer.cellName.";
299 }
300 ];
301
302 environment.systemPackages = [ openafsBin ];
303
304 environment.etc = {
305 bosConfig = {
306 source = bosConfig;
307 target = "openafs/BosConfig";
308 mode = "0644";
309 };
310 cellServDB = {
311 text = mkCellServDB cfg.cellName cfg.cellServDB;
312 target = "openafs/server/CellServDB";
313 mode = "0644";
314 };
315 thisCell = {
316 text = cfg.cellName;
317 target = "openafs/server/ThisCell";
318 mode = "0644";
319 };
320 buCellServDB = {
321 enable = useBuCellServDB;
322 text = mkCellServDB cfg.cellName cfg.roles.backup.cellServDB;
323 target = "openafs/backup/CellServDB";
324 };
325 };
326
327 systemd.services = {
328 openafs-server = {
329 description = "OpenAFS server";
330 after = [ "network.target" ];
331 wantedBy = [ "multi-user.target" ];
332 restartIfChanged = false;
333 unitConfig.ConditionPathExists = [
334 "|/etc/openafs/server/KeyFileExt"
335 ];
336 preStart = ''
337 mkdir -m 0755 -p /var/openafs
338 ${optionalString (netInfo != null) "cp ${netInfo} /var/openafs/netInfo"}
339 ${optionalString useBuCellServDB "cp ${buCellServDB}"}
340 '';
341 serviceConfig = {
342 ExecStart = "${openafsBin}/bin/bosserver -nofork";
343 ExecStop = "${openafsBin}/bin/bos shutdown localhost -wait -localauth";
344 };
345 };
346 };
347 };
348}