Unverified Commit 06677d51 authored by Markus Kowalewski's avatar Markus Kowalewski Committed by GitHub
Browse files

nixosModules.MooseFS: Improve (#360140)

parents 6045109e b3429b3e
Loading
Loading
Loading
Loading
+147 −74
Original line number Diff line number Diff line
@@ -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}
@@ -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" ];
@@ -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"
@@ -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;
        };

@@ -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 {
@@ -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 {
@@ -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;
@@ -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 = {};
@@ -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";
          };
        };
      })
    ];
  };
}
+1 −2
Original line number Diff line number Diff line
@@ -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"
@@ -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")