Commit graph

33 commits

Author SHA1 Message Date
954c96cf5b
feat(xcecli): jobs kill --signal and --force
The control API already takes `signal` (kill only: that signal once,
instead of the graceful INT, TERM, KILL sequence) and `force_kill`
(SIGKILL at once); xcecli could not send either. `jobs kill` now has
-s/--signal <name|number> (names in any case, SIG prefix optional, sent
upper case without it) and --force, in both the job-ID and the filter
request; using both at once, or an empty signal, is refused before any
request. stop and resume get neither (the server rejects a signal there).
Kill help and docs/xce.md "Killing and stopping jobs" document the flags.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 10:25:23 +00:00
0379823098
fix(xcecli): call the logout API so the token is revoked (bug-1959)
xcecli logout only removed the token from the local config, so the token
stayed valid on the server until it expired. It now first sends
POST /xce/v1/auth/logout with the bearer token (APIClient.Logout), which
revokes it server side since bug-1946. Best effort: if the server is
unreachable or rejects the token, the local login info is still cleared
and a warning says the revocation could not be confirmed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 10:25:23 +00:00
d84a793578
docs: document graceful job kill/stop and job.terminate_interval (bug-1957)
- src/docs/xce.md: explicit signal and force kill are REST-only (signal,
  force_kill); xcecli has no signal option yet.
- src/docs/deployment.md: app.yaml row lists the job block
  (max_array_size, terminate_interval) and trusted proxies.
- xcecli jobs kill/stop/resume help describes the signal sequences.
- REST: control endpoint annotations and the signal/force_kill model fields
  describe the behaviour (swagger output not regenerated: swag fails on an
  unrelated annotation).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 10:07:42 +00:00
1cedd7f791
fix(controller,apiserver,xcecli): expose job CPU peak and efficiency to the apiserver and xcecli (bug-1736)
The controller computed run usage (CPU time, memory, CPU peak and
efficiency, LSF bjobs -l definitions) but the capnp Job struct had no
field for it, so the job pushed to the apiserver never carried it, and
snapshots (the same struct) dropped it: a job restored from a checkpoint
lost its accumulated usage.

- controller.capnp: Job.runUsage @13 (JobRunusage); old entries decode
  with no run usage.
- apiserver: map run_usage into JobInfo; max_mem, avg_mem, used_mem,
  cpu_time, peak_cpu, peak_cpu_time, peak_cpu_duration, mem_efficiency,
  avg_cpu_efficiency, peak_cpu_efficiency become queryable columns.
- xcecli: -o fields MAX_MEM, AVG_MEM, MEM_EFFICIENCY, CPU_PEAK,
  CPU_PEAK_DURATION, CPU_EFFICIENCY, CPU_PEAK_EFFICIENCY (CPU_TIME now
  renders too), and a MEMORY USAGE / CPU USAGE block in jobs list -l.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-06 13:54:43 +00:00
c15580a7f3
fix(frontend): peek and restart take <array-id>[k] and written job IDs
- apiserver peek (parseJobIDParam): <array-id>[k] now resolves to the
  element; it used to drop [k] and look up the array identity itself
  (and panicked in parseArrayName on some inputs). A job number still
  names that job exactly (an element by its own XCE_JOBID); ranges and
  invalid selections are rejected.
- apiserver restart: the decimal-only pre-check (isValidJobId, now
  unused and removed) rejected the written form c-a-ts-seq[k];
  ParseIdentitySelection, already used for the lookup, validates it.
- xcecli jobs restart converts its argument with ToAPIJobID like the
  control commands, so written IDs work and invalid ones fail locally.
- docs: the peek/restart caveat in the Job arrays section.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:42:27 +00:00
3615c7c0fb
style(frontend): gofmt the apiserver and xcecli sources
Formatting only (gofmt -w on the 29 non-vendored, non-generated files
gofmt -l reported); swag-generated apiserver/docs/docs.go left as is.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:33:16 +00:00
6e631caa22
fix: scheduler empty-resreq JOB_UPDATE crash (bug-1904); xcecli jobs list rejection text (bug-1906)
bug-1904: both scheduler JOB_UPDATE paths parsed "" as-is:
parse_resreq() returns success with a PRIMARY container whose body is
NULL, and apply_job_task_count() wrote through it. Use ingest's default
("type == any") instead.

bug-1906: xcecli jobs list sent local selection-parse errors through
ExtractErrorMessage, which strips brackets and the quoted selection;
report them as written.

Also logs bug-1905 (xcecd_virtual ignores kill of a running job). All
three found by job-array-one-based-index task 10.2's live REST flow.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 14:48:50 +00:00
d3b12159a4
feat(job-array-one-based-index): xcecli submit shows the array (task 8.3)
Submitting an array prints the server's message with the array ID in
written form (no [k]) and the element count, e.g.
'Job <0-0-...> is submitted to queue <normal> (3 elements).'; ordinary
submits print exactly as before. The client model mirrors array_size.
Submit help documents name[1-N] and name[1], numbering from 1 and the
API-server limit (default 1000, at most 32767).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 12:58:36 +00:00
58ca7abb36
feat(job-array-one-based-index): xcecli list and control use the selection parser (task 8.2)
ID lists split only at commas outside brackets and every selection is
validated before any request (control allows identity ranges, listing
refuses them). A raw -J value with brackets is checked before the
wildcard mapping, and the search rule and * stripping apply to the
name part only (-J 'foo*[1]' lists element 1 of arrays whose name
starts with foo); values without brackets map exactly as before.
Control results print each item's own job ID when the server sends it,
so a pre-upgrade element 0 shows as <array-id>[0]. Control and list
help show <array-id>[k] and <array-id>[a-b]; list help now says -J.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 12:53:50 +00:00
bc616e8c4a
feat(job-array-one-based-index): client identity and selection parser (task 8.1)
xcecli's format package gains ParseSelection (written or decimal key
with optional [k]/[a-b], the server's grammar and check order; 5.8 and
5.7 also on decimal keys with [...], so an upgraded client protects
itself against an older server; query ranges refused after the other
checks), the bracket-aware SplitSelections, the raw -J
ParseNameSelection and Selection.APIKey. ParseJobID is bounded;
ToAPIJobID(s, allowRange) no longer passes unrecognised text through;
peek keeps today's behaviour via ToAPIJobIDLegacy.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 12:47:39 +00:00
e395eaa3ad
fix(frontend): count host job-state columns and EXEC_HOST by real slots
NJOBS/RUN/SSUSP/USUSP (xcecli hosts list -l) and EXEC_HOST (xcecli jobs
list) always showed a hardcoded 1 slot per host regardless of a job's
actual per-host allocation -- rawJobToModel()'s ExecHosts JSONB builder
never read the real per-host "slots" resource from the C job allocation,
so the already-correct downstream slot-counting logic (computeHostSlotUsage,
bug-1743) and EXEC_HOST's "N*host" formatter never had real data to work
with. convert.go now extracts each host's real slots allocation via a new
CGO indexing helper, mirroring the scheduler's own get_nslots_in_alloc()
convention.

Also wires hosts list -l's "CURRENT LOAD USED FOR SCHEDULING" table (tmp/
swap/mem/slots and friends) to the host's real live resource values --
previously entirely hardcoded placeholder strings, never connected to any
backend data.
2026-09-07 07:32:00 +00:00
12c6a59c03
feat(eliminate-frontend-makefile): task 3.4 - update source code comments
Comment-only edits in 4 files: test_ha_bootstrap.c/test_ha_ctrlhello.c
rename their "make test-integration" pointers to reference the
regression suite (tests/regression/run.sh) directly; apiserver/xcecli
cmd/main.go drop the Makefile clause from their ldflags-injection
comments, keeping only src/tools/go_build. Zero production/test
logic changed -- verified via full controller unit-test suite rerun
(1261 tests, 0 failures) and xcecli build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYdtrEWWZfKRRGED7raEYg
2026-09-03 14:34:48 +00:00
68bc86bc59
build: make Go and Python builds fully offline (hermetic Nix build)
The Nix build previously fetched Go modules from goproxy.cn and Python
build deps from PyPI during the build phase, relying on network leaking
into the sandbox. This is non-reproducible and breaks whenever the
sandbox resolver is unreachable (e.g. pc13v's loopback dnsmasq).

Go:
- Vendor all three modules (frontend/apiserver, frontend/xcecli,
  autoscaler/providers/baidu/src/bcctool) and commit vendor/ trees.
- tools/go_build now builds with GOFLAGS=-mod=vendor and GOPROXY=off
  instead of GOPROXY=https://goproxy.cn.

Python (xceadmin):
- Add setuptools + wheel to xce.nix nativeBuildInputs.
- meson-build.sh installs with pip --no-build-isolation --no-index
  --no-deps so no PyPI access happens at build time.

xceadmin install script:
- Invoke meson-install.sh via find_program('bash') instead of relying
  on its #!/usr/bin/env bash shebang, which fails in the Nix install
  sandbox (no /usr/bin/env -> 'could not be run').

Cleanup:
- Drop now-unneeded cacert and impureEnvVars=[HOME] from xce.nix and
  xcecli.nix (they only existed to enable the impure network fetch).

Docs:
- README build guide: drop '--option sandbox false' from nix build /
  nix bundle commands, note the build is now hermetic, and document the
  go mod vendor + git add vendor/ maintenance workflow.

Verified: nix build .#xcecore, .#xcecore_debug, .#xcecli, and .#xce all
succeed with the sandbox enabled.
2026-09-03 12:38:49 +08:00
4fad788430
fix(xcecli): assert own hostname as FROM_HOST at submission time (bug-1676, gitea #44)
JobSubmitRequest gains a FromHost field, populated in BuildJobRequest()
via os.Hostname(). Matches how traditional batch schedulers report the
submitting host, and sidesteps having the server derive it from the
connection (which apiserver was doing via ctx.ClientIP() -- an IP not
a hostname, and spoofable via X-Forwarded-For since this apiserver
never configures gin's TrustedProxies).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
2026-08-24 15:14:28 +00:00
a58c2a19e6
fix(xcecli): friendly message for connection-refused instead of raw OS error (bug-1675, gitea #42)
ExtractErrorMessage()'s connection-refused branch returned the bare
OS error string verbatim. A CLI call right after apiserver startup
(before its listener is up) surfaced a raw "get the request failed:
[connection refused]" with no indication it's a transient startup
race, not a real failure.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
2026-08-24 14:23:25 +00:00
d65d18ad5f
feat(dirty-content-fingerprint): xcecli shows fingerprint in --version
Adds DirtyFingerprint var and composeVersionDisplay() helper to
xcecli/cmd/main.go, a logical duplicate of apiserver's just-approved
implementation (task 4.4, same anchored strings.TrimSuffix strip-and-
append rule). Applied at the sole consumption point: the version string
fed into router.Execute(cm, version), which sets Cobra's rootCmd.Version.
router.go is untouched -- xcecli has no startup log to protect, already
established out of scope by the original build-time-versioning feature.

New main_test.go covers the same 6 cases as apiserver's tests. Verified
independently by review (including a second, independent mutation test)
with real builds across all 3 required scenarios and a full xcecli module
test suite run showing no regressions.

This completes all Go binary work (tasks 4.1-4.5) for this spec.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 08:21:18 +00:00
502dd0230f
feat(dirty-content-fingerprint): apiserver/xcecli meson pass fingerprint to go_build
Both apiserver/meson.build and xcecli/meson.build add
XCE_DIRTY_FINGERPRINT=get_option('dirty_fingerprint'), unquoted,
identically positioned to the existing XCE_GIT_COMMIT/XCE_BUILD_TIME
entries.

Verified independently by review with a distinct test value: fresh
configure + real ninja builds of both binaries confirm the value reaches
go build's actual invocation (visible in go version -m's recorded -ldflags
build setting), matches the C-side -DVERSION_DIRTY_FINGERPRINT= from the
same configure, and degrades to empty identically to the two pre-existing
vars when omitted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 06:21:21 +00:00
fb09afe6be
feat(build-time-versioning): xcecli --version via Cobra rootCmd.Version
Adds GitCommit/BuildTime vars to xcecli's main.go. Cobra's rootCmd is
declared unexported in router.go (a different file than the task's
original main.go-only boundary), so main.go can't reach it directly --
resolved by extending router.go's sole exported entry point,
Execute(cm, version), to accept the composed version string and set
rootCmd.Version before rootCmd.Execute() runs. Cobra then auto-registers
--version/-v natively once rootCmd.Version is non-empty (confirmed via
reading Cobra v1.9.1 source directly) -- zero additional flag-parsing
code, as designed.

Live-verified via both build paths (meson xce-build.sh and make
build-cli): real commit id (matching git rev-parse --short HEAD plus
dirty suffix) and build time, exit 0.

xcecli's startup log deliberately not extended -- Requirement 3 scopes
that to the four daemons only; xcecli is a one-shot CLI. Corrects a
stale design.md line that had assumed otherwise.

Task 4.5/13 -- closes out the Go binary version display phase (tasks
4.1-4.5).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 14:07:38 +00:00
071f3895f7
feat(build-time-versioning): thread commit_id/build_time into go_build env
apiserver/meson.build and xcecli/meson.build now pass
XCE_GIT_COMMIT/XCE_BUILD_TIME (from the project's commit_id/build_time
meson options) into go_build's environment, mirroring the existing
CURRENT_SOURCE_DIR/BUILD_ROOT env-passing mechanism. Deliberately
unquoted: go_build's fix_input_envs() only quote-strips
CURRENT_SOURCE_DIR/BUILD_ROOT, not these two -- quoting them would embed
literal quote characters and corrupt the -ldflags argument.

Live-verified: real values (matching git rev-parse --short HEAD plus
dirty suffix, and a real UTC timestamp) reach go build's actual
invocation and are embedded in both binaries' Go build-info metadata.

No main.GitCommit/main.BuildTime symbols exist in either binary yet
(confirmed via go tool nm) since apiserver/xcecli's main packages don't
declare those vars until tasks 4.4/4.5 -- expected, this task's scope is
the env-var plumbing only.

Task 4.2/13 of build-time-versioning.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 12:50:36 +00:00
4ec401672b fix(xcecli): restore dangling CA-cert cleanup misses, enable https support
bug-1463: commit 94f50ce6 (bug-1453 CA-cert-plumbing removal) missed
GetJobOutput's dead tls.Config/loadRootCAs block in request.go, plus
peek.go's SetRootCAs call and serverInfo.CACert field access (the
field no longer exists on APIServerInfo) -- broke the xcecli build.

Removed all three dangling references. Also enabled NewAPIClient's
previously-commented-out InsecureSkipVerify TLS config, since no
xcecli method set any TLS config at all -- any https:// apiserver URL
would have failed cert verification, not just GetJobOutput. Matches
bug-1453's documented design (server-side TLS only, no peer
verification, mTLS deferred as P3 hardening).

Documented both the api-server (http+https) and controller
(server-side-cert-only, no client certs) TLS postures in
.kiro/steering/security.md, replacing a stale line claiming TLS is
handled at the network layer, plus a follow-up note for the planned
HAProxy TLS-termination reverse proxy once its cert type and
apiserver's own listener fate are decided.
2026-07-23 07:28:01 +00:00
ff1be48001 merge 2026-07-23 12:35:10 +08:00
Lei Chen
3a2094a461 Merge branch 'working' into job_peek_lchen
job_peek_lchen: Add fetchfile feature (job output/error peek proxy)
working: HA/Raft infrastructure (consensus, replication, config mgmt)

Conflict resolution summary:
- controller.capnp: fetchfile @41, fetchfilereply @18, fetchfilemsg @30
- cluster.c: bifurcated OPCode_reply for fetchfile + config-push ACK
- job.c: kept full fetchfile pending-request subsystem (~183 lines)
- request.c: kept both xce_fetchfile_req() and XCE_RETRY_DEFAULTS
- helper.c: added missing preVoteRequest/preVoteReply mappings
- All 15 new test registrations (test_cbuf.c + 14 HA tests)
2026-07-22 13:57:25 +08:00
94f50ce6e1 fix(scheduler,cli): bug-1453/1454/1455/1456 remove dead CA-cert plumbing, fix scheduler HA config bugs
bug-1453: remove unused client-side CA-certificate plumbing. C-side:
drop ca_cert_path from xce_cluster_config_t, do_connect()'s ca_cert
param, --ca-cert flags on worker/scheduler, and controller's cert
population (TLS is server-side only, SSL_VERIFY_NONE everywhere on
the client side already, verified zero SSL_CTX_load_verify_locations
calls in the C tree). Go-side: delete xcecli's self-signed cert
TOFU-pinning flow (cmd/auth/cert/*), CACert field, SetRootCAs/
loadRootCAs, and every call site.

bug-1454: fix xcecli_ctx_t leak in scheduler.c sched_init() — the
unconditional initial ctx_init was never freed before the HA
candidate loop re-initialized it on the first iteration.

bug-1455: sched_init()'s memset(sched, 0, ...) was silently wiping
sched->cluster_cfg that main.c had populated from --peers just before
calling sched_init(), so --peers was always ignored and the scheduler
fell back to the hardcoded localhost:9990 single-host default.
Restructured sched_init() to take cluster_cfg as an explicit parameter
(assigned after the memset) instead of relying on caller-side
ordering with a separate sched_set_cluster_cfg() setter, which is now
removed.

bug-1456: revert an unsafe stack-local xce_client_config_t introduced
while fixing bug-1455 — xcecli_ctx_init() stores that pointer as
ctx->conf and client_failover.c dereferences it for the ctx's entire
life (runtime reconnect), so a per-loop-iteration stack copy would
dangle the moment sched_init() returned. Back to mutating the
caller-owned, process-lifetime config in place.

Verified: full ASAN build (all components), meson test suite 9/9 OK,
manual scheduler testsuite 15/15, Go build/vet/test all pass.
2026-07-20 12:01:10 +00:00
86fe35e671 add kiro skills 2026-05-21 03:41:57 +00:00
a07a74a943 Merge branch 'persistent_ha' into scheduler 2026-05-12 10:52:46 +00:00
475ed20bba use fmt_jobid() when job submission 2026-05-12 10:52:28 +00:00
Lei Chen
d2b47e3985 Init commit of jobs output/error message peek project. 2026-05-09 16:57:54 +08:00
ce2edf0dac refactor: represent time fields as int64 Unix seconds throughout the stack
Collapses a four-step conversion chain (time_t → int64 → time.Time →
RFC3339 string → string → time.Time) to a direct int64 pass-through:

  C time_t → rawJobData int64 → JobInfo int64 → JSON integer → QueryJob int64 → time.Unix() for display

Changes:
- apiserver/models/jobs.go: SubmitTime, QueueTime, StartTime, EndTime,
  ReserveTime in JobInfo and JobAdditionalFields: time.Time → int64
- apiserver/models/common.go: ActionControl.SubmitTime: time.Time → int64
- backend/convert_pure.go: remove time.Unix() calls; assign int64 directly
- backend/convert_test.go: update time assertions to compare int64 values
- xcecli/models/jobs.go: SubmitTime, StartTime, EndTime, ReserveTime in
  QueryJob: string/time.Time → int64; remove time import
- xcecli/common/output/time.go: replace parseJobTime(string) with
  unixToTime(int64) and fmtUnixTime(int64) helpers
- xcecli/common/output/page_print_jobs.go: replace parseJobTime() calls
  with unixToTime()/fmtUnixTime(); remove !startTime.IsZero() guard
  (unixToTime returns false for ts<=0, making it redundant)
- xcecli/common/output/page_print_array_elements_jobs.go: replace
  string-split+time.Parse submit-time block with fmtUnixTime(); remove
  unused time import

Side effect: eliminates the "0001-01-01T00:00:00Z" zero-time
serialization issue at the source — zero timestamps are now 0 (integer)
and unixToTime/fmtUnixTime return false/"-" for ts<=0 without special-
casing needed in callers.
2026-05-09 07:00:49 +00:00
a2476d0176 fix: xcecli jobs list -l — hide spurious start line and show pending reason
Three fixes:

1. ExecHosts.UnmarshalJSON: JSON null (sent when no allocation exists)
   was treated as a non-"-" string because json.Unmarshal(null, &str)
   returns nil with str="". This created a phantom HostSlot{NumSlots:1,
   HostName:""} producing "<1*>" for every PEND job. Now null and ""
   are both treated as empty hosts.

2. page_print_jobs.go: added !startTime.IsZero() guard so a zero
   timestamp ("0001-01-01T00:00:00Z") never produces a start line
   even if the status check is bypassed.

3. Added PENDING_REASON field to JobFieldsMap so it is requested from
   the API when -l is passed, and rendered in printJobsVerboseOutput
   for PEND/PSUSP jobs before the start-time section.
2026-05-09 05:15:31 +00:00
af578c29ca fix show exec host for pend jobs 2026-05-09 04:09:16 +00:00
d6008ead99 improve frontend jobid display 2026-05-07 02:36:24 +00:00
960ef62342 fix job array display issue 2026-04-14 18:23:49 +08:00
c9dc8c4676 Merge Go frontend (apiserver + xcecli) into meson build 2026-04-14 11:23:18 +08:00