lol

Merge pull request #140891 from markuskowa/os-moosefs

nixos: init moosefs module and test

authored by

markuskowa and committed by
GitHub
768dd747 64cb9c78

+350
+7
nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
··· 170 170 </listitem> 171 171 <listitem> 172 172 <para> 173 + <link xlink:href="https://moosefs.com">moosefs</link>, fault 174 + tolerant petabyte distributed file system. Available as 175 + <link linkend="opt-services.moosefs">moosefs</link>. 176 + </para> 177 + </listitem> 178 + <listitem> 179 + <para> 173 180 <link xlink:href="https://github.com/ThomasLeister/prosody-filer">prosody-filer</link>, 174 181 a server for handling XMPP HTTP Upload requests. Available at 175 182 <link linkend="opt-services.prosody-filer.enable">services.prosody-filer</link>.
+3
nixos/doc/manual/release-notes/rl-2205.section.md
··· 51 51 52 52 - [BaGet](https://loic-sharma.github.io/BaGet/), a lightweight NuGet and symbol server. Available at [services.baget](#opt-services.baget.enable). 53 53 54 + - [moosefs](https://moosefs.com), fault tolerant petabyte distributed file system. 55 + Available as [moosefs](#opt-services.moosefs). 56 + 54 57 - [prosody-filer](https://github.com/ThomasLeister/prosody-filer), a server for handling XMPP HTTP Upload requests. Available at [services.prosody-filer](#opt-services.prosody-filer.enable). 55 58 56 59 - [ethercalc](https://github.com/audreyt/ethercalc), an online collaborative
+1
nixos/modules/module-list.nix
··· 682 682 ./services/network-filesystems/litestream/default.nix 683 683 ./services/network-filesystems/netatalk.nix 684 684 ./services/network-filesystems/nfsd.nix 685 + ./services/network-filesystems/moosefs.nix 685 686 ./services/network-filesystems/openafs/client.nix 686 687 ./services/network-filesystems/openafs/server.nix 687 688 ./services/network-filesystems/orangefs/server.nix
+249
nixos/modules/services/network-filesystems/moosefs.nix
··· 1 + { config, lib, pkgs, ... }: 2 + 3 + with lib; 4 + 5 + let 6 + cfg = config.services.moosefs; 7 + 8 + mfsUser = if cfg.runAsUser then "moosefs" else "root"; 9 + 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; 17 + 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; 26 + 27 + generate = name: value: 28 + pkgs.writeText name ( lib.concatStringsSep "\n" ( 29 + lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value )); 30 + }; 31 + 32 + 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 + ''; 42 + 43 + # master config file 44 + masterCfg = settingsFormat.generate 45 + "mfsmaster.cfg" cfg.master.settings; 46 + 47 + # metalogger config file 48 + metaloggerCfg = settingsFormat.generate 49 + "mfsmetalogger.cfg" cfg.metalogger.settings; 50 + 51 + # chunkserver config file 52 + chunkserverCfg = settingsFormat.generate 53 + "mfschunkserver.cfg" cfg.chunkserver.settings; 54 + 55 + # generic template for all deamons 56 + systemdService = name: extraConfig: configFile: { 57 + wantedBy = [ "multi-user.target" ]; 58 + wants = [ "network-online.target" ]; 59 + after = [ "network.target" "network-online.target" ]; 60 + 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 + }; 69 + 70 + in { 71 + ###### interface 72 + 73 + options = { 74 + services.moosefs = { 75 + masterHost = mkOption { 76 + type = types.str; 77 + default = null; 78 + description = "IP or DNS name of master host."; 79 + }; 80 + 81 + runAsUser = mkOption { 82 + type = types.bool; 83 + default = true; 84 + example = true; 85 + description = "Run daemons as user moosefs instead of root."; 86 + }; 87 + 88 + client.enable = mkEnableOption "Moosefs client."; 89 + 90 + master = { 91 + enable = mkOption { 92 + type = types.bool; 93 + description = '' 94 + Enable Moosefs master daemon. 95 + 96 + You need to run <literal>mfsmaster-init</literal> on a freshly installed master server to 97 + initialize the <literal>DATA_PATH</literal> direcory. 98 + ''; 99 + default = false; 100 + }; 101 + 102 + exports = mkOption { 103 + type = with types; listOf str; 104 + default = null; 105 + description = "Paths to export (see mfsexports.cfg)."; 106 + example = [ 107 + "* / rw,alldirs,admin,maproot=0:0" 108 + "* . rw" 109 + ]; 110 + }; 111 + 112 + openFirewall = mkOption { 113 + type = types.bool; 114 + description = "Whether to automatically open the necessary ports in the firewall."; 115 + default = false; 116 + }; 117 + 118 + settings = mkOption { 119 + type = types.submodule { 120 + freeformType = settingsFormat.type; 121 + 122 + options.DATA_PATH = mkOption { 123 + type = types.str; 124 + default = "/var/lib/mfs"; 125 + description = "Data storage directory."; 126 + }; 127 + }; 128 + 129 + description = "Contents of config file (mfsmaster.cfg)."; 130 + }; 131 + }; 132 + 133 + metalogger = { 134 + enable = mkEnableOption "Moosefs metalogger daemon."; 135 + 136 + settings = mkOption { 137 + type = types.submodule { 138 + freeformType = settingsFormat.type; 139 + 140 + options.DATA_PATH = mkOption { 141 + type = types.str; 142 + default = "/var/lib/mfs"; 143 + description = "Data storage directory"; 144 + }; 145 + }; 146 + 147 + description = "Contents of metalogger config file (mfsmetalogger.cfg)."; 148 + }; 149 + }; 150 + 151 + chunkserver = { 152 + enable = mkEnableOption "Moosefs chunkserver daemon."; 153 + 154 + openFirewall = mkOption { 155 + type = types.bool; 156 + description = "Whether to automatically open the necessary ports in the firewall."; 157 + default = false; 158 + }; 159 + 160 + hdds = mkOption { 161 + type = with types; listOf str; 162 + default = null; 163 + description = "Mount points to be used by chunkserver for storage (see mfshdd.cfg)."; 164 + example = [ "/mnt/hdd1" ]; 165 + }; 166 + 167 + settings = mkOption { 168 + type = types.submodule { 169 + freeformType = settingsFormat.type; 170 + 171 + options.DATA_PATH = mkOption { 172 + type = types.str; 173 + default = "/var/lib/mfs"; 174 + description = "Directory for lock file."; 175 + }; 176 + }; 177 + 178 + description = "Contents of chunkserver config file (mfschunkserver.cfg)."; 179 + }; 180 + }; 181 + }; 182 + }; 183 + 184 + ###### implementation 185 + 186 + config = mkIf ( cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) { 187 + 188 + warnings = [ ( mkIf (!cfg.runAsUser) "Running moosefs services as root is not recommended.") ]; 189 + 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 + }; 197 + 198 + metalogger.settings = mkIf cfg.metalogger.enable { 199 + WORKING_USER = mfsUser; 200 + MASTER_HOST = cfg.masterHost; 201 + }; 202 + 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 + }; 210 + 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 + }; 220 + 221 + environment.systemPackages = 222 + (lib.optional cfg.client.enable pkgs.moosefs) ++ 223 + (lib.optional cfg.master.enable initTool); 224 + 225 + networking.firewall.allowedTCPPorts = 226 + (lib.optionals cfg.master.openFirewall [ 9419 9420 9421 ]) ++ 227 + (lib.optional cfg.chunkserver.openFirewall 9422); 228 + 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}"; 234 + 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 ); 242 + 243 + systemd.services.mfs-metalogger = mkIf cfg.metalogger.enable 244 + ( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg ); 245 + 246 + systemd.services.mfs-chunkserver = mkIf cfg.chunkserver.enable 247 + ( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg ); 248 + }; 249 + }
+1
nixos/tests/all-tests.nix
··· 305 305 moodle = handleTest ./moodle.nix {}; 306 306 morty = handleTest ./morty.nix {}; 307 307 mosquitto = handleTest ./mosquitto.nix {}; 308 + moosefs = handleTest ./moosefs.nix {}; 308 309 mpd = handleTest ./mpd.nix {}; 309 310 mpv = handleTest ./mpv.nix {}; 310 311 mumble = handleTest ./mumble.nix {};
+89
nixos/tests/moosefs.nix
··· 1 + import ./make-test-python.nix ({ pkgs, ... } : 2 + 3 + let 4 + master = { pkgs, ... } : { 5 + # data base is stored in memory 6 + # server crashes with default memory size 7 + virtualisation.memorySize = 1024; 8 + 9 + services.moosefs.master = { 10 + enable = true; 11 + openFirewall = true; 12 + exports = [ 13 + "* / rw,alldirs,admin,maproot=0:0" 14 + "* . rw" 15 + ]; 16 + }; 17 + }; 18 + 19 + chunkserver = { pkgs, ... } : { 20 + virtualisation.emptyDiskImages = [ 4096 ]; 21 + boot.initrd.postDeviceCommands = '' 22 + ${pkgs.e2fsprogs}/bin/mkfs.ext4 -L data /dev/vdb 23 + ''; 24 + 25 + fileSystems = pkgs.lib.mkVMOverride { 26 + "/data" = { 27 + device = "/dev/disk/by-label/data"; 28 + fsType = "ext4"; 29 + }; 30 + }; 31 + 32 + services.moosefs = { 33 + masterHost = "master"; 34 + chunkserver = { 35 + openFirewall = true; 36 + enable = true; 37 + hdds = [ "~/data" ]; 38 + }; 39 + }; 40 + }; 41 + 42 + metalogger = { pkgs, ... } : { 43 + services.moosefs = { 44 + masterHost = "master"; 45 + metalogger.enable = true; 46 + }; 47 + }; 48 + 49 + client = { pkgs, ... } : { 50 + services.moosefs.client.enable = true; 51 + }; 52 + 53 + in { 54 + name = "moosefs"; 55 + 56 + nodes= { 57 + inherit master; 58 + inherit metalogger; 59 + chunkserver1 = chunkserver; 60 + chunkserver2 = chunkserver; 61 + client1 = client; 62 + client2 = client; 63 + }; 64 + 65 + testScript = '' 66 + # prepare master server 67 + master.start() 68 + master.wait_for_unit("multi-user.target") 69 + master.succeed("mfsmaster-init") 70 + master.succeed("systemctl restart mfs-master") 71 + master.wait_for_unit("mfs-master.service") 72 + 73 + metalogger.wait_for_unit("mfs-metalogger.service") 74 + 75 + for chunkserver in [chunkserver1, chunkserver2]: 76 + chunkserver.wait_for_unit("multi-user.target") 77 + chunkserver.succeed("chown moosefs:moosefs /data") 78 + chunkserver.succeed("systemctl restart mfs-chunkserver") 79 + chunkserver.wait_for_unit("mfs-chunkserver.service") 80 + 81 + for client in [client1, client2]: 82 + client.wait_for_unit("multi-user.target") 83 + client.succeed("mkdir /moosefs") 84 + client.succeed("mount -t moosefs master:/ /moosefs") 85 + 86 + client1.succeed("echo test > /moosefs/file") 87 + client2.succeed("grep test /moosefs/file") 88 + ''; 89 + })