1 { config, lib, pkgs, ... }:
6 cfg = config.services.moosefs;
8 mfsUser = if cfg.runAsUser then "moosefs" else "root";
12 allowedTypes = with types; [ bool int float str ];
14 if isList val then concatStringsSep listSep (map (x: valueToString x) val)
15 else if isBool val then (if val then "1" else "0")
19 type = with types; let
22 ] ++ allowedTypes) // {
23 description = "Flat key-value file";
27 generate = name: value:
28 pkgs.writeText name ( lib.concatStringsSep "\n" (
29 lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value ));
33 initTool = pkgs.writeShellScriptBin "mfsmaster-init" ''
34 if [ ! -e ${cfg.master.settings.DATA_PATH}/metadata.mfs ]; then
35 cp ${pkgs.moosefs}/var/mfs/metadata.mfs.empty ${cfg.master.settings.DATA_PATH}
36 chmod +w ${cfg.master.settings.DATA_PATH}/metadata.mfs.empty
37 ${pkgs.moosefs}/bin/mfsmaster -a -c ${masterCfg} start
38 ${pkgs.moosefs}/bin/mfsmaster -c ${masterCfg} stop
39 rm ${cfg.master.settings.DATA_PATH}/metadata.mfs.empty
44 masterCfg = settingsFormat.generate
45 "mfsmaster.cfg" cfg.master.settings;
47 # metalogger config file
48 metaloggerCfg = settingsFormat.generate
49 "mfsmetalogger.cfg" cfg.metalogger.settings;
51 # chunkserver config file
52 chunkserverCfg = settingsFormat.generate
53 "mfschunkserver.cfg" cfg.chunkserver.settings;
55 # generic template for all daemons
56 systemdService = name: extraConfig: configFile: {
57 wantedBy = [ "multi-user.target" ];
58 wants = [ "network-online.target" ];
59 after = [ "network.target" "network-online.target" ];
63 ExecStart = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} start";
64 ExecStop = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} stop";
65 ExecReload = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} reload";
66 PIDFile = "${cfg."${name}".settings.DATA_PATH}/.mfs${name}.lock";
75 masterHost = mkOption {
78 description = lib.mdDoc "IP or DNS name of master host.";
81 runAsUser = mkOption {
85 description = lib.mdDoc "Run daemons as user moosefs instead of root.";
88 client.enable = mkEnableOption (lib.mdDoc "Moosefs client");
93 description = lib.mdDoc ''
94 Enable Moosefs master daemon.
96 You need to run `mfsmaster-init` on a freshly installed master server to
97 initialize the `DATA_PATH` directory.
103 type = with types; listOf str;
105 description = lib.mdDoc "Paths to export (see mfsexports.cfg).";
107 "* / rw,alldirs,admin,maproot=0:0"
112 openFirewall = mkOption {
114 description = lib.mdDoc "Whether to automatically open the necessary ports in the firewall.";
118 settings = mkOption {
119 type = types.submodule {
120 freeformType = settingsFormat.type;
122 options.DATA_PATH = mkOption {
124 default = "/var/lib/mfs";
125 description = lib.mdDoc "Data storage directory.";
129 description = lib.mdDoc "Contents of config file (mfsmaster.cfg).";
134 enable = mkEnableOption (lib.mdDoc "Moosefs metalogger daemon");
136 settings = mkOption {
137 type = types.submodule {
138 freeformType = settingsFormat.type;
140 options.DATA_PATH = mkOption {
142 default = "/var/lib/mfs";
143 description = lib.mdDoc "Data storage directory";
147 description = lib.mdDoc "Contents of metalogger config file (mfsmetalogger.cfg).";
152 enable = mkEnableOption (lib.mdDoc "Moosefs chunkserver daemon");
154 openFirewall = mkOption {
156 description = lib.mdDoc "Whether to automatically open the necessary ports in the firewall.";
161 type = with types; listOf str;
163 description = lib.mdDoc "Mount points to be used by chunkserver for storage (see mfshdd.cfg).";
164 example = [ "/mnt/hdd1" ];
167 settings = mkOption {
168 type = types.submodule {
169 freeformType = settingsFormat.type;
171 options.DATA_PATH = mkOption {
173 default = "/var/lib/mfs";
174 description = lib.mdDoc "Directory for lock file.";
178 description = lib.mdDoc "Contents of chunkserver config file (mfschunkserver.cfg).";
184 ###### implementation
186 config = mkIf ( cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) {
188 warnings = [ ( mkIf (!cfg.runAsUser) "Running moosefs services as root is not recommended.") ];
192 master.settings = mkIf cfg.master.enable {
193 WORKING_USER = mfsUser;
194 EXPORTS_FILENAME = toString ( pkgs.writeText "mfsexports.cfg"
195 (concatStringsSep "\n" cfg.master.exports));
198 metalogger.settings = mkIf cfg.metalogger.enable {
199 WORKING_USER = mfsUser;
200 MASTER_HOST = cfg.masterHost;
203 chunkserver.settings = mkIf cfg.chunkserver.enable {
204 WORKING_USER = mfsUser;
205 MASTER_HOST = cfg.masterHost;
206 HDD_CONF_FILENAME = toString ( pkgs.writeText "mfshdd.cfg"
207 (concatStringsSep "\n" cfg.chunkserver.hdds));
211 # Create system user account for daemons
212 users = mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) ) {
215 description = "moosefs daemon user";
221 environment.systemPackages =
222 (lib.optional cfg.client.enable pkgs.moosefs) ++
223 (lib.optional cfg.master.enable initTool);
225 networking.firewall.allowedTCPPorts =
226 (lib.optionals cfg.master.openFirewall [ 9419 9420 9421 ]) ++
227 (lib.optional cfg.chunkserver.openFirewall 9422);
229 # Ensure storage directories exist
230 systemd.tmpfiles.rules =
231 optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"
232 ++ optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"
233 ++ optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}";
235 # Service definitions
236 systemd.services.mfs-master = mkIf cfg.master.enable
237 ( systemdService "master" {
238 TimeoutStartSec = 1800;
239 TimeoutStopSec = 1800;
243 systemd.services.mfs-metalogger = mkIf cfg.metalogger.enable
244 ( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg );
246 systemd.services.mfs-chunkserver = mkIf cfg.chunkserver.enable
247 ( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg );