parent
d1d974caea
commit
b302bda010
@ -0,0 +1,252 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.moosefs; |
||||
|
||||
mfsUser = if cfg.runAsUser then "moosefs" else "root"; |
||||
|
||||
settingsFormat = let |
||||
|
||||
listSep = " "; |
||||
allowedTypes = with types; [ bool int float str ]; |
||||
valueToString = val: |
||||
if isList val then concatStringsSep listSep (map (x: valueToString x) val) |
||||
else if isBool val then (if val then "1" else "0") |
||||
else toString val; |
||||
|
||||
in { |
||||
type = with types; let |
||||
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 )); |
||||
}; |
||||
|
||||
|
||||
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 |
||||
''; |
||||
|
||||
# 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; |
||||
|
||||
# generic template for all deamons |
||||
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 = { |
||||
masterHost = mkOption { |
||||
type = types.str; |
||||
default = null; |
||||
description = "IP or DNS name of master host."; |
||||
}; |
||||
|
||||
runAsUser = mkOption { |
||||
type = types.bool; |
||||
default = true; |
||||
example = true; |
||||
description = "Run daemons as user moosefs instead of root."; |
||||
}; |
||||
|
||||
client.enable = mkEnableOption "Moosefs client."; |
||||
|
||||
master = { |
||||
enable = mkOption { |
||||
type = types.bool; |
||||
description = '' |
||||
Enable Moosefs master daemon. |
||||
|
||||
You need to run <literal>mfsmaster-init</literal> on a freshly installed master server to |
||||
initialize the <literal>DATA_PATH</literal> direcory. |
||||
''; |
||||
default = false; |
||||
}; |
||||
|
||||
|
||||
exports = mkOption { |
||||
type = with types; listOf str; |
||||
default = null; |
||||
description = "Paths to export (see mfsexports.cfg)."; |
||||
example = [ |
||||
"* / rw,alldirs,admin,maproot=0:0" |
||||
"* . rw" |
||||
]; |
||||
}; |
||||
|
||||
openFirewall = mkOption { |
||||
type = types.bool; |
||||
description = "Whether to automatically open the necessary ports in the firewall."; |
||||
default = false; |
||||
}; |
||||
|
||||
settings = mkOption { |
||||
type = types.submodule { |
||||
freeformType = settingsFormat.type; |
||||
|
||||
options.DATA_PATH = mkOption { |
||||
type = types.str; |
||||
default = "/var/lib/mfs"; |
||||
description = "Data storage directory."; |
||||
}; |
||||
}; |
||||
|
||||
description = "Contents of config file (mfsmaster.cfg)."; |
||||
}; |
||||
}; |
||||
|
||||
metalogger = { |
||||
enable = mkEnableOption "Moosefs metalogger daemon."; |
||||
|
||||
settings = mkOption { |
||||
type = types.submodule { |
||||
freeformType = settingsFormat.type; |
||||
|
||||
options.DATA_PATH = mkOption { |
||||
type = types.str; |
||||
default = "/var/lib/mfs"; |
||||
description = "Data storage directory"; |
||||
}; |
||||
}; |
||||
|
||||
description = "Contents of metalogger config file (mfsmetalogger.cfg)."; |
||||
}; |
||||
}; |
||||
|
||||
chunkserver = { |
||||
enable = mkEnableOption "Moosefs chunkserver daemon."; |
||||
|
||||
openFirewall = mkOption { |
||||
type = types.bool; |
||||
description = "Whether to automatically open the necessary ports in the firewall."; |
||||
default = false; |
||||
}; |
||||
|
||||
hdds = mkOption { |
||||
type = with types; listOf str; |
||||
default = null; |
||||
description = "Mount points to be used by chunkserver for storage (see mfshdd.cfg)."; |
||||
example = [ "/mnt/hdd1" ]; |
||||
}; |
||||
|
||||
settings = mkOption { |
||||
type = types.submodule { |
||||
freeformType = settingsFormat.type; |
||||
|
||||
options.DATA_PATH = mkOption { |
||||
type = types.str; |
||||
default = "/var/lib/mfs"; |
||||
description = "Directory for lock file."; |
||||
}; |
||||
}; |
||||
|
||||
description = "Contents of chunkserver config file (mfschunkserver.cfg)."; |
||||
}; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf ( cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) { |
||||
|
||||
warnings = [ ( mkIf (!cfg.runAsUser) "Running moosefs services as root is not recommended.") ]; |
||||
|
||||
# Service settings |
||||
services.moosefs = { |
||||
master.settings = mkIf cfg.master.enable { |
||||
WORKING_USER = mfsUser; |
||||
EXPORTS_FILENAME = toString ( pkgs.writeText "mfsexports.cfg" |
||||
(concatStringsSep "\n" cfg.master.exports)); |
||||
}; |
||||
|
||||
metalogger.settings = mkIf cfg.metalogger.enable { |
||||
WORKING_USER = mfsUser; |
||||
MASTER_HOST = cfg.masterHost; |
||||
}; |
||||
|
||||
chunkserver.settings = mkIf cfg.chunkserver.enable { |
||||
WORKING_USER = mfsUser; |
||||
MASTER_HOST = cfg.masterHost; |
||||
HDD_CONF_FILENAME = toString ( pkgs.writeText "mfshdd.cfg" |
||||
(concatStringsSep "\n" cfg.chunkserver.hdds)); |
||||
}; |
||||
}; |
||||
|
||||
# Create system user account for daemons |
||||
users = mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) ) { |
||||
users.moosefs = { |
||||
isSystemUser = true; |
||||
description = "moosefs daemon user"; |
||||
group = "moosefs"; |
||||
}; |
||||
groups.moosefs = {}; |
||||
}; |
||||
|
||||
environment.systemPackages = |
||||
(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); |
||||
|
||||
# Ensure storage directories exist |
||||
systemd.tmpfiles.rules = |
||||
optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" |
||||
++ optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" |
||||
++ optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"; |
||||
|
||||
# Service definitions |
||||
systemd.services.mfs-master = mkIf cfg.master.enable |
||||
( systemdService "master" { |
||||
TimeoutStartSec = 1800; |
||||
TimeoutStopSec = 1800; |
||||
Restart = "no"; |
||||
} masterCfg ); |
||||
|
||||
systemd.services.mfs-metalogger = mkIf cfg.metalogger.enable |
||||
( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg ); |
||||
|
||||
systemd.services.mfs-chunkserver = mkIf cfg.chunkserver.enable |
||||
( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg ); |
||||
}; |
||||
} |
||||
|
Loading…
Reference in new issue