nixosModules.MooseFS: Improve

Changed files
+144 -72
nixos
modules
services
network-filesystems
tests
+143 -70
nixos/modules/services/network-filesystems/moosefs.nix
···
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}
···
fi
'';
-
# master config file
-
masterCfg = settingsFormat.generate
-
"mfsmaster.cfg" cfg.master.settings;
-
-
# metalogger config file
-
metaloggerCfg = settingsFormat.generate
-
"mfsmetalogger.cfg" cfg.metalogger.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;
-
# chunkserver config file
-
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" ];
···
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"
···
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;
};
···
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 {
···
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" ];
+
default = null;
+
description = "Mount points used by chunkserver for data storage (see mfshdd.cfg).";
+
example = [ "/mnt/hdd1" "/mnt/hdd2" ];
};
settings = lib.mkOption {
···
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).";
+
};
+
};
-
description = "Contents of chunkserver config file (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.";
+
};
+
+
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 ) {
-
-
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 || cfg.cgiserver.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 {
-
WORKING_USER = mfsUser;
-
EXPORTS_FILENAME = toString ( pkgs.writeText "mfsexports.cfg"
-
(lib.concatStringsSep "\n" cfg.master.exports));
-
};
+
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;
···
};
};
-
# 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 = {};
···
(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)
+
];
-
# 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}";
+
systemd.tmpfiles.rules = [
+
# Master directories
+
(lib.optionalString cfg.master.enable
+
"d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -")
-
# Service definitions
-
systemd.services.mfs-master = lib.mkIf cfg.master.enable
-
( systemdService "master" {
-
TimeoutStartSec = 1800;
-
TimeoutStopSec = 1800;
-
Restart = "no";
-
} masterCfg );
+
# Metalogger directories
+
(lib.optionalString cfg.metalogger.enable
+
"d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -")
-
systemd.services.mfs-metalogger = lib.mkIf cfg.metalogger.enable
-
( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg );
+
# 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.mfs-chunkserver = lib.mkIf cfg.chunkserver.enable
-
( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg );
-
};
+
systemd.services = lib.mkMerge [
+
(lib.mkIf cfg.master.enable {
+
mfs-master = (lib.mkMerge [
+
(systemdService "master" {
+
TimeoutStartSec = 1800;
+
TimeoutStopSec = 1800;
+
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" ];
+
+
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";
+
};
+
};
+
})
+
];
+
};
}
+1 -2
nixos/tests/moosefs.nix
···
services.moosefs.master = {
enable = true;
openFirewall = true;
+
autoInit = true;
exports = [
"* / rw,alldirs,admin,maproot=0:0"
"* . rw"
···
# 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")