nixos/preload: init
[NixPkgs.git] / nixos / modules / services / network-filesystems / moosefs.nix
blob49cbc89d5a91f1eebef72d64d33011bfd7842f9e
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.moosefs;
8   mfsUser = if cfg.runAsUser then "moosefs" else "root";
10   settingsFormat = let
11     listSep = " ";
12     allowedTypes = with types; [ bool int float str ];
13     valueToString = val:
14         if isList val then concatStringsSep listSep (map (x: valueToString x) val)
15         else if isBool val then (if val then "1" else "0")
16         else toString val;
18     in {
19       type = with types; let
20         valueType = oneOf ([
21           (listOf valueType)
22         ] ++ allowedTypes) // {
23           description = "Flat key-value file";
24         };
25       in attrsOf valueType;
27       generate = name: value:
28         pkgs.writeText name ( lib.concatStringsSep "\n" (
29           lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value ));
30     };
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
40     fi
41   '';
43   # master config file
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" ];
61     serviceConfig = {
62       Type = "forking";
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";
67     } // extraConfig;
68   };
70 in {
71   ###### interface
73   options = {
74     services.moosefs = {
75       masterHost = mkOption {
76         type = types.str;
77         default = null;
78         description = lib.mdDoc "IP or DNS name of master host.";
79       };
81       runAsUser = mkOption {
82         type = types.bool;
83         default = true;
84         example = true;
85         description = lib.mdDoc "Run daemons as user moosefs instead of root.";
86       };
88       client.enable = mkEnableOption (lib.mdDoc "Moosefs client");
90       master = {
91         enable = mkOption {
92           type = types.bool;
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.
98           '';
99           default = false;
100         };
102         exports = mkOption {
103           type = with types; listOf str;
104           default = null;
105           description = lib.mdDoc "Paths to export (see mfsexports.cfg).";
106           example = [
107             "* / rw,alldirs,admin,maproot=0:0"
108             "* . rw"
109           ];
110         };
112         openFirewall = mkOption {
113           type = types.bool;
114           description = lib.mdDoc "Whether to automatically open the necessary ports in the firewall.";
115           default = false;
116         };
118         settings = mkOption {
119           type = types.submodule {
120             freeformType = settingsFormat.type;
122             options.DATA_PATH = mkOption {
123               type = types.str;
124               default = "/var/lib/mfs";
125               description = lib.mdDoc "Data storage directory.";
126             };
127           };
129           description = lib.mdDoc "Contents of config file (mfsmaster.cfg).";
130         };
131       };
133       metalogger = {
134         enable = mkEnableOption (lib.mdDoc "Moosefs metalogger daemon");
136         settings = mkOption {
137           type = types.submodule {
138             freeformType = settingsFormat.type;
140             options.DATA_PATH = mkOption {
141               type = types.str;
142               default = "/var/lib/mfs";
143               description = lib.mdDoc "Data storage directory";
144             };
145           };
147           description = lib.mdDoc "Contents of metalogger config file (mfsmetalogger.cfg).";
148         };
149       };
151       chunkserver = {
152         enable = mkEnableOption (lib.mdDoc "Moosefs chunkserver daemon");
154         openFirewall = mkOption {
155           type = types.bool;
156           description = lib.mdDoc "Whether to automatically open the necessary ports in the firewall.";
157           default = false;
158         };
160         hdds = mkOption {
161           type = with types; listOf str;
162           default =  null;
163           description = lib.mdDoc "Mount points to be used by chunkserver for storage (see mfshdd.cfg).";
164           example = [ "/mnt/hdd1" ];
165         };
167         settings = mkOption {
168           type = types.submodule {
169             freeformType = settingsFormat.type;
171             options.DATA_PATH = mkOption {
172               type = types.str;
173               default = "/var/lib/mfs";
174               description = lib.mdDoc "Directory for lock file.";
175             };
176           };
178           description = lib.mdDoc "Contents of chunkserver config file (mfschunkserver.cfg).";
179         };
180       };
181     };
182   };
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.") ];
190     # Service settings
191     services.moosefs = {
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));
196       };
198       metalogger.settings = mkIf cfg.metalogger.enable {
199         WORKING_USER = mfsUser;
200         MASTER_HOST = cfg.masterHost;
201       };
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));
208       };
209     };
211     # Create system user account for daemons
212     users = mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) ) {
213       users.moosefs = {
214         isSystemUser = true;
215         description = "moosefs daemon user";
216         group = "moosefs";
217       };
218       groups.moosefs = {};
219     };
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;
240       Restart = "no";
241     } masterCfg );
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 );
248     };