···1+{ config, lib, pkgs, ... }:
2+3+with lib;
4+let
5+ cfg = config.services.tahoe;
6+in
7+ {
8+ options.services.tahoe = {
9+ introducers = mkOption {
10+ default = {};
11+ type = types.loaOf types.optionSet;
12+ description = ''
13+ The Tahoe introducers.
14+ '';
15+ options = {
16+ nickname = mkOption {
17+ type = types.str;
18+ description = ''
19+ The nickname of this Tahoe introducer.
20+ '';
21+ };
22+ tub.port = mkOption {
23+ default = 3458;
24+ type = types.int;
25+ description = ''
26+ The port on which the introducer will listen.
27+ '';
28+ };
29+ package = mkOption {
30+ default = pkgs.tahoelafs;
31+ defaultText = "pkgs.tahoelafs";
32+ type = types.package;
33+ example = literalExample "pkgs.tahoelafs";
34+ description = ''
35+ The package to use for the Tahoe LAFS daemon.
36+ '';
37+ };
38+ };
39+ };
40+ nodes = mkOption {
41+ default = {};
42+ type = types.loaOf types.optionSet;
43+ description = ''
44+ The Tahoe nodes.
45+ '';
46+ options = {
47+ nickname = mkOption {
48+ type = types.str;
49+ description = ''
50+ The nickname of this Tahoe node.
51+ '';
52+ };
53+ tub.port = mkOption {
54+ default = 3457;
55+ type = types.int;
56+ description = ''
57+ The port on which the tub will listen.
58+59+ This is the correct setting to tweak if you want Tahoe's storage
60+ system to listen on a different port.
61+ '';
62+ };
63+ web.port = mkOption {
64+ default = 3456;
65+ type = types.int;
66+ description = ''
67+ The port on which the Web server will listen.
68+69+ This is the correct setting to tweak if you want Tahoe's WUI to
70+ listen on a different port.
71+ '';
72+ };
73+ client.introducer = mkOption {
74+ default = null;
75+ type = types.nullOr types.str;
76+ description = ''
77+ The furl for a Tahoe introducer node.
78+79+ Like all furls, keep this safe and don't share it.
80+ '';
81+ };
82+ client.helper = mkOption {
83+ default = null;
84+ type = types.nullOr types.str;
85+ description = ''
86+ The furl for a Tahoe helper node.
87+88+ Like all furls, keep this safe and don't share it.
89+ '';
90+ };
91+ client.shares.needed = mkOption {
92+ default = 3;
93+ type = types.int;
94+ description = ''
95+ The number of shares required to reconstitute a file.
96+ '';
97+ };
98+ client.shares.happy = mkOption {
99+ default = 7;
100+ type = types.int;
101+ description = ''
102+ The number of distinct storage nodes required to store
103+ a file.
104+ '';
105+ };
106+ client.shares.total = mkOption {
107+ default = 10;
108+ type = types.int;
109+ description = ''
110+ The number of shares required to store a file.
111+ '';
112+ };
113+ storage.enable = mkEnableOption "storage service";
114+ storage.reservedSpace = mkOption {
115+ default = "1G";
116+ type = types.str;
117+ description = ''
118+ The amount of filesystem space to not use for storage.
119+ '';
120+ };
121+ helper.enable = mkEnableOption "helper service";
122+ package = mkOption {
123+ default = pkgs.tahoelafs;
124+ defaultText = "pkgs.tahoelafs";
125+ type = types.package;
126+ example = literalExample "pkgs.tahoelafs";
127+ description = ''
128+ The package to use for the Tahoe LAFS daemon.
129+ '';
130+ };
131+ };
132+ };
133+ };
134+ config = mkMerge [
135+ (mkIf (cfg.introducers != {}) {
136+ environment = {
137+ etc = flip mapAttrs' cfg.introducers (node: settings:
138+ nameValuePair "tahoe-lafs/introducer-${node}.cfg" {
139+ mode = "0444";
140+ text = ''
141+ # This configuration is generated by Nix. Edit at your own
142+ # peril; here be dragons.
143+144+ [node]
145+ nickname = ${settings.nickname}
146+ tub.port = ${toString settings.tub.port}
147+ '';
148+ });
149+ # Actually require Tahoe, so that we will have it installed.
150+ systemPackages = flip mapAttrsToList cfg.introducers (node: settings:
151+ settings.package
152+ );
153+ };
154+ # Open up the firewall.
155+ # networking.firewall.allowedTCPPorts = flip mapAttrsToList cfg.introducers
156+ # (node: settings: settings.tub.port);
157+ systemd.services = flip mapAttrs' cfg.introducers (node: settings:
158+ let
159+ pidfile = "/run/tahoe.introducer-${node}.pid";
160+ # This is a directory, but it has no trailing slash. Tahoe commands
161+ # get antsy when there's a trailing slash.
162+ nodedir = "/var/db/tahoe-lafs/introducer-${node}";
163+ in nameValuePair "tahoe.introducer-${node}" {
164+ description = "Tahoe LAFS node ${node}";
165+ wantedBy = [ "multi-user.target" ];
166+ path = [ settings.package ];
167+ restartTriggers = [
168+ config.environment.etc."tahoe-lafs/introducer-${node}.cfg".source ];
169+ serviceConfig = {
170+ Type = "simple";
171+ PIDFile = pidfile;
172+ };
173+ preStart = ''
174+ if [ \! -d ${nodedir} ]; then
175+ mkdir -p /var/db/tahoe-lafs
176+ tahoe create-introducer ${nodedir}
177+ fi
178+179+ # Tahoe has created a predefined tahoe.cfg which we must now
180+ # scribble over.
181+ # XXX I thought that a symlink would work here, but it doesn't, so
182+ # we must do this on every prestart. Fixes welcome.
183+ # rm ${nodedir}/tahoe.cfg
184+ # ln -s /etc/tahoe-lafs/introducer-${node}.cfg ${nodedir}/tahoe.cfg
185+ cp /etc/tahoe-lafs/introducer-${node}.cfg ${nodedir}/tahoe.cfg
186+ '';
187+ # Believe it or not, Tahoe is very brittle about the order of
188+ # arguments to $(tahoe start). The node directory must come first,
189+ # and arguments which alter Twisted's behavior come afterwards.
190+ script = ''
191+ tahoe start ${nodedir} -n -l- --pidfile=${pidfile}
192+ '';
193+ });
194+ users.extraUsers = flip mapAttrs' cfg.introducers (node: _:
195+ nameValuePair "tahoe.introducer-${node}" {
196+ description = "Tahoe node user for introducer ${node}";
197+ isSystemUser = true;
198+ });
199+ })
200+ (mkIf (cfg.nodes != {}) {
201+ environment = {
202+ etc = flip mapAttrs' cfg.nodes (node: settings:
203+ nameValuePair "tahoe-lafs/${node}.cfg" {
204+ mode = "0444";
205+ text = ''
206+ # This configuration is generated by Nix. Edit at your own
207+ # peril; here be dragons.
208+209+ [node]
210+ nickname = ${settings.nickname}
211+ tub.port = ${toString settings.tub.port}
212+ # This is a Twisted endpoint. Twisted Web doesn't work on
213+ # non-TCP. ~ C.
214+ web.port = tcp:${toString settings.web.port}
215+216+ [client]
217+ ${optionalString (settings.client.introducer != null)
218+ "introducer.furl = ${settings.client.introducer}"}
219+ ${optionalString (settings.client.helper != null)
220+ "helper.furl = ${settings.client.helper}"}
221+222+ shares.needed = ${toString settings.client.shares.needed}
223+ shares.happy = ${toString settings.client.shares.happy}
224+ shares.total = ${toString settings.client.shares.total}
225+226+ [storage]
227+ enabled = ${if settings.storage.enable then "true" else "false"}
228+ reserved_space = ${settings.storage.reservedSpace}
229+230+ [helper]
231+ enabled = ${if settings.helper.enable then "true" else "false"}
232+ '';
233+ });
234+ # Actually require Tahoe, so that we will have it installed.
235+ systemPackages = flip mapAttrsToList cfg.nodes (node: settings:
236+ settings.package
237+ );
238+ };
239+ # Open up the firewall.
240+ # networking.firewall.allowedTCPPorts = flip mapAttrsToList cfg.nodes
241+ # (node: settings: settings.tub.port);
242+ systemd.services = flip mapAttrs' cfg.nodes (node: settings:
243+ let
244+ pidfile = "/run/tahoe.${node}.pid";
245+ # This is a directory, but it has no trailing slash. Tahoe commands
246+ # get antsy when there's a trailing slash.
247+ nodedir = "/var/db/tahoe-lafs/${node}";
248+ in nameValuePair "tahoe.${node}" {
249+ description = "Tahoe LAFS node ${node}";
250+ wantedBy = [ "multi-user.target" ];
251+ path = [ settings.package ];
252+ restartTriggers = [
253+ config.environment.etc."tahoe-lafs/${node}.cfg".source ];
254+ serviceConfig = {
255+ Type = "simple";
256+ PIDFile = pidfile;
257+ };
258+ preStart = ''
259+ if [ \! -d ${nodedir} ]; then
260+ mkdir -p /var/db/tahoe-lafs
261+ tahoe create-node ${nodedir}
262+ fi
263+264+ # Tahoe has created a predefined tahoe.cfg which we must now
265+ # scribble over.
266+ # XXX I thought that a symlink would work here, but it doesn't, so
267+ # we must do this on every prestart. Fixes welcome.
268+ # rm ${nodedir}/tahoe.cfg
269+ # ln -s /etc/tahoe-lafs/${node}.cfg ${nodedir}/tahoe.cfg
270+ cp /etc/tahoe-lafs/${node}.cfg ${nodedir}/tahoe.cfg
271+ '';
272+ # Believe it or not, Tahoe is very brittle about the order of
273+ # arguments to $(tahoe start). The node directory must come first,
274+ # and arguments which alter Twisted's behavior come afterwards.
275+ script = ''
276+ tahoe start ${nodedir} -n -l- --pidfile=${pidfile}
277+ '';
278+ });
279+ users.extraUsers = flip mapAttrs' cfg.nodes (node: _:
280+ nameValuePair "tahoe.${node}" {
281+ description = "Tahoe node user for node ${node}";
282+ isSystemUser = true;
283+ });
284+ })
285+ ];
286+ }