1 { config, lib, pkgs, ... }:
3 cfg = config.services.moosefs;
5 mfsUser = if cfg.runAsUser then "moosefs" else "root";
9 allowedTypes = with lib.types; [ bool int float str ];
11 if lib.isList val then lib.concatStringsSep listSep (map (x: valueToString x) val)
12 else if lib.isBool val then (if val then "1" else "0")
16 type = with lib.types; let
19 ] ++ allowedTypes) // {
20 description = "Flat key-value file";
24 generate = name: value:
25 pkgs.writeText name ( lib.concatStringsSep "\n" (
26 lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value ));
30 initTool = pkgs.writeShellScriptBin "mfsmaster-init" ''
31 if [ ! -e ${cfg.master.settings.DATA_PATH}/metadata.mfs ]; then
32 cp ${pkgs.moosefs}/var/mfs/metadata.mfs.empty ${cfg.master.settings.DATA_PATH}
33 chmod +w ${cfg.master.settings.DATA_PATH}/metadata.mfs.empty
34 ${pkgs.moosefs}/bin/mfsmaster -a -c ${masterCfg} start
35 ${pkgs.moosefs}/bin/mfsmaster -c ${masterCfg} stop
36 rm ${cfg.master.settings.DATA_PATH}/metadata.mfs.empty
41 masterCfg = settingsFormat.generate
42 "mfsmaster.cfg" cfg.master.settings;
44 # metalogger config file
45 metaloggerCfg = settingsFormat.generate
46 "mfsmetalogger.cfg" cfg.metalogger.settings;
48 # chunkserver config file
49 chunkserverCfg = settingsFormat.generate
50 "mfschunkserver.cfg" cfg.chunkserver.settings;
52 # generic template for all daemons
53 systemdService = name: extraConfig: configFile: {
54 wantedBy = [ "multi-user.target" ];
55 wants = [ "network-online.target" ];
56 after = [ "network.target" "network-online.target" ];
60 ExecStart = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} start";
61 ExecStop = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} stop";
62 ExecReload = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} reload";
63 PIDFile = "${cfg."${name}".settings.DATA_PATH}/.mfs${name}.lock";
72 masterHost = lib.mkOption {
75 description = "IP or DNS name of master host.";
78 runAsUser = lib.mkOption {
79 type = lib.types.bool;
82 description = "Run daemons as user moosefs instead of root.";
85 client.enable = lib.mkEnableOption "Moosefs client";
88 enable = lib.mkOption {
89 type = lib.types.bool;
91 Enable Moosefs master daemon.
93 You need to run `mfsmaster-init` on a freshly installed master server to
94 initialize the `DATA_PATH` directory.
99 exports = lib.mkOption {
100 type = with lib.types; listOf str;
102 description = "Paths to export (see mfsexports.cfg).";
104 "* / rw,alldirs,admin,maproot=0:0"
109 openFirewall = lib.mkOption {
110 type = lib.types.bool;
111 description = "Whether to automatically open the necessary ports in the firewall.";
115 settings = lib.mkOption {
116 type = lib.types.submodule {
117 freeformType = settingsFormat.type;
119 options.DATA_PATH = lib.mkOption {
120 type = lib.types.str;
121 default = "/var/lib/mfs";
122 description = "Data storage directory.";
126 description = "Contents of config file (mfsmaster.cfg).";
131 enable = lib.mkEnableOption "Moosefs metalogger daemon";
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/mfs";
140 description = "Data storage directory";
144 description = "Contents of metalogger config file (mfsmetalogger.cfg).";
149 enable = lib.mkEnableOption "Moosefs chunkserver daemon";
151 openFirewall = lib.mkOption {
152 type = lib.types.bool;
153 description = "Whether to automatically open the necessary ports in the firewall.";
157 hdds = lib.mkOption {
158 type = with lib.types; listOf str;
160 description = "Mount points to be used by chunkserver for storage (see mfshdd.cfg).";
161 example = [ "/mnt/hdd1" ];
164 settings = lib.mkOption {
165 type = lib.types.submodule {
166 freeformType = settingsFormat.type;
168 options.DATA_PATH = lib.mkOption {
169 type = lib.types.str;
170 default = "/var/lib/mfs";
171 description = "Directory for lock file.";
175 description = "Contents of chunkserver config file (mfschunkserver.cfg).";
181 ###### implementation
183 config = lib.mkIf ( cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) {
185 warnings = [ ( lib.mkIf (!cfg.runAsUser) "Running moosefs services as root is not recommended.") ];
189 master.settings = lib.mkIf cfg.master.enable {
190 WORKING_USER = mfsUser;
191 EXPORTS_FILENAME = toString ( pkgs.writeText "mfsexports.cfg"
192 (lib.concatStringsSep "\n" cfg.master.exports));
195 metalogger.settings = lib.mkIf cfg.metalogger.enable {
196 WORKING_USER = mfsUser;
197 MASTER_HOST = cfg.masterHost;
200 chunkserver.settings = lib.mkIf cfg.chunkserver.enable {
201 WORKING_USER = mfsUser;
202 MASTER_HOST = cfg.masterHost;
203 HDD_CONF_FILENAME = toString ( pkgs.writeText "mfshdd.cfg"
204 (lib.concatStringsSep "\n" cfg.chunkserver.hdds));
208 # Create system user account for daemons
209 users = lib.mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) ) {
212 description = "moosefs daemon user";
218 environment.systemPackages =
219 (lib.optional cfg.client.enable pkgs.moosefs) ++
220 (lib.optional cfg.master.enable initTool);
222 networking.firewall.allowedTCPPorts =
223 (lib.optionals cfg.master.openFirewall [ 9419 9420 9421 ]) ++
224 (lib.optional cfg.chunkserver.openFirewall 9422);
226 # Ensure storage directories exist
227 systemd.tmpfiles.rules =
228 lib.optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"
229 ++ lib.optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"
230 ++ lib.optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}";
232 # Service definitions
233 systemd.services.mfs-master = lib.mkIf cfg.master.enable
234 ( systemdService "master" {
235 TimeoutStartSec = 1800;
236 TimeoutStopSec = 1800;
240 systemd.services.mfs-metalogger = lib.mkIf cfg.metalogger.enable
241 ( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg );
243 systemd.services.mfs-chunkserver = lib.mkIf cfg.chunkserver.enable
244 ( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg );