Loading nixos/modules/services/network-filesystems/moosefs.nix +147 −74 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ let lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value )); }; # Manual initialization tool initTool = pkgs.writeShellScriptBin "mfsmaster-init" '' if [ ! -e ${cfg.master.settings.DATA_PATH}/metadata.mfs ]; then cp ${pkgs.moosefs}/var/mfs/metadata.mfs.empty ${cfg.master.settings.DATA_PATH} Loading @@ -37,19 +37,10 @@ let fi ''; # master config file masterCfg = settingsFormat.generate "mfsmaster.cfg" cfg.master.settings; # metalogger config file metaloggerCfg = settingsFormat.generate "mfsmetalogger.cfg" cfg.metalogger.settings; # chunkserver config file chunkserverCfg = settingsFormat.generate "mfschunkserver.cfg" cfg.chunkserver.settings; masterCfg = settingsFormat.generate "mfsmaster.cfg" cfg.master.settings; metaloggerCfg = settingsFormat.generate "mfsmetalogger.cfg" cfg.metalogger.settings; chunkserverCfg = settingsFormat.generate "mfschunkserver.cfg" cfg.chunkserver.settings; # generic template for all daemons systemdService = name: extraConfig: configFile: { wantedBy = [ "multi-user.target" ]; wants = [ "network-online.target" ]; Loading @@ -66,40 +57,43 @@ let in { ###### interface options = { services.moosefs = { masterHost = lib.mkOption { type = lib.types.str; default = null; description = "IP or DNS name of master host."; description = "IP or DNS name of the MooseFS master server."; }; runAsUser = lib.mkOption { type = lib.types.bool; default = true; example = true; description = "Run daemons as user moosefs instead of root."; description = "Run daemons as moosefs user instead of root for better security."; }; client.enable = lib.mkEnableOption "Moosefs client"; client.enable = lib.mkEnableOption "MooseFS client"; master = { enable = lib.mkOption { type = lib.types.bool; description = '' Enable Moosefs master daemon. You need to run `mfsmaster-init` on a freshly installed master server to initialize the `DATA_PATH` directory. Enable MooseFS master daemon. The master server coordinates all MooseFS operations and stores metadata. ''; default = false; }; autoInit = lib.mkOption { type = lib.types.bool; default = false; description = "Whether to automatically initialize the master's metadata directory on first run. Use with caution."; }; exports = lib.mkOption { type = with lib.types; listOf str; default = null; description = "Paths to export (see mfsexports.cfg)."; description = "Export definitions for MooseFS (see mfsexports.cfg)."; example = [ "* / rw,alldirs,admin,maproot=0:0" "* . rw" Loading @@ -108,7 +102,7 @@ in { openFirewall = lib.mkOption { type = lib.types.bool; description = "Whether to automatically open the necessary ports in the firewall."; description = "Whether to automatically open required firewall ports for master service."; default = false; }; Loading @@ -119,16 +113,15 @@ in { options.DATA_PATH = lib.mkOption { type = lib.types.str; default = "/var/lib/mfs"; description = "Data storage directory."; description = "Directory for storing master metadata."; }; }; description = "Contents of config file (mfsmaster.cfg)."; description = "Master configuration options (mfsmaster.cfg)."; }; }; metalogger = { enable = lib.mkEnableOption "Moosefs metalogger daemon"; enable = lib.mkEnableOption "MooseFS metalogger daemon that maintains a backup copy of the master's metadata"; settings = lib.mkOption { type = lib.types.submodule { Loading @@ -137,28 +130,27 @@ in { options.DATA_PATH = lib.mkOption { type = lib.types.str; default = "/var/lib/mfs"; description = "Data storage directory"; description = "Directory for storing metalogger data."; }; }; description = "Contents of metalogger config file (mfsmetalogger.cfg)."; description = "Metalogger configuration options (mfsmetalogger.cfg)."; }; }; chunkserver = { enable = lib.mkEnableOption "Moosefs chunkserver daemon"; enable = lib.mkEnableOption "MooseFS chunkserver daemon that stores file data"; openFirewall = lib.mkOption { type = lib.types.bool; description = "Whether to automatically open the necessary ports in the firewall."; description = "Whether to automatically open required firewall ports for chunkserver service."; default = false; }; hdds = lib.mkOption { type = with lib.types; listOf str; default = null; description = "Mount points to be used by chunkserver for storage (see mfshdd.cfg)."; example = [ "/mnt/hdd1" ]; description = "Mount points used by chunkserver for data storage (see mfshdd.cfg)."; example = [ "/mnt/hdd1" "/mnt/hdd2" ]; }; settings = lib.mkOption { Loading @@ -168,29 +160,65 @@ in { options.DATA_PATH = lib.mkOption { type = lib.types.str; default = "/var/lib/mfs"; description = "Directory for lock file."; description = "Directory for lock files and other runtime data."; }; }; description = "Chunkserver configuration options (mfschunkserver.cfg)."; }; }; cgiserver = { enable = lib.mkEnableOption '' MooseFS CGI server for web interface. Warning: The CGI server interface should be properly secured from unauthorized access, as it provides full control over your MooseFS installation. ''; openFirewall = lib.mkOption { type = lib.types.bool; description = "Whether to automatically open the web interface port."; default = false; }; settings = lib.mkOption { type = lib.types.submodule { freeformType = settingsFormat.type; options = { BIND_HOST = lib.mkOption { type = lib.types.str; default = "0.0.0.0"; description = "IP address to bind CGI server to."; }; description = "Contents of chunkserver config file (mfschunkserver.cfg)."; PORT = lib.mkOption { type = lib.types.port; default = 9425; description = "Port for CGI server to listen on."; }; }; }; default = {}; description = "CGI server configuration options."; }; }; }; }; ###### implementation config = lib.mkIf (cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable || cfg.cgiserver.enable) { warnings = [ ( lib.mkIf (!cfg.runAsUser) "Running MooseFS services as root is not recommended.") ]; config = lib.mkIf ( cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) { warnings = [ ( lib.mkIf (!cfg.runAsUser) "Running moosefs services as root is not recommended.") ]; # Service settings services.moosefs = { master.settings = lib.mkIf cfg.master.enable { master.settings = lib.mkIf cfg.master.enable (lib.mkMerge [ { WORKING_USER = mfsUser; EXPORTS_FILENAME = toString ( pkgs.writeText "mfsexports.cfg" (lib.concatStringsSep "\n" cfg.master.exports)); }; } (lib.mkIf cfg.cgiserver.enable { MFSCGISERV = toString cfg.cgiserver.settings.PORT; }) ]); metalogger.settings = lib.mkIf cfg.metalogger.enable { WORKING_USER = mfsUser; Loading @@ -205,11 +233,10 @@ in { }; }; # Create system user account for daemons users = lib.mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) ) { users = lib.mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable || cfg.cgiserver.enable ) ) { users.moosefs = { isSystemUser = true; description = "moosefs daemon user"; description = "MooseFS daemon user"; group = "moosefs"; }; groups.moosefs = {}; Loading @@ -219,28 +246,74 @@ in { (lib.optional cfg.client.enable pkgs.moosefs) ++ (lib.optional cfg.master.enable initTool); networking.firewall.allowedTCPPorts = (lib.optionals cfg.master.openFirewall [ 9419 9420 9421 ]) ++ (lib.optional cfg.chunkserver.openFirewall 9422); networking.firewall.allowedTCPPorts = lib.mkMerge [ (lib.optionals cfg.master.openFirewall [ 9419 9420 9421 ]) (lib.optional cfg.chunkserver.openFirewall 9422) (lib.optional (cfg.cgiserver.enable && cfg.cgiserver.openFirewall) cfg.cgiserver.settings.PORT) ]; systemd.tmpfiles.rules = [ # Master directories (lib.optionalString cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -") # Ensure storage directories exist systemd.tmpfiles.rules = lib.optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" ++ lib.optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" ++ lib.optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"; # Metalogger directories (lib.optionalString cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -") # Service definitions systemd.services.mfs-master = lib.mkIf cfg.master.enable # Chunkserver directories (lib.optionalString cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -") ] ++ lib.optionals (cfg.chunkserver.enable && cfg.chunkserver.hdds != null) (map (dir: "d ${dir} 0755 ${mfsUser} ${mfsUser} -") cfg.chunkserver.hdds); systemd.services = lib.mkMerge [ (lib.mkIf cfg.master.enable { mfs-master = (lib.mkMerge [ (systemdService "master" { TimeoutStartSec = 1800; TimeoutStopSec = 1800; Restart = "no"; } masterCfg ); systemd.services.mfs-metalogger = lib.mkIf cfg.metalogger.enable ( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg ); Restart = "on-failure"; User = mfsUser; } masterCfg) { preStart = lib.mkIf cfg.master.autoInit "${initTool}/bin/mfsmaster-init"; } ]); }) (lib.mkIf cfg.metalogger.enable { mfs-metalogger = systemdService "metalogger" { Restart = "on-abnormal"; User = mfsUser; } metaloggerCfg; }) (lib.mkIf cfg.chunkserver.enable { mfs-chunkserver = systemdService "chunkserver" { Restart = "on-abnormal"; User = mfsUser; } chunkserverCfg; }) (lib.mkIf cfg.cgiserver.enable { mfs-cgiserv = { description = "MooseFS CGI Server"; wantedBy = [ "multi-user.target" ]; after = [ "mfs-master.service" ]; systemd.services.mfs-chunkserver = lib.mkIf cfg.chunkserver.enable ( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg ); serviceConfig = { Type = "simple"; ExecStart = "${pkgs.moosefs}/bin/mfscgiserv -D /var/lib/mfs -f start"; ExecStop = "${pkgs.moosefs}/bin/mfscgiserv -D /var/lib/mfs stop"; Restart = "on-failure"; RestartSec = "30s"; User = mfsUser; Group = mfsUser; WorkingDirectory = "/var/lib/mfs"; }; }; }) ]; }; } nixos/tests/moosefs.nix +1 −2 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ import ./make-test-python.nix ( services.moosefs.master = { enable = true; openFirewall = true; autoInit = true; exports = [ "* / rw,alldirs,admin,maproot=0:0" "* . rw" Loading Loading @@ -76,8 +77,6 @@ import ./make-test-python.nix ( # prepare master server master.start() master.wait_for_unit("multi-user.target") master.succeed("mfsmaster-init") master.succeed("systemctl restart mfs-master") master.wait_for_unit("mfs-master.service") metalogger.wait_for_unit("mfs-metalogger.service") Loading Loading
nixos/modules/services/network-filesystems/moosefs.nix +147 −74 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ let lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value )); }; # Manual initialization tool initTool = pkgs.writeShellScriptBin "mfsmaster-init" '' if [ ! -e ${cfg.master.settings.DATA_PATH}/metadata.mfs ]; then cp ${pkgs.moosefs}/var/mfs/metadata.mfs.empty ${cfg.master.settings.DATA_PATH} Loading @@ -37,19 +37,10 @@ let fi ''; # master config file masterCfg = settingsFormat.generate "mfsmaster.cfg" cfg.master.settings; # metalogger config file metaloggerCfg = settingsFormat.generate "mfsmetalogger.cfg" cfg.metalogger.settings; # chunkserver config file chunkserverCfg = settingsFormat.generate "mfschunkserver.cfg" cfg.chunkserver.settings; masterCfg = settingsFormat.generate "mfsmaster.cfg" cfg.master.settings; metaloggerCfg = settingsFormat.generate "mfsmetalogger.cfg" cfg.metalogger.settings; chunkserverCfg = settingsFormat.generate "mfschunkserver.cfg" cfg.chunkserver.settings; # generic template for all daemons systemdService = name: extraConfig: configFile: { wantedBy = [ "multi-user.target" ]; wants = [ "network-online.target" ]; Loading @@ -66,40 +57,43 @@ let in { ###### interface options = { services.moosefs = { masterHost = lib.mkOption { type = lib.types.str; default = null; description = "IP or DNS name of master host."; description = "IP or DNS name of the MooseFS master server."; }; runAsUser = lib.mkOption { type = lib.types.bool; default = true; example = true; description = "Run daemons as user moosefs instead of root."; description = "Run daemons as moosefs user instead of root for better security."; }; client.enable = lib.mkEnableOption "Moosefs client"; client.enable = lib.mkEnableOption "MooseFS client"; master = { enable = lib.mkOption { type = lib.types.bool; description = '' Enable Moosefs master daemon. You need to run `mfsmaster-init` on a freshly installed master server to initialize the `DATA_PATH` directory. Enable MooseFS master daemon. The master server coordinates all MooseFS operations and stores metadata. ''; default = false; }; autoInit = lib.mkOption { type = lib.types.bool; default = false; description = "Whether to automatically initialize the master's metadata directory on first run. Use with caution."; }; exports = lib.mkOption { type = with lib.types; listOf str; default = null; description = "Paths to export (see mfsexports.cfg)."; description = "Export definitions for MooseFS (see mfsexports.cfg)."; example = [ "* / rw,alldirs,admin,maproot=0:0" "* . rw" Loading @@ -108,7 +102,7 @@ in { openFirewall = lib.mkOption { type = lib.types.bool; description = "Whether to automatically open the necessary ports in the firewall."; description = "Whether to automatically open required firewall ports for master service."; default = false; }; Loading @@ -119,16 +113,15 @@ in { options.DATA_PATH = lib.mkOption { type = lib.types.str; default = "/var/lib/mfs"; description = "Data storage directory."; description = "Directory for storing master metadata."; }; }; description = "Contents of config file (mfsmaster.cfg)."; description = "Master configuration options (mfsmaster.cfg)."; }; }; metalogger = { enable = lib.mkEnableOption "Moosefs metalogger daemon"; enable = lib.mkEnableOption "MooseFS metalogger daemon that maintains a backup copy of the master's metadata"; settings = lib.mkOption { type = lib.types.submodule { Loading @@ -137,28 +130,27 @@ in { options.DATA_PATH = lib.mkOption { type = lib.types.str; default = "/var/lib/mfs"; description = "Data storage directory"; description = "Directory for storing metalogger data."; }; }; description = "Contents of metalogger config file (mfsmetalogger.cfg)."; description = "Metalogger configuration options (mfsmetalogger.cfg)."; }; }; chunkserver = { enable = lib.mkEnableOption "Moosefs chunkserver daemon"; enable = lib.mkEnableOption "MooseFS chunkserver daemon that stores file data"; openFirewall = lib.mkOption { type = lib.types.bool; description = "Whether to automatically open the necessary ports in the firewall."; description = "Whether to automatically open required firewall ports for chunkserver service."; default = false; }; hdds = lib.mkOption { type = with lib.types; listOf str; default = null; description = "Mount points to be used by chunkserver for storage (see mfshdd.cfg)."; example = [ "/mnt/hdd1" ]; description = "Mount points used by chunkserver for data storage (see mfshdd.cfg)."; example = [ "/mnt/hdd1" "/mnt/hdd2" ]; }; settings = lib.mkOption { Loading @@ -168,29 +160,65 @@ in { options.DATA_PATH = lib.mkOption { type = lib.types.str; default = "/var/lib/mfs"; description = "Directory for lock file."; description = "Directory for lock files and other runtime data."; }; }; description = "Chunkserver configuration options (mfschunkserver.cfg)."; }; }; cgiserver = { enable = lib.mkEnableOption '' MooseFS CGI server for web interface. Warning: The CGI server interface should be properly secured from unauthorized access, as it provides full control over your MooseFS installation. ''; openFirewall = lib.mkOption { type = lib.types.bool; description = "Whether to automatically open the web interface port."; default = false; }; settings = lib.mkOption { type = lib.types.submodule { freeformType = settingsFormat.type; options = { BIND_HOST = lib.mkOption { type = lib.types.str; default = "0.0.0.0"; description = "IP address to bind CGI server to."; }; description = "Contents of chunkserver config file (mfschunkserver.cfg)."; PORT = lib.mkOption { type = lib.types.port; default = 9425; description = "Port for CGI server to listen on."; }; }; }; default = {}; description = "CGI server configuration options."; }; }; }; }; ###### implementation config = lib.mkIf (cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable || cfg.cgiserver.enable) { warnings = [ ( lib.mkIf (!cfg.runAsUser) "Running MooseFS services as root is not recommended.") ]; config = lib.mkIf ( cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) { warnings = [ ( lib.mkIf (!cfg.runAsUser) "Running moosefs services as root is not recommended.") ]; # Service settings services.moosefs = { master.settings = lib.mkIf cfg.master.enable { master.settings = lib.mkIf cfg.master.enable (lib.mkMerge [ { WORKING_USER = mfsUser; EXPORTS_FILENAME = toString ( pkgs.writeText "mfsexports.cfg" (lib.concatStringsSep "\n" cfg.master.exports)); }; } (lib.mkIf cfg.cgiserver.enable { MFSCGISERV = toString cfg.cgiserver.settings.PORT; }) ]); metalogger.settings = lib.mkIf cfg.metalogger.enable { WORKING_USER = mfsUser; Loading @@ -205,11 +233,10 @@ in { }; }; # Create system user account for daemons users = lib.mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) ) { users = lib.mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable || cfg.cgiserver.enable ) ) { users.moosefs = { isSystemUser = true; description = "moosefs daemon user"; description = "MooseFS daemon user"; group = "moosefs"; }; groups.moosefs = {}; Loading @@ -219,28 +246,74 @@ in { (lib.optional cfg.client.enable pkgs.moosefs) ++ (lib.optional cfg.master.enable initTool); networking.firewall.allowedTCPPorts = (lib.optionals cfg.master.openFirewall [ 9419 9420 9421 ]) ++ (lib.optional cfg.chunkserver.openFirewall 9422); networking.firewall.allowedTCPPorts = lib.mkMerge [ (lib.optionals cfg.master.openFirewall [ 9419 9420 9421 ]) (lib.optional cfg.chunkserver.openFirewall 9422) (lib.optional (cfg.cgiserver.enable && cfg.cgiserver.openFirewall) cfg.cgiserver.settings.PORT) ]; systemd.tmpfiles.rules = [ # Master directories (lib.optionalString cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -") # Ensure storage directories exist systemd.tmpfiles.rules = lib.optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" ++ lib.optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" ++ lib.optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"; # Metalogger directories (lib.optionalString cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -") # Service definitions systemd.services.mfs-master = lib.mkIf cfg.master.enable # Chunkserver directories (lib.optionalString cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -") ] ++ lib.optionals (cfg.chunkserver.enable && cfg.chunkserver.hdds != null) (map (dir: "d ${dir} 0755 ${mfsUser} ${mfsUser} -") cfg.chunkserver.hdds); systemd.services = lib.mkMerge [ (lib.mkIf cfg.master.enable { mfs-master = (lib.mkMerge [ (systemdService "master" { TimeoutStartSec = 1800; TimeoutStopSec = 1800; Restart = "no"; } masterCfg ); systemd.services.mfs-metalogger = lib.mkIf cfg.metalogger.enable ( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg ); Restart = "on-failure"; User = mfsUser; } masterCfg) { preStart = lib.mkIf cfg.master.autoInit "${initTool}/bin/mfsmaster-init"; } ]); }) (lib.mkIf cfg.metalogger.enable { mfs-metalogger = systemdService "metalogger" { Restart = "on-abnormal"; User = mfsUser; } metaloggerCfg; }) (lib.mkIf cfg.chunkserver.enable { mfs-chunkserver = systemdService "chunkserver" { Restart = "on-abnormal"; User = mfsUser; } chunkserverCfg; }) (lib.mkIf cfg.cgiserver.enable { mfs-cgiserv = { description = "MooseFS CGI Server"; wantedBy = [ "multi-user.target" ]; after = [ "mfs-master.service" ]; systemd.services.mfs-chunkserver = lib.mkIf cfg.chunkserver.enable ( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg ); serviceConfig = { Type = "simple"; ExecStart = "${pkgs.moosefs}/bin/mfscgiserv -D /var/lib/mfs -f start"; ExecStop = "${pkgs.moosefs}/bin/mfscgiserv -D /var/lib/mfs stop"; Restart = "on-failure"; RestartSec = "30s"; User = mfsUser; Group = mfsUser; WorkingDirectory = "/var/lib/mfs"; }; }; }) ]; }; }
nixos/tests/moosefs.nix +1 −2 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ import ./make-test-python.nix ( services.moosefs.master = { enable = true; openFirewall = true; autoInit = true; exports = [ "* / rw,alldirs,admin,maproot=0:0" "* . rw" Loading Loading @@ -76,8 +77,6 @@ import ./make-test-python.nix ( # prepare master server master.start() master.wait_for_unit("multi-user.target") master.succeed("mfsmaster-init") master.succeed("systemctl restart mfs-master") master.wait_for_unit("mfs-master.service") metalogger.wait_for_unit("mfs-metalogger.service") Loading