1{ config, pkgs, lib, ... }:
2
3with import ./lib.nix { inherit lib; };
4
5let
6 inherit (lib) concatStringsSep intersperse mapAttrsToList mkForce mkIf mkMerge mkOption optionalString types;
7
8 bosConfig = pkgs.writeText "BosConfig" (''
9 restrictmode 1
10 restarttime 16 0 0 0 0
11 checkbintime 3 0 5 0 0
12 '' + (optionalString cfg.roles.database.enable ''
13 bnode simple vlserver 1
14 parm ${openafsBin}/libexec/openafs/vlserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.vlserverArgs}
15 end
16 bnode simple ptserver 1
17 parm ${openafsBin}/libexec/openafs/ptserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.ptserverArgs}
18 end
19 '') + (optionalString cfg.roles.fileserver.enable ''
20 bnode dafs dafs 1
21 parm ${openafsBin}/libexec/openafs/dafileserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.fileserverArgs}
22 parm ${openafsBin}/libexec/openafs/davolserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.volserverArgs}
23 parm ${openafsBin}/libexec/openafs/salvageserver ${cfg.roles.fileserver.salvageserverArgs}
24 parm ${openafsBin}/libexec/openafs/dasalvager ${cfg.roles.fileserver.salvagerArgs}
25 end
26 '') + (optionalString (cfg.roles.database.enable && cfg.roles.backup.enable) ''
27 bnode simple buserver 1
28 parm ${openafsBin}/libexec/openafs/buserver ${cfg.roles.backup.buserverArgs} ${optionalString (cfg.roles.backup.cellServDB != []) "-cellservdb /etc/openafs/backup/"}
29 end
30 ''));
31
32 netInfo = if (cfg.advertisedAddresses != []) then
33 pkgs.writeText "NetInfo" ((concatStringsSep "\nf " cfg.advertisedAddresses) + "\n")
34 else null;
35
36 buCellServDB = pkgs.writeText "backup-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.roles.backup.cellServDB);
37
38 cfg = config.services.openafsServer;
39
40 udpSizeStr = toString cfg.udpPacketSize;
41
42 openafsBin = lib.getBin pkgs.openafs;
43
44in {
45
46 options = {
47
48 services.openafsServer = {
49
50 enable = mkOption {
51 default = false;
52 type = types.bool;
53 description = ''
54 Whether to enable the OpenAFS server. An OpenAFS server needs a
55 complex setup. So, be aware that enabling this service and setting
56 some options does not give you a turn-key-ready solution. You need
57 at least a running Kerberos 5 setup, as OpenAFS relies on it for
58 authentication. See the Guide "QuickStartUnix" coming with
59 <literal>pkgs.openafs.doc</literal> for complete setup
60 instructions.
61 '';
62 };
63
64 advertisedAddresses = mkOption {
65 default = [];
66 description = "List of IP addresses this server is advertised under. See NetInfo(5)";
67 };
68
69 cellName = mkOption {
70 default = "";
71 type = types.str;
72 description = "Cell name, this server will serve.";
73 example = "grand.central.org";
74 };
75
76 cellServDB = mkOption {
77 default = [];
78 type = with types; listOf (submodule [ { options = cellServDBConfig;} ]);
79 description = "Definition of all cell-local database server machines.";
80 };
81
82 roles = {
83 fileserver = {
84 enable = mkOption {
85 default = true;
86 type = types.bool;
87 description = "Fileserver role, serves files and volumes from its local storage.";
88 };
89
90 fileserverArgs = mkOption {
91 default = "-vattachpar 128 -vhashsize 11 -L -rxpck 400 -cb 1000000";
92 type = types.str;
93 description = "Arguments to the dafileserver process. See its man page.";
94 };
95
96 volserverArgs = mkOption {
97 default = "";
98 type = types.str;
99 description = "Arguments to the davolserver process. See its man page.";
100 example = "-sync never";
101 };
102
103 salvageserverArgs = mkOption {
104 default = "";
105 type = types.str;
106 description = "Arguments to the salvageserver process. See its man page.";
107 example = "-showlog";
108 };
109
110 salvagerArgs = mkOption {
111 default = "";
112 type = types.str;
113 description = "Arguments to the dasalvager process. See its man page.";
114 example = "-showlog -showmounts";
115 };
116 };
117
118 database = {
119 enable = mkOption {
120 default = true;
121 type = types.bool;
122 description = ''
123 Database server role, maintains the Volume Location Database,
124 Protection Database (and Backup Database, see
125 <literal>backup</literal> role). There can be multiple
126 servers in the database role for replication, which then need
127 reliable network connection to each other.
128
129 Servers in this role appear in AFSDB DNS records or the
130 CellServDB.
131 '';
132 };
133
134 vlserverArgs = mkOption {
135 default = "";
136 type = types.str;
137 description = "Arguments to the vlserver process. See its man page.";
138 example = "-rxbind";
139 };
140
141 ptserverArgs = mkOption {
142 default = "";
143 type = types.str;
144 description = "Arguments to the ptserver process. See its man page.";
145 example = "-restricted -default_access S---- S-M---";
146 };
147 };
148
149 backup = {
150 enable = mkOption {
151 default = false;
152 type = types.bool;
153 description = ''
154 Backup server role. Use in conjunction with the
155 <literal>database</literal> role to maintain the Backup
156 Database. Normally only used in conjunction with tape storage
157 or IBM's Tivoli Storage Manager.
158 '';
159 };
160
161 buserverArgs = mkOption {
162 default = "";
163 type = types.str;
164 description = "Arguments to the buserver process. See its man page.";
165 example = "-p 8";
166 };
167
168 cellServDB = mkOption {
169 default = [];
170 type = with types; listOf (submodule [ { options = cellServDBConfig;} ]);
171 description = ''
172 Definition of all cell-local backup database server machines.
173 Use this when your cell uses less backup database servers than
174 other database server machines.
175 '';
176 };
177 };
178 };
179
180 dottedPrincipals= mkOption {
181 default = false;
182 type = types.bool;
183 description = ''
184 If enabled, allow principal names containing (.) dots. Enabling
185 this has security implications!
186 '';
187 };
188
189 udpPacketSize = mkOption {
190 default = 1310720;
191 type = types.int;
192 description = ''
193 UDP packet size to use in Bytes. Higher values can speed up
194 communications. The default of 1 MB is a sufficient in most
195 cases. Make sure to increase the kernel's UDP buffer size
196 accordingly via <literal>net.core(w|r|opt)mem_max</literal>
197 sysctl.
198 '';
199 };
200
201 };
202
203 };
204
205 config = mkIf cfg.enable {
206
207 assertions = [
208 { assertion = cfg.cellServDB != [];
209 message = "You must specify all cell-local database servers in config.services.openafsServer.cellServDB.";
210 }
211 { assertion = cfg.cellName != "";
212 message = "You must specify the local cell name in config.services.openafsServer.cellName.";
213 }
214 ];
215
216 environment.systemPackages = [ pkgs.openafs ];
217
218 environment.etc = {
219 bosConfig = {
220 source = bosConfig;
221 target = "openafs/BosConfig";
222 mode = "0644";
223 };
224 cellServDB = {
225 text = mkCellServDB cfg.cellName cfg.cellServDB;
226 target = "openafs/server/CellServDB";
227 mode = "0644";
228 };
229 thisCell = {
230 text = cfg.cellName;
231 target = "openafs/server/ThisCell";
232 mode = "0644";
233 };
234 buCellServDB = {
235 enable = (cfg.roles.backup.cellServDB != []);
236 text = mkCellServDB cfg.cellName cfg.roles.backup.cellServDB;
237 target = "openafs/backup/CellServDB";
238 };
239 };
240
241 systemd.services = {
242 openafs-server = {
243 description = "OpenAFS server";
244 after = [ "syslog.target" "network.target" ];
245 wantedBy = [ "multi-user.target" ];
246 restartIfChanged = false;
247 unitConfig.ConditionPathExists = [ "/etc/openafs/server/rxkad.keytab" ];
248 preStart = ''
249 mkdir -m 0755 -p /var/openafs
250 ${optionalString (netInfo != null) "cp ${netInfo} /var/openafs/netInfo"}
251 ${optionalString (cfg.roles.backup.cellServDB != []) "cp ${buCellServDB}"}
252 '';
253 serviceConfig = {
254 ExecStart = "${openafsBin}/bin/bosserver -nofork";
255 ExecStop = "${openafsBin}/bin/bos shutdown localhost -wait -localauth";
256 };
257 };
258 };
259 };
260}