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