feat(spur-cli): support slurm-buildkite bridge compatibility#443
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #443 +/- ##
==========================================
+ Coverage 70.85% 70.92% +0.07%
==========================================
Files 140 140
Lines 41849 42026 +177
==========================================
+ Hits 29650 29804 +154
- Misses 12199 12222 +23 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds missing Slurm CLI compatibility features in spur-cli (and the underlying proto/controller/agent plumbing) to support Slurm CI bridges like CliMA/slurm-buildkite, including sbatch output/argument handling and squeue formatting/field support.
Changes:
- Extended the public proto + core job spec to carry
script_args(positional script parameters) andcomment(readback viasqueue/scontrol show). - Updated the agent to inject
set -- <args>into batch scripts so positional parameters ($1,$@) work as expected. - Refactored the CLI format engine to preserve literal characters (e.g. commas) and added new
squeuebehaviors (--name,%k,%A,%%).
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| proto/slurm.proto | Adds script_args to JobSpec and comment to JobInfo. |
| crates/spurd/src/agent_server.rs | Injects set -- ... into scripts to pass positional args safely. |
| crates/spurctld/src/server.rs | Maps script_args and comment between proto and core job types. |
| crates/spurctld/src/scheduler_loop.rs | Propagates script_args through controller-to-agent dispatch. |
| crates/spurctld/src/accounting/grpc.rs | Initializes new comment field for accounting responses. |
| crates/spur-k8s/src/job_controller.rs | Includes script_args in k8s job spec proto conversion. |
| crates/spur-core/src/job.rs | Persists script_args in core JobSpec with backward-compatible defaults. |
| crates/spur-cli/src/squeue.rs | Adds --name filtering and resolves new output fields (%k, %A). |
| crates/spur-cli/src/sinfo.rs | Updates to new format token API. |
| crates/spur-cli/src/scontrol.rs | Surfaces Comment= in scontrol show output. |
| crates/spur-cli/src/sbatch.rs | Adds --parsable output and captures trailing script args. |
| crates/spur-cli/src/sacct.rs | Adjusts tests for the new tokenized format engine output. |
| crates/spur-cli/src/format_engine.rs | Preserves literals between specifiers and adds %% escaping. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
0b0f551 to
75c7f5c
Compare
yansun1996
left a comment
There was a problem hiding this comment.
Summary
This is a well-scoped, well-tested PR — the format-engine literal-preservation redesign in particular is nicely done. A couple of minor things worth a look before merging.
What's good
format_engine.rs'sFormatField→FormatTokenrefactor is the right way to solve "buildkite needs%k,%Ato emitcomment,42with a literal comma, not a space-joinedcomment , 42" — preserving literal runs between specifiers rather than always space-joining fields. Genuinely nice:test_default_format_spacing_unchangedexplicitly proves the existing default squeue/sinfo format output is byte-identical to before, which is exactly the backward-compat check I'd have asked for.script_args/set --injection (agent_server.rs) usesshlex::try_jointo shell-escape each argument before injectingset -- <args>after the shebang — correctly prevents a malicious/malformed script argument from escaping into shell metacharacter territory. Good edge-case test coverage (shebang, no shebang,#!/usr/bin/env bash, CRLF shebang).candidate_script_path's rewrite to a real clap pre-parse (instead of the old "assume the last positional arg" heuristic) is more robust, and — importantly —script_argsis declaredtrailing_var_arg + allow_hyphen_values, which correctly avoids the exact class of bug found and fixed elsewhere in this repo recently (a flag like-Vbeing misinterpreted as sbatch's own flag instead of being passed through to the wrapped script/command). Confirmed this is handled correctly here.- The
scheduler_loop.rs/server.rs/accounting/grpc.rs/spur-k8s/job_controller.rstouches are all legitimate, mechanical propagation of the two new fields (script_args,comment) through everyJobSpec/JobInfoconversion site — not scope creep. proto/slurm.protochanges are clean appends (script_args = 81,comment = 53), no renumbering,package slurm;untouched.
Two things worth a look
-
%A(newARRAY_JOB_IDformat spec) resolves tojob.job_id, notjob.array_job_id. (squeue.rs:'A' => job.job_id.to_string().) For a non-array job these are the same, but for an individual task within a job array, real Slurm's%Ameans "the array's master job ID" — which should bejob.array_job_id(already available onJobInfo, used a few lines away for thearray_job_id/array_task_idproto fields), not the task's own ID. Worth a quick fix:if job.array_job_id != 0 { job.array_job_id } else { job.job_id }(or whatever this codebase's existing convention is for "0 means not an array job"). -
squeue --name/-nfilters client-side, unlike its sibling filters.--account/-Ais passed through as a field onGetJobsRequest(server-side filter), butGetJobsRequesthas nonamefield, so--nameended up implemented as a post-fetch.retain()-style loop in the CLI. Functionally correct, but inconsistent with the existing pattern, and meanssqueue -n fooon a cluster with many jobs fetches and discards everything server-side would otherwise have filtered. Given this PR already touchesproto/slurm.protofor two other fields, addingstring name = 6;toGetJobsRequestand filtering server-side (matchingaccount/partition/user) would be a small, consistent addition — or if there's a reason to keep it client-side for now, worth a one-line note on why.
Neither of these is a blocker — happy to see this land with a fast-follow, or fixed inline if it's a quick change. Nice work on the format-engine piece especially.
(Reviewed by direct code inspection rather than a full build/test run, given the PR's modest size and the focused nature of the changes — happy to do a build-level pass too if useful.)
…sable, script args, format literals, squeue --name) Add five Slurm-compatibility features so CliMA/slurm-buildkite runs unmodified on Spur (ROCm#434): - `sbatch --parsable`: print bare job ID on success - `sbatch script.sh <args>`: forward positional args to the script via `set --` injection in build_job_script, with a new `script_args` proto field (distinct from the overloaded `argv`) - `squeue --format` literal preservation: refactor format engine to a FormatToken enum (Field | Literal) with empty-string join, so `--format=%k,%A` emits `comment,jobid` with the comma intact; also handle `%%` as literal `%` - `squeue %k` (comment) and `%A` (array/job ID) specifiers, plus `Comment=` in `scontrol show job`; wired via new `JobInfo.comment` proto field populated from the existing `JobSpec.comment` - `squeue --name` / `-n`: client-side job name filter supporting comma-separated names The three bridge commands now work end-to-end: sbatch --parsable --comment=<url> --job-name=buildkite script.sh <uuid> squeue --name=buildkite --noheader --format=%k,%A scancel --name=buildkite (already worked) Also fixes candidate_script_path to use a clap pre-parse instead of argv.last(), which broke #SBATCH directive reading when trailing script args were present.
75c7f5c to
29b4061
Compare
|
Thanks for the thorough review, Yan. On your two points: [1] [2] |
yansun1996
left a comment
There was a problem hiding this comment.
Both findings from my earlier review are resolved — the --name filter is now server-side (matches the sibling user/partition/account filters), and my %A concern was a false positive on my part (verified: real Slurm's %A is the per-element job ID, not the array parent — that's %F — thanks for catching that with the man page + live-cluster verification). LGTM.
Summary
Adds the missing Slurm CLI features required by CliMA/slurm-buildkite and similar CI bridges that script against Slurm's CLI surface.
sbatch --parsable: prints bare job ID on stdout (no header/decoration)sbatchpositional script args: trailing arguments after the script path are forwarded as$1,$2, etc. viaset --injection--commentreadback: newcommentfield onJobInfoproto, surfaced insqueue %kandscontrol showsqueue --formatliterals: refactored format engine to preserve literal characters between specifiers (%k,%Aemitscomment,42with no extra spacing), added%%escape supportsqueue %A: resolves to per-element job ID (matches Slurm semantics)squeue --name: client-side filter by job nameApproach
script_args(field 81) onJobSpec,comment(field 53) onJobInfo. Both default to empty, backward-compatible with existing Raft state via#[serde(default)].FormatTokenenum (Field | Literal) replacing the oldVec<FormatField>+join(" ")pattern. All callers (squeue,sinfo,sacct) updated. Named-format path (sacct) emits literal space separators between fields.build_job_scriptinjectsset -- <args>after the shebang line (or at top if no shebang) when script args are present. Handles CRLF shebangs and shell-escapes args viashlex.Test plan
build_job_script/inject_script_argstests (shebang, no-shebang, CRLF, quoting)cargo testandcargo clippycleansbatch --parsable,--commentreadback viasqueue %k,%A,scontrol show,squeue --name, positional script argsCloses #434