A-batch admin-plane fixes: rusage unit name, XCE_JOBID identity, select WARN, CLI env, docs

rusage collection (merge cb0c7fe9 regression, root cause of 0 counters):
- collect_job_rusages builds the systemd unit name with
  make_job_sd_unit_name (four-segment fmt_jobid_ex form) instead of a bare
  %lu of the packed uint64, so the D-Bus property lookups hit the real
  per-job unit again. E2E on t1: DONE job reports max_mem/avg_mem/cpu_time
  non-zero (previously all 0).

XCE_JOBID written identity:
- exdata sets XCE_JOBID via fmt_jobid (four-segment
  cluster-apiserver-timestamp-seq) instead of a bare packed decimal;
  XCE_JOBINDEX handling unchanged.
- xrun parses XCE_JOBID with parse_jobid (accepts the four-segment form);
  a bare decimal no longer round-trips through the written identity.
- E2E on t1: job sees XCE_JOBID=<submit id>; xrun remote-start round-trip
  to another host matches the job.

select WARN (silent degradation):
- parse_resreq_primary WARNs when a select references an unregistered
  resource ("...references an unregistered resource -- dropping the select
  and skipping any rusage[] clause of this primary") instead of failing
  silently; scheduler log shows the WARN on t1 and the job schedules
  without the constraint.

CLI env handling (unit-tested; subEnvVars is not flag-bound so this is
not reachable from the production CLI):
- getEnvironmentVariables keeps B=b=c (split at first '=') and warns +
  drops a bare key or an '=value' fragment instead of silently mis-parsing.

Docs:
- src/docs/xce.md: document the dead-clause semantics (select/rusage
  primary drop behavior) matching the WARN.

bug-1972 (test-only UAF): test_job_live_gc asserted job destruction by
reading refcount from the freed job; rewrite the assertion to observe
destruction without touching freed memory. controller_unit_test is green
again (1354 tests).

Regenerate 3 repl_trace_baseline fixtures whose baselines shifted with the
select-WARN logging; replay tests green.

Spec naming: external-license-resources design.md/brief.md fix the
self-referential daemon-name note (old drafts said xceextresd/extresd).

Verified on t1: rusage_burn job (counters non-zero in DONE), echo_env job
(four-segment XCE_JOBID), select[nosuchres] job (WARN + schedules),
xrun t2 remote-start round-trip, CLI env unit tests, xcelib 762 /
controller 1354 / worker exdata 8+11 / sched repl_trace 4+14+4+10+17
tests green.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
lei.chen 2026-10-26 14:02:53 +00:00
parent 68eabd8a4a
commit f780a1660a
17 changed files with 329 additions and 44 deletions

View file

@ -1,8 +1,10 @@
package jobs
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
@ -133,6 +135,48 @@ func TestSubmitHelpShowsArrayForms(t *testing.T) {
}
}
// getEnvironmentVariables must keep entries whose value contains '=' (the
// apiserver splits at the FIRST '=', so A=b=c is A -> "b=c") -- dropping
// them used to be silent data loss. A nameless or '='-less entry cannot
// become a map key, so it is warned about and dropped.
func TestGetEnvironmentVariables_KeepsMultiEqualSign(t *testing.T) {
js := NewJobSubmitter(nil)
js.subEnvVars = []string{"A=1", "B=b=c", "C=", "=novalue", "novalue"}
r, w, pipeErr := os.Pipe()
if pipeErr != nil {
t.Fatalf("pipe: %v", pipeErr)
}
old := os.Stdout
os.Stdout = w
done := make(chan string)
go func() {
var buf bytes.Buffer
_, _ = io.Copy(&buf, r)
done <- buf.String()
}()
got := js.getEnvironmentVariables()
os.Stdout = old
_ = w.Close()
warn := <-done
want := []string{"A=1", "B=b=c", "C="}
if len(got) != len(want) {
t.Fatalf("env = %q, want %q", got, want)
}
for i := range want {
if got[i] != want[i] {
t.Errorf("env[%d] = %q, want %q", i, got[i], want[i])
}
}
if !strings.Contains(warn, "=novalue") || !strings.Contains(warn, "warning:") {
t.Errorf("warning output = %q, want it to name the nameless entry", warn)
}
if !strings.Contains(warn, "novalue") {
t.Errorf("warning output = %q, want it to name the '='-less entry", warn)
}
}
// Attach marks the terminal-attach kind of TTY job so the worker may reap
// ttyd when no client ever connects; --browse keeps the web-viewed
// semantics and must not set it.