···
9
+
cfg = config.services.saunafs;
14
+
allowedTypes = with lib.types; [
22
+
if lib.isList val then
23
+
lib.concatStringsSep listSep (map (x: valueToString x) val)
24
+
else if lib.isBool val then
25
+
(if val then "1" else "0")
36
+
(lib.types.listOf valueType)
41
+
description = "Flat key-value file";
44
+
lib.types.attrsOf valueType;
48
+
pkgs.writeText name (
49
+
lib.concatStringsSep "\n" (lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value)
53
+
initTool = pkgs.writeShellScriptBin "sfsmaster-init" ''
54
+
if [ ! -e ${cfg.master.settings.DATA_PATH}/metadata.sfs ]; then
55
+
cp --update=none ${pkgs.saunafs}/var/lib/saunafs/metadata.sfs.empty ${cfg.master.settings.DATA_PATH}/metadata.sfs
56
+
chmod +w ${cfg.master.settings.DATA_PATH}/metadata.sfs
60
+
# master config file
61
+
masterCfg = settingsFormat.generate "sfsmaster.cfg" cfg.master.settings;
63
+
# metalogger config file
64
+
metaloggerCfg = settingsFormat.generate "sfsmetalogger.cfg" cfg.metalogger.settings;
66
+
# chunkserver config file
67
+
chunkserverCfg = settingsFormat.generate "sfschunkserver.cfg" cfg.chunkserver.settings;
69
+
# generic template for all daemons
70
+
systemdService = name: extraConfig: configFile: {
71
+
wantedBy = [ "multi-user.target" ];
72
+
wants = [ "network-online.target" ];
75
+
"network-online.target"
80
+
ExecStart = "${pkgs.saunafs}/bin/sfs${name} -c ${configFile} start";
81
+
ExecStop = "${pkgs.saunafs}/bin/sfs${name} -c ${configFile} stop";
82
+
ExecReload = "${pkgs.saunafs}/bin/sfs${name} -c ${configFile} reload";
91
+
services.saunafs = {
92
+
masterHost = lib.mkOption {
93
+
type = lib.types.str;
95
+
description = "IP or hostname name of master host.";
98
+
sfsUser = lib.mkOption {
99
+
type = lib.types.str;
100
+
default = "saunafs";
101
+
description = "Run daemons as user.";
104
+
client.enable = lib.mkEnableOption "Saunafs client";
107
+
enable = lib.mkOption {
108
+
type = lib.types.bool;
110
+
Enable Saunafs master daemon.
112
+
You need to run `sfsmaster-init` on a freshly installed master server to
113
+
initialize the `DATA_PATH` directory.
118
+
exports = lib.mkOption {
119
+
type = with lib.types; listOf str;
121
+
description = "Paths to exports file (see {manpage}`sfsexports.cfg(5)`).";
122
+
example = lib.literalExpression ''
123
+
[ "* / rw,alldirs,admin,maproot=0:0" ];
127
+
openFirewall = lib.mkOption {
128
+
type = lib.types.bool;
129
+
description = "Whether to automatically open the necessary ports in the firewall.";
133
+
settings = lib.mkOption {
134
+
type = lib.types.submodule {
135
+
freeformType = settingsFormat.type;
137
+
options.DATA_PATH = lib.mkOption {
138
+
type = lib.types.str;
139
+
default = "/var/lib/saunafs/master";
140
+
description = "Data storage directory.";
144
+
description = "Contents of config file ({manpage}`sfsmaster.cfg(5)`).";
149
+
enable = lib.mkEnableOption "Saunafs metalogger daemon";
151
+
settings = lib.mkOption {
152
+
type = lib.types.submodule {
153
+
freeformType = settingsFormat.type;
155
+
options.DATA_PATH = lib.mkOption {
156
+
type = lib.types.str;
157
+
default = "/var/lib/saunafs/metalogger";
158
+
description = "Data storage directory";
162
+
description = "Contents of metalogger config file (see {manpage}`sfsmetalogger.cfg(5)`).";
167
+
enable = lib.mkEnableOption "Saunafs chunkserver daemon";
169
+
openFirewall = lib.mkOption {
170
+
type = lib.types.bool;
171
+
description = "Whether to automatically open the necessary ports in the firewall.";
175
+
hdds = lib.mkOption {
176
+
type = with lib.types; listOf str;
179
+
example = lib.literalExpression ''
184
+
Mount points to be used by chunkserver for storage (see {manpage}`sfshdd.cfg(5)`).
186
+
Note, that these mount points must writeable by the user defined by the saunafs user.
190
+
settings = lib.mkOption {
191
+
type = lib.types.submodule {
192
+
freeformType = settingsFormat.type;
194
+
options.DATA_PATH = lib.mkOption {
195
+
type = lib.types.str;
196
+
default = "/var/lib/saunafs/chunkserver";
197
+
description = "Directory for chunck meta data";
201
+
description = "Contents of chunkserver config file (see {manpage}`sfschunkserver.cfg(5)`).";
207
+
###### implementation
210
+
lib.mkIf (cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable)
214
+
(lib.mkIf (cfg.sfsUser == "root") "Running saunafs services as root is not recommended.")
218
+
services.saunafs = {
219
+
master.settings = lib.mkIf cfg.master.enable {
220
+
WORKING_USER = cfg.sfsUser;
221
+
EXPORTS_FILENAME = toString (
222
+
pkgs.writeText "sfsexports.cfg" (lib.concatStringsSep "\n" cfg.master.exports)
226
+
metalogger.settings = lib.mkIf cfg.metalogger.enable {
227
+
WORKING_USER = cfg.sfsUser;
228
+
MASTER_HOST = cfg.masterHost;
231
+
chunkserver.settings = lib.mkIf cfg.chunkserver.enable {
232
+
WORKING_USER = cfg.sfsUser;
233
+
MASTER_HOST = cfg.masterHost;
234
+
HDD_CONF_FILENAME = toString (
235
+
pkgs.writeText "sfshdd.cfg" (lib.concatStringsSep "\n" cfg.chunkserver.hdds)
240
+
# Create system user account for daemons
243
+
(cfg.sfsUser != "root" && (cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable))
245
+
users."${cfg.sfsUser}" = {
246
+
isSystemUser = true;
247
+
description = "saunafs daemon user";
250
+
groups."${cfg.sfsUser}" = { };
253
+
environment.systemPackages =
254
+
(lib.optional cfg.client.enable pkgs.saunafs) ++ (lib.optional cfg.master.enable initTool);
256
+
networking.firewall.allowedTCPPorts =
257
+
(lib.optionals cfg.master.openFirewall [
262
+
++ (lib.optional cfg.chunkserver.openFirewall 9422);
264
+
# Ensure storage directories exist
265
+
systemd.tmpfiles.rules =
266
+
lib.optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${cfg.sfsUser} ${cfg.sfsUser} -"
267
+
++ lib.optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${cfg.sfsUser} ${cfg.sfsUser} -"
268
+
++ lib.optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${cfg.sfsUser} ${cfg.sfsUser} -";
270
+
# Service definitions
271
+
systemd.services.sfs-master = lib.mkIf cfg.master.enable (
272
+
systemdService "master" {
273
+
TimeoutStartSec = 1800;
274
+
TimeoutStopSec = 1800;
279
+
systemd.services.sfs-metalogger = lib.mkIf cfg.metalogger.enable (
280
+
systemdService "metalogger" { Restart = "on-abort"; } metaloggerCfg
283
+
systemd.services.sfs-chunkserver = lib.mkIf cfg.chunkserver.enable (
284
+
systemdService "chunkserver" { Restart = "on-abort"; } chunkserverCfg