1 { config, lib, options, pkgs, ... }:
7 cfg = config.services.slurm;
8 opt = options.services.slurm;
9 # configuration file can be generated by https://slurm.schedmd.com/configurator.html
11 defaultUser = "slurm";
13 configFile = pkgs.writeTextDir "slurm.conf"
15 ClusterName=${cfg.clusterName}
16 StateSaveLocation=${cfg.stateSaveLocation}
18 ${optionalString (cfg.controlMachine != null) "controlMachine=${cfg.controlMachine}"}
19 ${optionalString (cfg.controlAddr != null) "controlAddr=${cfg.controlAddr}"}
20 ${toString (map (x: "NodeName=${x}\n") cfg.nodeName)}
21 ${toString (map (x: "PartitionName=${x}\n") cfg.partitionName)}
22 PlugStackConfig=${plugStackConfig}/plugstack.conf
23 ProctrackType=${cfg.procTrackType}
27 plugStackConfig = pkgs.writeTextDir "plugstack.conf"
29 ${optionalString cfg.enableSrunX11 "optional ${pkgs.slurm-spank-x11}/lib/x11.so"}
30 ${cfg.extraPlugstackConfig}
33 cgroupConfig = pkgs.writeTextDir "cgroup.conf"
35 ${cfg.extraCgroupConfig}
38 slurmdbdConf = pkgs.writeText "slurmdbd.conf"
40 DbdHost=${cfg.dbdserver.dbdHost}
42 StorageType=accounting_storage/mysql
43 StorageUser=${cfg.dbdserver.storageUser}
44 ${cfg.dbdserver.extraConfig}
47 # slurm expects some additional config files to be
48 # in the same directory as slurm.conf
49 etcSlurm = pkgs.symlinkJoin {
51 paths = [ configFile cgroupConfig plugStackConfig ] ++ cfg.extraConfigPaths;
59 meta.maintainers = [ maintainers.markuskowa ];
69 description = lib.mdDoc ''
70 Whether to enable the slurm control daemon.
71 Note that the standard authentication method is "munge".
72 The "munge" service needs to be provided with a password file in order for
73 slurm to work properly (see `services.munge.password`).
79 enable = mkEnableOption (lib.mdDoc "SlurmDBD service");
83 default = config.networking.hostName;
84 defaultText = literalExpression "config.networking.hostName";
85 description = lib.mdDoc ''
86 Hostname of the machine where `slurmdbd`
87 is running (i.e. name returned by `hostname -s`).
91 storageUser = mkOption {
94 defaultText = literalExpression "config.${opt.user}";
95 description = lib.mdDoc ''
100 storagePassFile = mkOption {
101 type = with types; nullOr str;
103 description = lib.mdDoc ''
104 Path to file with database password. The content of this will be used to
105 create the password for the `StoragePass` option.
109 extraConfig = mkOption {
112 description = lib.mdDoc ''
113 Extra configuration for `slurmdbd.conf` See also:
114 {manpage}`slurmdbd.conf(8)`.
120 enable = mkEnableOption (lib.mdDoc "slurm client daemon");
123 enableStools = mkOption {
126 description = lib.mdDoc ''
127 Whether to provide a slurm.conf file.
128 Enable this option if you do not run a slurm daemon on this host
129 (i.e. `server.enable` and `client.enable` are `false`)
130 but you still want to run slurm commands from this host.
135 type = types.package;
136 default = pkgs.slurm.override { enableX11 = ! cfg.enableSrunX11; };
137 defaultText = literalExpression "pkgs.slurm";
138 example = literalExpression "pkgs.slurm-full";
139 description = lib.mdDoc ''
140 The package to use for slurm binaries.
144 controlMachine = mkOption {
145 type = types.nullOr types.str;
148 description = lib.mdDoc ''
149 The short hostname of the machine where SLURM control functions are
150 executed (i.e. the name returned by the command "hostname -s", use "tux001"
151 rather than "tux001.my.com").
155 controlAddr = mkOption {
156 type = types.nullOr types.str;
157 default = cfg.controlMachine;
158 defaultText = literalExpression "config.${opt.controlMachine}";
160 description = lib.mdDoc ''
161 Name that ControlMachine should be referred to in establishing a
166 clusterName = mkOption {
169 example = "myCluster";
170 description = lib.mdDoc ''
171 Necessary to distinguish accounting records in a multi-cluster environment.
175 nodeName = mkOption {
176 type = types.listOf types.str;
178 example = literalExpression ''[ "linux[1-32] CPUs=1 State=UNKNOWN" ];'';
179 description = lib.mdDoc ''
180 Name that SLURM uses to refer to a node (or base partition for BlueGene
181 systems). Typically this would be the string that "/bin/hostname -s"
182 returns. Note that now you have to write node's parameters after the name.
186 partitionName = mkOption {
187 type = types.listOf types.str;
189 example = literalExpression ''[ "debug Nodes=linux[1-32] Default=YES MaxTime=INFINITE State=UP" ];'';
190 description = lib.mdDoc ''
191 Name by which the partition may be referenced. Note that now you have
192 to write the partition's parameters after the name.
196 enableSrunX11 = mkOption {
199 description = lib.mdDoc ''
200 If enabled srun will accept the option "--x11" to allow for X11 forwarding
201 from within an interactive session or a batch job. This activates the
202 slurm-spank-x11 module. Note that this option also enables
203 {option}`services.openssh.forwardX11` on the client.
205 This option requires slurm to be compiled without native X11 support.
206 The default behavior is to re-compile the slurm package with native X11
207 support disabled if this option is set to true.
209 To use the native X11 support add `PrologFlags=X11` in {option}`extraConfig`.
210 Note that this method will only work RSA SSH host keys.
214 procTrackType = mkOption {
216 default = "proctrack/linuxproc";
217 description = lib.mdDoc ''
218 Plugin to be used for process tracking on a job step basis.
219 The slurmd daemon uses this mechanism to identify all processes
220 which are children of processes it spawns for a user job step.
224 stateSaveLocation = mkOption {
226 default = "/var/spool/slurmctld";
227 description = lib.mdDoc ''
228 Directory into which the Slurm controller, slurmctld, saves its state.
234 default = defaultUser;
235 description = lib.mdDoc ''
236 Set this option when you want to run the slurmctld daemon
237 as something else than the default slurm user "slurm".
238 Note that the UID of this user needs to be the same
243 extraConfig = mkOption {
246 description = lib.mdDoc ''
247 Extra configuration options that will be added verbatim at
248 the end of the slurm configuration file.
252 extraPlugstackConfig = mkOption {
255 description = lib.mdDoc ''
256 Extra configuration that will be added to the end of `plugstack.conf`.
260 extraCgroupConfig = mkOption {
263 description = lib.mdDoc ''
264 Extra configuration for `cgroup.conf`. This file is
265 used when `procTrackType=proctrack/cgroup`.
269 extraConfigPaths = mkOption {
270 type = with types; listOf path;
272 description = lib.mdDoc ''
273 Slurm expects config files for plugins in the same path
274 as `slurm.conf`. Add extra nix store
275 paths that should be merged into same directory as
280 etcSlurm = mkOption {
284 defaultText = literalMD ''
285 Directory created from generated config files and
286 `config.${opt.extraConfigPaths}`.
288 description = lib.mdDoc ''
289 Path to directory with slurm config files. This option is set by default from the
290 Slurm module and is meant to make the Slurm config file available to other modules.
299 (mkRemovedOptionModule [ "services" "slurm" "dbdserver" "storagePass" ] ''
300 This option has been removed so that the database password is not exposed via the nix store.
301 Use services.slurm.dbdserver.storagePassFile to provide the database password.
303 (mkRemovedOptionModule [ "services" "slurm" "dbdserver" "configFile" ] ''
304 This option has been removed. Use services.slurm.dbdserver.storagePassFile
305 and services.slurm.dbdserver.extraConfig instead.
309 ###### implementation
313 wrappedSlurm = pkgs.stdenv.mkDerivation {
314 name = "wrappedSlurm";
316 builder = pkgs.writeText "builder.sh" ''
319 find ${getBin cfg.package}/bin -type f -executable | while read EXE
321 exename="$(basename $EXE)"
322 wrappername="$out/bin/$exename"
323 cat > "$wrappername" <<EOT
325 if [ -z "$SLURM_CONF" ]
327 SLURM_CONF="${cfg.etcSlurm}/slurm.conf" "$EXE" "\$@"
332 chmod +x "$wrappername"
336 ln -s ${getBin cfg.package}/share/man $out/share/man
340 in mkIf ( cfg.enableStools ||
343 cfg.dbdserver.enable ) {
345 environment.systemPackages = [ wrappedSlurm ];
347 services.munge.enable = mkDefault true;
349 # use a static uid as default to ensure it is the same on all nodes
350 users.users.slurm = mkIf (cfg.user == defaultUser) {
353 uid = config.ids.uids.slurm;
356 users.groups.slurm.gid = config.ids.uids.slurm;
358 systemd.services.slurmd = mkIf (cfg.client.enable) {
359 path = with pkgs; [ wrappedSlurm coreutils ]
360 ++ lib.optional cfg.enableSrunX11 slurm-spank-x11;
362 wantedBy = [ "multi-user.target" ];
364 "systemd-tmpfiles-clean.service"
366 "network-online.target"
369 wants = [ "network-online.target" ];
373 KillMode = "process";
374 ExecStart = "${wrappedSlurm}/bin/slurmd";
375 PIDFile = "/run/slurmd.pid";
376 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
377 LimitMEMLOCK = "infinity";
382 systemd.tmpfiles.rules = mkIf cfg.client.enable [
383 "d /var/spool/slurmd 755 root root -"
386 services.openssh.settings.X11Forwarding = mkIf cfg.client.enable (mkDefault true);
388 systemd.services.slurmctld = mkIf (cfg.server.enable) {
389 path = with pkgs; [ wrappedSlurm munge coreutils ]
390 ++ lib.optional cfg.enableSrunX11 slurm-spank-x11;
392 wantedBy = [ "multi-user.target" ];
393 after = [ "network.target" "munged.service" ];
394 requires = [ "munged.service" ];
398 ExecStart = "${wrappedSlurm}/bin/slurmctld";
399 PIDFile = "/run/slurmctld.pid";
400 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
404 mkdir -p ${cfg.stateSaveLocation}
405 chown -R ${cfg.user}:slurm ${cfg.stateSaveLocation}
409 systemd.services.slurmdbd = let
410 # slurm strips the last component off the path
411 configPath = "$RUNTIME_DIRECTORY/slurmdbd.conf";
412 in mkIf (cfg.dbdserver.enable) {
413 path = with pkgs; [ wrappedSlurm munge coreutils ];
415 wantedBy = [ "multi-user.target" ];
416 after = [ "network.target" "munged.service" "mysql.service" ];
417 requires = [ "munged.service" "mysql.service" ];
420 install -m 600 -o ${cfg.user} -T ${slurmdbdConf} ${configPath}
421 ${optionalString (cfg.dbdserver.storagePassFile != null) ''
422 echo "StoragePass=$(cat ${cfg.dbdserver.storagePassFile})" \
428 export SLURM_CONF=${configPath}
429 exec ${cfg.package}/bin/slurmdbd -D
433 RuntimeDirectory = "slurmdbd";
435 PIDFile = "/run/slurmdbd.pid";
436 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";