2021-10-06 21:50:13 +02:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
|
|
cfg = config.services.moosefs;
|
|
|
|
|
|
|
|
mfsUser = if cfg.runAsUser then "moosefs" else "root";
|
|
|
|
|
|
|
|
settingsFormat = let
|
|
|
|
listSep = " ";
|
2024-08-28 21:18:58 +02:00
|
|
|
allowedTypes = with lib.types; [ bool int float str ];
|
2021-10-06 21:50:13 +02:00
|
|
|
valueToString = val:
|
2024-08-28 21:18:58 +02:00
|
|
|
if lib.isList val then lib.concatStringsSep listSep (map (x: valueToString x) val)
|
|
|
|
else if lib.isBool val then (if val then "1" else "0")
|
2021-10-06 21:50:13 +02:00
|
|
|
else toString val;
|
|
|
|
|
|
|
|
in {
|
2024-08-28 21:18:58 +02:00
|
|
|
type = with lib.types; let
|
2021-10-06 21:50:13 +02:00
|
|
|
valueType = oneOf ([
|
|
|
|
(listOf valueType)
|
|
|
|
] ++ allowedTypes) // {
|
|
|
|
description = "Flat key-value file";
|
|
|
|
};
|
|
|
|
in attrsOf valueType;
|
|
|
|
|
|
|
|
generate = name: value:
|
|
|
|
pkgs.writeText name ( lib.concatStringsSep "\n" (
|
|
|
|
lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value ));
|
|
|
|
};
|
|
|
|
|
2024-11-29 15:59:23 +01:00
|
|
|
# Manual initialization tool
|
2021-10-06 21:50:13 +02:00
|
|
|
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}
|
|
|
|
chmod +w ${cfg.master.settings.DATA_PATH}/metadata.mfs.empty
|
|
|
|
${pkgs.moosefs}/bin/mfsmaster -a -c ${masterCfg} start
|
|
|
|
${pkgs.moosefs}/bin/mfsmaster -c ${masterCfg} stop
|
|
|
|
rm ${cfg.master.settings.DATA_PATH}/metadata.mfs.empty
|
|
|
|
fi
|
|
|
|
'';
|
|
|
|
|
2024-11-29 15:59:23 +01:00
|
|
|
masterCfg = settingsFormat.generate "mfsmaster.cfg" cfg.master.settings;
|
|
|
|
metaloggerCfg = settingsFormat.generate "mfsmetalogger.cfg" cfg.metalogger.settings;
|
|
|
|
chunkserverCfg = settingsFormat.generate "mfschunkserver.cfg" cfg.chunkserver.settings;
|
2021-10-06 21:50:13 +02:00
|
|
|
|
|
|
|
systemdService = name: extraConfig: configFile: {
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
wants = [ "network-online.target" ];
|
|
|
|
after = [ "network.target" "network-online.target" ];
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "forking";
|
|
|
|
ExecStart = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} start";
|
|
|
|
ExecStop = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} stop";
|
|
|
|
ExecReload = "${pkgs.moosefs}/bin/mfs${name} -c ${configFile} reload";
|
|
|
|
PIDFile = "${cfg."${name}".settings.DATA_PATH}/.mfs${name}.lock";
|
|
|
|
} // extraConfig;
|
|
|
|
};
|
|
|
|
|
|
|
|
in {
|
|
|
|
###### interface
|
|
|
|
options = {
|
|
|
|
services.moosefs = {
|
2024-08-28 21:18:58 +02:00
|
|
|
masterHost = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2021-10-06 21:50:13 +02:00
|
|
|
default = null;
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "IP or DNS name of the MooseFS master server.";
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
runAsUser = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
2021-10-06 21:50:13 +02:00
|
|
|
default = true;
|
|
|
|
example = true;
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Run daemons as moosefs user instead of root for better security.";
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
|
2024-11-29 15:59:23 +01:00
|
|
|
client.enable = lib.mkEnableOption "MooseFS client";
|
2021-10-06 21:50:13 +02:00
|
|
|
|
|
|
|
master = {
|
2024-08-28 21:18:58 +02:00
|
|
|
enable = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
2021-10-06 21:50:13 +02:00
|
|
|
description = ''
|
2024-11-29 15:59:23 +01:00
|
|
|
Enable MooseFS master daemon.
|
|
|
|
The master server coordinates all MooseFS operations and stores metadata.
|
2021-10-06 21:50:13 +02:00
|
|
|
'';
|
|
|
|
default = false;
|
|
|
|
};
|
|
|
|
|
2024-11-29 15:59:23 +01:00
|
|
|
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.";
|
|
|
|
};
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
exports = lib.mkOption {
|
|
|
|
type = with lib.types; listOf str;
|
2021-10-06 21:50:13 +02:00
|
|
|
default = null;
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Export definitions for MooseFS (see mfsexports.cfg).";
|
2021-10-06 21:50:13 +02:00
|
|
|
example = [
|
|
|
|
"* / rw,alldirs,admin,maproot=0:0"
|
|
|
|
"* . rw"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
openFirewall = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Whether to automatically open required firewall ports for master service.";
|
2021-10-06 21:50:13 +02:00
|
|
|
default = false;
|
|
|
|
};
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
settings = lib.mkOption {
|
|
|
|
type = lib.types.submodule {
|
2021-10-06 21:50:13 +02:00
|
|
|
freeformType = settingsFormat.type;
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
options.DATA_PATH = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2021-10-06 21:50:13 +02:00
|
|
|
default = "/var/lib/mfs";
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Directory for storing master metadata.";
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
};
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Master configuration options (mfsmaster.cfg).";
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
metalogger = {
|
2024-11-29 15:59:23 +01:00
|
|
|
enable = lib.mkEnableOption "MooseFS metalogger daemon that maintains a backup copy of the master's metadata";
|
2021-10-06 21:50:13 +02:00
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
settings = lib.mkOption {
|
|
|
|
type = lib.types.submodule {
|
2021-10-06 21:50:13 +02:00
|
|
|
freeformType = settingsFormat.type;
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
options.DATA_PATH = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2021-10-06 21:50:13 +02:00
|
|
|
default = "/var/lib/mfs";
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Directory for storing metalogger data.";
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
};
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Metalogger configuration options (mfsmetalogger.cfg).";
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
chunkserver = {
|
2024-11-29 15:59:23 +01:00
|
|
|
enable = lib.mkEnableOption "MooseFS chunkserver daemon that stores file data";
|
2021-10-06 21:50:13 +02:00
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
openFirewall = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Whether to automatically open required firewall ports for chunkserver service.";
|
2021-10-06 21:50:13 +02:00
|
|
|
default = false;
|
|
|
|
};
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
hdds = lib.mkOption {
|
|
|
|
type = with lib.types; listOf str;
|
2024-11-29 15:59:23 +01:00
|
|
|
default = null;
|
|
|
|
description = "Mount points used by chunkserver for data storage (see mfshdd.cfg).";
|
|
|
|
example = [ "/mnt/hdd1" "/mnt/hdd2" ];
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
settings = lib.mkOption {
|
|
|
|
type = lib.types.submodule {
|
2021-10-06 21:50:13 +02:00
|
|
|
freeformType = settingsFormat.type;
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
options.DATA_PATH = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2021-10-06 21:50:13 +02:00
|
|
|
default = "/var/lib/mfs";
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "Directory for lock files and other runtime data.";
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
};
|
2024-11-29 15:59:23 +01:00
|
|
|
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.
|
|
|
|
'';
|
2021-10-06 21:50:13 +02:00
|
|
|
|
2024-11-29 15:59:23 +01:00
|
|
|
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.";
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
###### implementation
|
2024-11-29 15:59:23 +01:00
|
|
|
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.") ];
|
2021-10-06 21:50:13 +02:00
|
|
|
|
|
|
|
services.moosefs = {
|
2024-11-29 15:59:23 +01:00
|
|
|
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;
|
|
|
|
})
|
|
|
|
]);
|
2021-10-06 21:50:13 +02:00
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
metalogger.settings = lib.mkIf cfg.metalogger.enable {
|
2021-10-06 21:50:13 +02:00
|
|
|
WORKING_USER = mfsUser;
|
|
|
|
MASTER_HOST = cfg.masterHost;
|
|
|
|
};
|
|
|
|
|
2024-08-28 21:18:58 +02:00
|
|
|
chunkserver.settings = lib.mkIf cfg.chunkserver.enable {
|
2021-10-06 21:50:13 +02:00
|
|
|
WORKING_USER = mfsUser;
|
|
|
|
MASTER_HOST = cfg.masterHost;
|
|
|
|
HDD_CONF_FILENAME = toString ( pkgs.writeText "mfshdd.cfg"
|
2024-08-28 21:18:58 +02:00
|
|
|
(lib.concatStringsSep "\n" cfg.chunkserver.hdds));
|
2021-10-06 21:50:13 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-11-29 15:59:23 +01:00
|
|
|
users = lib.mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable || cfg.cgiserver.enable ) ) {
|
2021-10-06 21:50:13 +02:00
|
|
|
users.moosefs = {
|
|
|
|
isSystemUser = true;
|
2024-11-29 15:59:23 +01:00
|
|
|
description = "MooseFS daemon user";
|
2021-10-06 21:50:13 +02:00
|
|
|
group = "moosefs";
|
|
|
|
};
|
|
|
|
groups.moosefs = {};
|
|
|
|
};
|
|
|
|
|
|
|
|
environment.systemPackages =
|
|
|
|
(lib.optional cfg.client.enable pkgs.moosefs) ++
|
|
|
|
(lib.optional cfg.master.enable initTool);
|
|
|
|
|
2024-11-29 15:59:23 +01:00
|
|
|
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} -")
|
|
|
|
|
|
|
|
# Metalogger directories
|
|
|
|
(lib.optionalString cfg.metalogger.enable
|
|
|
|
"d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser} -")
|
|
|
|
|
|
|
|
# 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 = "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";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
})
|
|
|
|
];
|
|
|
|
};
|
2021-10-06 21:50:13 +02:00
|
|
|
}
|