fix(frontend): job control no longer returns HTTP 500 (bug-1490)
Two stacked defects in the apiserver job-control link, both of which kept hold/release/cancel from ever reaching the controller: 1. controllers/jobs.go: validateJobControl and foundJob asserted jobinfo.Data["array_idx"].(int64), but StoreToOrderMaps produces array_idx as int (models.JobInfo.ArrayIdx is declared int) -> panic -> Gin Recovery -> HTTP 500 before backend.ControlJob ran. Add normalizeJobInt64 / jobArrayIdx helpers and use them in both functions (job_status already had this fix via normalizeJobStatus; array_idx was missed). 2. backend/clib.go: backend.ControlJob set xce_jobctrl_t.action to the models.JOB_* constant (JOB_STOP=1 / JOB_RESUME=2 / JOB_KILL=3 / JOB_CHKPNT=8), but that field is the capnp JobControl union discriminant (JobControl_u_siginfo=0 / JobControl_u_ckptoption=1). The controller's job_ctrl() selected the wrong union branch (or none, since encode_JobControl drops the union pointer for non-0/1 discriminants) and rejected every control with -EINVAL. Add jobCtrlDiscriminant() and use it. Also: resolveExecUser was defined in the cgo-only convert.go but is exercised by a non-cgo test, so `make test` (CGO_ENABLED=0) failed to build the backend package. Move it to convert_pure.go so it compiles in both modes. Tests: 3 controller regression tests (validateJobControl allowed / not-allowed branches, foundJob array-child branch) + 1 backend jobCtrlDiscriminant test. make test fully green. Cluster E2E verified: hold -> PSUSP, release -> PEND, cancel -> EXIT on a PEND job, no 500, no -EINVAL, all daemons healthy. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d3a92f1033
commit
c90e63ec0f
7 changed files with 368 additions and 29 deletions
|
|
@ -7,6 +7,36 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
// resolveExecUser returns the user a job should run as: an explicit exec_user
|
||||
// wins; otherwise the job runs as the submitting user. bug-1500: the submit
|
||||
// conversion previously dropped this entirely, so the worker received a NULL
|
||||
// execuser and ran every job as "nobody". Plain Go so it is unit-testable
|
||||
// without cgo — keep it OUT of the cgo-only convert.go.
|
||||
func resolveExecUser(job *models.JobInfo) string {
|
||||
execUser := job.ExecUser
|
||||
if execUser == "" {
|
||||
execUser = job.SubmitUser
|
||||
}
|
||||
return execUser
|
||||
}
|
||||
|
||||
// jobCtrlDiscriminant maps a models.JOB_* action to the capnp JobControl union
|
||||
// discriminant carried in xce_jobctrl_t.action: JobControl_u_siginfo (0) for
|
||||
// signal-based actions (kill/stop/resume), JobControl_u_ckptoption (1) for
|
||||
// checkpoint. The models.JOB_* constants are a DIFFERENT enum — using them as
|
||||
// the discriminant made the controller's job_ctrl() select the wrong union
|
||||
// branch (or none) and reject every control request with -EINVAL (bug-1490).
|
||||
// Returns -1 for an unknown action (clib.go never calls ControlJob with one).
|
||||
func jobCtrlDiscriminant(action int) int {
|
||||
switch action {
|
||||
case models.JOB_STOP, models.JOB_RESUME, models.JOB_KILL:
|
||||
return 0 // JobControl_u_siginfo
|
||||
case models.JOB_CHKPNT:
|
||||
return 1 // JobControl_u_ckptoption
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// JobID bit layout constants — mirrors src/include/config.h.
|
||||
//
|
||||
// |63 62|61 56|55 52|51 20|19 15|14 0|
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue