Skip to content

slurm: job-scoped epilog cleanup, default on, with a user escape hatch (#1407) - #1433

Open
dholt wants to merge 6 commits into
masterfrom
dholt/epilog-1407-job-scoped-r2
Open

dholt wants to merge 6 commits into
masterfrom
dholt/epilog-1407-job-scoped-r2

Conversation

@dholt

@dholt dholt commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Fixes the cleanup half of #1407 (does not claim the whole issue is fixed; see "Limits").

What changes

The Slurm epilog cleanup scripts now work per job. When one job of a user ends, the processes, /tmp files and enroot containers of that user's other running jobs are no longer removed. Leftovers are still removed after the user's last job ends. Processes are classified through /proc/<pid>/cgroup (cgroup v1 and v2): ending job = kill, other job = never, unassigned = only when it is the user's last job. Anything unreadable defers the cleanup (logged) and the epilog never fails.

  • New variable slurm_epilog_cleanup_scope, default job. user restores the 26.09 scripts and is deprecated, to be removed in 27.01.
  • job_container/tmpfs is documented, not rebuilt; script 42 skips when it is configured.
  • Separate commit: the SSH-access cleanup (script 41) matched names as patterns (user al also removed alice, . matched any character). It now matches whole lines. Applies in both scopes.
  • User doc: docs/slurm-cluster/epilog-job-scoped-cleanup.md.

scope=user is byte-identical to 26.09

Rendered with the real Ansible template module for both trees; diff -r is empty for epilog.sh, run-parts.sh, 40, 42, 50 (script 41 is the intended exception, separate commit):

f015dc774c074402037e402c3bf23bd2f4d4604dd0b075f7955c78134a45a5c3  40-lastuserjob-processes
bbc76a772ace94176ce350b076572602968e6441766b90f8a3eeee8d7c39b561  42-lastuserjob-cleanup
8ed80d32f33dc89f0ae8fc9afe063730bc487c67ec622f8d21232f2e0abd0213  50-lastuserjob-all-enroot-dirs
35d8de2bf2fadf2b19b999f537788967abb971d993d683f889cc547cf72bc171  epilog.sh
95fc80703598361a557345e51b3be7438f3147b6a224c0850078fca04781ee15  run-parts.sh

The suite pins this with snapshots under tests/slurm-epilog/snapshots/user-scope/.

Testing

  • tests/slurm-epilog/run-tests.sh: 68 passed, 0 failed (was 20). Deliberate breakages of the templates turn it red.
  • Live runs on real Slurm 26.05, baseline then this branch on the same machine: cgroup v2 and cgroup v1 scenarios all matched the expected tables (cleanup of the ending job, other jobs spared, last-job cleanup, SSH entry handling).
  • Independent code review (different model family): approve, one docs finding fixed in the last commit.

Limits

  • Requires proctrack/cgroup (the DeepOps default). With another tracker every process counts as unassigned and the cleanup falls back to squeue.
  • Processes started outside Slurm (for example over SSH) during job end are not protected.
  • The overlap race itself could not be reproduced through the scheduler on Slurm 26.05, so this change is not shown to fix it end to end.

dholt added 6 commits October 20, 2026 07:16
41-lastuserjob-ssh used 'grep -w' for the localusers.backup exemption and an
unanchored 'sed "/${SLURM_JOB_USER}/d"' on /etc/localusers. Both match
substrings and regular expressions: a job user 'al' removed the SSH allow entry
of 'alice' and 'halley', a dot matched any character, and 'je' was treated as
exempt when 'je.kim' was listed. Match the exact line, literally, in both
places (the same -x -F form scripts 40 and 42 already use).

Adds six cases to tests/slurm-epilog/run-tests.sh.

Signed-off-by: Doug Holt <dholt@nvidia.com>
…e hatch (#1407)

The *-lastuserjob-* epilog scripts decided what to remove from squeue alone and
killed every process the user owned, so a job of the same user placed on the node
just after squeue answered (CompleteWait=0), or one the controller was slow to
report, could lose its processes.

New role variable slurm_epilog_cleanup_scope, rendered at deploy time:

  job   (default) The dispatcher also scans /proc/<pid>/cgroup for the user's
        processes in any job_<id> cgroup other than the ending job's (cgroup v1
        and v2 layouts) and skips the last-user-job scripts when it finds one.
        40-lastuserjob-processes replaces killall -9 -u with a PID list classified
        by cgroup: the ending job's processes are killed, another job's never,
        orphans only when the user has no other job. 42 skips when
        job_container/tmpfs is configured. Anything that cannot be read or
        recognised is treated as 'another job may be here': the cleanup is
        deferred, never guessed, and the epilog never fails.
  user  DEPRECATED, removed in 27.01. Renders the 26.09 scripts byte-for-byte.

The playbook validates the value and warns when it is user.

Signed-off-by: Doug Holt <dholt@nvidia.com>
…hot (#1407)

Extends tests/slurm-epilog/run-tests.sh with a fake /proc and a recording kill so
the job-scoped paths run unprivileged: dispatcher guard (cgroup v1 and v2, other
user, orphan, unrecognised, empty, missing library, no uid), script 40 per-PID
classification, 42 job_container/tmpfs skip, 50 behind the guard, and a snapshot
check that scope=user renders the 26.09 scripts byte-for-byte. render.py takes
the scope and matches Ansible's trim_blocks.

Signed-off-by: Doug Holt <dholt@nvidia.com>
…_container/tmpfs (#1407)

Signed-off-by: Doug Holt <dholt@nvidia.com>
Signed-off-by: Doug Holt <dholt@nvidia.com>
@dholt
dholt requested a review from michael-balint October 22, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant