8 cfg = config.services.foundationdb;
11 # used for initial cluster configuration
12 initialIpAddr = if (cfg.publicAddress != "auto") then cfg.publicAddress else "127.0.0.1";
16 lib.concatStringsSep "\n" (
17 map (x: "[fdbserver.${toString (x + cfg.listenPortStart)}]") (lib.range 0 (n - 1))
21 n: lib.concatStringsSep "\n" (map (x: "[backup_agent.${toString x}]") (lib.range 1 n));
23 configFile = pkgs.writeText "foundationdb.conf" ''
25 cluster_file = /etc/foundationdb/fdb.cluster
28 restart_delay = ${toString cfg.restartDelay}
33 command = ${pkg}/bin/fdbserver
34 public_address = ${cfg.publicAddress}:$ID
35 listen_address = ${cfg.listenAddress}
36 datadir = ${cfg.dataDir}/$ID
37 logdir = ${cfg.logDir}
38 logsize = ${cfg.logSize}
39 maxlogssize = ${cfg.maxLogSize}
40 ${lib.optionalString (cfg.class != null) "class = ${cfg.class}"}
41 memory = ${cfg.memory}
42 storage_memory = ${cfg.storageMemory}
44 ${lib.optionalString (lib.versionAtLeast cfg.package.version "6.1") ''
45 trace_format = ${cfg.traceFormat}
48 ${lib.optionalString (cfg.tls != null) ''
49 tls_plugin = ${pkg}/libexec/plugins/FDBLibTLS.so
50 tls_certificate_file = ${cfg.tls.certificate}
51 tls_key_file = ${cfg.tls.key}
52 tls_verify_peers = ${cfg.tls.allowedPeers}
55 ${lib.optionalString (
56 cfg.locality.machineId != null
57 ) "locality_machineid=${cfg.locality.machineId}"}
58 ${lib.optionalString (cfg.locality.zoneId != null) "locality_zoneid=${cfg.locality.zoneId}"}
59 ${lib.optionalString (
60 cfg.locality.datacenterId != null
61 ) "locality_dcid=${cfg.locality.datacenterId}"}
62 ${lib.optionalString (cfg.locality.dataHall != null) "locality_data_hall=${cfg.locality.dataHall}"}
64 ${fdbServers cfg.serverProcesses}
67 command = ${pkg}/libexec/backup_agent
68 ${backupAgents cfg.backupProcesses}
72 options.services.foundationdb = {
74 enable = lib.mkEnableOption "FoundationDB Server";
76 package = lib.mkOption {
77 type = lib.types.package;
79 The FoundationDB package to use for this server. This must be specified by the user
80 in order to ensure migrations and upgrades are controlled appropriately.
84 publicAddress = lib.mkOption {
87 description = "Publicly visible IP address of the process. Port is determined by process ID";
90 listenAddress = lib.mkOption {
93 description = "Publicly visible IP address of the process. Port is determined by process ID";
96 listenPortStart = lib.mkOption {
100 Starting port number for database listening sockets. Every FDB process binds to a
101 subsequent port, to this number reflects the start of the overall range. e.g. having
102 8 server processes will use all ports between 4500 and 4507.
106 openFirewall = lib.mkOption {
107 type = lib.types.bool;
110 Open the firewall ports corresponding to FoundationDB processes and coordinators
111 using {option}`config.networking.firewall.*`.
115 dataDir = lib.mkOption {
116 type = lib.types.path;
117 default = "/var/lib/foundationdb";
118 description = "Data directory. All cluster data will be put under here.";
121 logDir = lib.mkOption {
122 type = lib.types.path;
123 default = "/var/log/foundationdb";
124 description = "Log directory.";
127 user = lib.mkOption {
128 type = lib.types.str;
129 default = "foundationdb";
130 description = "User account under which FoundationDB runs.";
133 group = lib.mkOption {
134 type = lib.types.str;
135 default = "foundationdb";
136 description = "Group account under which FoundationDB runs.";
139 class = lib.mkOption {
140 type = lib.types.nullOr (
148 description = "Process class";
151 restartDelay = lib.mkOption {
152 type = lib.types.int;
154 description = "Number of seconds to wait before restarting servers.";
157 logSize = lib.mkOption {
158 type = lib.types.str;
161 Roll over to a new log file after the current log file
162 reaches the specified size.
166 maxLogSize = lib.mkOption {
167 type = lib.types.str;
170 Delete the oldest log file when the total size of all log
171 files exceeds the specified size. If set to 0, old log files
176 serverProcesses = lib.mkOption {
177 type = lib.types.int;
179 description = "Number of fdbserver processes to run.";
182 backupProcesses = lib.mkOption {
183 type = lib.types.int;
185 description = "Number of backup_agent processes to run for snapshots.";
188 memory = lib.mkOption {
189 type = lib.types.str;
192 Maximum memory used by the process. The default value is
193 `8GiB`. When specified without a unit,
194 `MiB` is assumed. This parameter does not
195 change the memory allocation of the program. Rather, it sets
196 a hard limit beyond which the process will kill itself and
197 be restarted. The default value of `8GiB`
198 is double the intended memory usage in the default
199 configuration (providing an emergency buffer to deal with
200 memory leaks or similar problems). It is not recommended to
201 decrease the value of this parameter below its default
202 value. It may be increased if you wish to allocate a very
203 large amount of storage engine memory or cache. In
204 particular, when the `storageMemory`
205 parameter is increased, the `memory`
206 parameter should be increased by an equal amount.
210 storageMemory = lib.mkOption {
211 type = lib.types.str;
214 Maximum memory used for data storage. The default value is
215 `1GiB`. When specified without a unit,
216 `MB` is assumed. Clusters using the memory
217 storage engine will be restricted to using this amount of
218 memory per process for purposes of data storage. Memory
219 overhead associated with storing the data is counted against
220 this total. If you increase the
221 `storageMemory`, you should also increase
222 the `memory` parameter by the same amount.
229 FoundationDB Transport Security Layer (TLS) settings.
232 type = lib.types.nullOr (
233 lib.types.submodule ({
235 certificate = lib.mkOption {
236 type = lib.types.str;
238 Path to the TLS certificate file. This certificate will
239 be offered to, and may be verified by, clients.
244 type = lib.types.str;
245 description = "Private key file for the certificate.";
248 allowedPeers = lib.mkOption {
249 type = lib.types.str;
250 default = "Check.Valid=1,Check.Unexpired=1";
252 "Peer verification string". This may be used to adjust which TLS
253 client certificates a server will accept, as a form of user
254 authorization; for example, it may only accept TLS clients who
255 offer a certificate abiding by some locality or organization name.
257 For more information, please see the FoundationDB documentation.
265 locality = lib.mkOption {
274 FoundationDB locality settings.
277 type = lib.types.submodule ({
279 machineId = lib.mkOption {
281 type = lib.types.nullOr lib.types.str;
283 Machine identifier key. All processes on a machine should share a
284 unique id. By default, processes on a machine determine a unique id to share.
285 This does not generally need to be set.
289 zoneId = lib.mkOption {
291 type = lib.types.nullOr lib.types.str;
293 Zone identifier key. Processes that share a zone id are
294 considered non-unique for the purposes of data replication.
295 If unset, defaults to machine id.
299 datacenterId = lib.mkOption {
301 type = lib.types.nullOr lib.types.str;
303 Data center identifier key. All processes physically located in a
304 data center should share the id. If you are depending on data
305 center based replication this must be set on all processes.
309 dataHall = lib.mkOption {
311 type = lib.types.nullOr lib.types.str;
313 Data hall identifier key. All processes physically located in a
314 data hall should share the id. If you are depending on data
315 hall based replication this must be set on all processes.
322 extraReadWritePaths = lib.mkOption {
324 type = lib.types.listOf lib.types.path;
326 An extra set of filesystem paths that FoundationDB can read to
327 and write from. By default, FoundationDB runs under a heavily
328 namespaced systemd environment without write access to most of
329 the filesystem outside of its data and log directories. By
330 adding paths to this list, the set of writeable paths will be
331 expanded. This is useful for allowing e.g. backups to local files,
332 which must be performed on behalf of the foundationdb service.
336 pidfile = lib.mkOption {
337 type = lib.types.path;
338 default = "/run/foundationdb.pid";
339 description = "Path to pidfile for fdbmonitor.";
342 traceFormat = lib.mkOption {
343 type = lib.types.enum [
348 description = "Trace logging format.";
352 config = lib.mkIf cfg.enable {
355 assertion = lib.versionOlder cfg.package.version "6.1" -> cfg.traceFormat == "xml";
358 Versions of FoundationDB before 6.1 do not support configurable trace formats (only XML is supported).
359 This option has no effect for version ''
360 + cfg.package.version
362 , and enabling it is an error.
367 environment.systemPackages = [ pkg ];
369 users.users = lib.optionalAttrs (cfg.user == "foundationdb") {
371 description = "FoundationDB User";
372 uid = config.ids.uids.foundationdb;
377 users.groups = lib.optionalAttrs (cfg.group == "foundationdb") {
378 foundationdb.gid = config.ids.gids.foundationdb;
381 networking.firewall.allowedTCPPortRanges = lib.mkIf cfg.openFirewall [
383 from = cfg.listenPortStart;
384 to = (cfg.listenPortStart + cfg.serverProcesses) - 1;
388 systemd.tmpfiles.rules = [
389 "d /etc/foundationdb 0755 ${cfg.user} ${cfg.group} - -"
390 "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
391 "d '${cfg.logDir}' 0770 ${cfg.user} ${cfg.group} - -"
392 "F '${cfg.pidfile}' - ${cfg.user} ${cfg.group} - -"
395 systemd.services.foundationdb = {
396 description = "FoundationDB Service";
398 after = [ "network.target" ];
399 wantedBy = [ "multi-user.target" ];
401 RequiresMountsFor = "${cfg.dataDir} ${cfg.logDir}";
411 ] ++ cfg.extraReadWritePaths;
419 PIDFile = "${cfg.pidfile}";
421 PermissionsStartOnly = true; # setup needs root perms
422 TimeoutSec = 120; # give reasonable time to shut down
425 NoNewPrivileges = true;
427 ProtectSystem = "strict";
428 ProtectKernelTunables = true;
429 ProtectControlGroups = true;
431 PrivateDevices = true;
432 ReadWritePaths = lib.concatStringsSep " " (map (x: "-" + x) rwpaths);
441 if [ ! -f /etc/foundationdb/fdb.cluster ]; then
442 cf=/etc/foundationdb/fdb.cluster
443 desc=$(tr -dc A-Za-z0-9 </dev/urandom 2>/dev/null | head -c8)
444 rand=$(tr -dc A-Za-z0-9 </dev/urandom 2>/dev/null | head -c8)
445 echo ''${desc}:''${rand}@${initialIpAddr}:${builtins.toString cfg.listenPortStart} > $cf
447 touch "${cfg.dataDir}/.first_startup"
451 script = "exec fdbmonitor --lockfile ${cfg.pidfile} --conffile ${configFile}";
454 if [ -e "${cfg.dataDir}/.first_startup" ]; then
455 fdbcli --exec "configure new single ssd"
456 rm -f "${cfg.dataDir}/.first_startup";
462 meta.doc = ./foundationdb.md;
463 meta.maintainers = with lib.maintainers; [ thoughtpolice ];