feat: P0-1e expand handleConfigPush with host config and cluster dispatch
Wires the remaining cluster_config_t data into the notification pipeline: - dispatchConfigPush() extracted as a pure-Go helper (CGO-free, testable) that drives OnQueueUpdated, OnResourceUpdated, OnHostConfigUpdated, and OnClusterUpdated from a single config push event - handleConfigPush() delegates to dispatchConfigPush via the new helper, eliminating the previous inline loops - OnHostConfigUpdated and OnClusterUpdated added to NotificationHandler interface and implemented with partial-merge semantics in DefaultHandler - rawHostConfigData/rawHostConfigToModel and rawClusterData/rawClusterToModel added to convert_pure.go with their CGO extraction counterparts in convert.go Safety fixes from code review: - OnHostUpdated, OnHostConfigUpdated, OnClusterUpdated now copy *incoming to a local merged value before mutation, closing the TOCTOU window between store.Get and store.Put under concurrent pushes - cClusterConfQueues and cClusterConfResources gain nil-pointer guards matching the existing guard in cClusterConfHostConfigs - handleConfigPush gains an explicit gHandler nil check - cClusterConfToClusterInfo returns nil on empty clustername (prevents phantom empty-key write to store.Clusters); handleConfigPush logs a warning when nil - 36 unit tests passing (CGO_ENABLED=0)
This commit is contained in:
parent
00c4472d6c
commit
893812e7aa
8 changed files with 850 additions and 11 deletions
117
src/docs/apiserver-backend-tasks.md
Normal file
117
src/docs/apiserver-backend-tasks.md
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# API Server Backend Enhancement — Task Tracker
|
||||
|
||||
## Status Legend
|
||||
- [x] Completed
|
||||
- [ ] Pending
|
||||
- [>] In Progress (blocked)
|
||||
|
||||
---
|
||||
|
||||
## P0-1: Handle Cluster Config Push
|
||||
|
||||
- [x] **#1 P0-1a: Add HostConfig + Cluster fields to models**
|
||||
- `models/clusters.go` — Added `HeartbeatInterval`, `Vcpus`, `InactiveHeartbeatCount` to `ClusterInfo`
|
||||
- `models/hosts.go` — Changed `HostStateStr(0)` from `"OK"` to `"UNKNOWN"`
|
||||
- `models/clusters_test.go` — New: verifies new fields serialize + existing fields unchanged
|
||||
- `models/hosts_test.go` — New: verifies `HostStateStr` for zero, flags, non-flag, combined
|
||||
- All 15 tests passing
|
||||
|
||||
- [x] **#2 P0-1b: Add pure Go conversion functions + TDD tests**
|
||||
- `backend/convert_pure.go` — Added `rawHostConfigData` + `rawHostConfigToModel()`, `rawClusterData` + `rawClusterToModel()`
|
||||
- `backend/convert_test.go` — 8 new table-driven tests: zero-value ints, empty strings, normal values, worker/config-sourced field isolation
|
||||
- `TODO(dispatchwindow)` comment added per plan spec
|
||||
- `DisptWindow` guard test added to catch accidental future CGO layer changes
|
||||
- All 26 backend tests passing
|
||||
|
||||
- [x] **#3 P0-1c: Add CGO conversion layer in convert.go**
|
||||
- `backend/convert.go` — Added `cHostConfigToModel()`, `cClusterConfHostConfigs()`, `cClusterConfToClusterInfo()`
|
||||
- `cResdefToModel` intentionally skipped — `xce_resdef_t` doesn't exist in C codebase and `ResourceInfo` has no store/consumer (YAGNI); existing `cResourceToModel` → `ResourceDefinitionInfo` already handles config push
|
||||
- `cClusterConfResources` already existed — no change needed
|
||||
- CGO compilation verified passing
|
||||
- All unit tests still passing
|
||||
|
||||
- [x] **#4 P0-1d: Implement handlers with partial merge + TDD**
|
||||
- `backend/notification.go` — Added `OnClusterUpdated(cluster *models.ClusterInfo)` and `OnHostConfigUpdated(host *models.HostInfo)` to `NotificationHandler` interface
|
||||
- `backend/handler.go` — Implemented partial-merge `OnClusterUpdated` (preserves Version, Status, ControllerName, NumServers, Resources, HostTypes, HostModels, ClusterAdmins), `OnHostConfigUpdated` (preserves HostStatus, CPUFactor, NumCPUs, NumCores, NumThreads, MaxMem, MaxSwap, MaxTmp, NumDisk, NumRun, NumSSusp, NumUSusp, NumDone, Topology, SchedStop), fixed `OnHostUpdated` (preserves HostModel, HostType, MaxSlot, DisptWindow via two-value `Get()`)
|
||||
- `backend/handler_test.go` — 6 new tests: new host, partial merge for each of OnHostConfigUpdated, OnClusterUpdated, OnHostUpdated
|
||||
- All backend tests passing (32 total)
|
||||
|
||||
- [x] **#5 P0-1e: Expand handleConfigPush** (unblocked)
|
||||
- `backend/clib.go` — Expand `handleConfigPush()` to call `cClusterConfHostConfigs()` and `cClusterConfToClusterInfo()`
|
||||
- Call `gHandler.OnHostConfigUpdated()` per host config, `gHandler.OnClusterUpdated()` for cluster settings
|
||||
|
||||
---
|
||||
|
||||
## P0-2: Host Control via Backend
|
||||
|
||||
- [ ] **#6 P0-2a: C-side plumbing for host control**
|
||||
- `schema/controller.capnp` — Add `HostControl` struct + `hostctrlmsg @21`
|
||||
- `include/typemap.h` — Add `xce_hostctrl_t* hostctrlmsg;` to body union
|
||||
- `include/client.h` — Add `xcecli_hostctrl()` declaration
|
||||
- `include/xceapi.h` — Add `xce_hostctrl()` declaration
|
||||
- `include/request.h` — Add `xce_hostctrl_req()` declaration
|
||||
- `lib/client.c` — Implement `xcecli_hostctrl()`
|
||||
- `lib/xceapi.c` — Implement `xce_hostctrl()` with `cbuf_get()` wait
|
||||
- `lib/request.c` — Implement `xce_hostctrl_req()` (validate HOST_OPEN/HOST_CLOSE only)
|
||||
- `lib/helper.c` — Add `Request_body_hostctrlmsg` case to `xce_request_body()` + `xce_request_msg_name()`
|
||||
- `controller/cluster.c` — Add `OPCode_hostcontrol` case → `do_hostcontrol_op()`
|
||||
- `controller/worker.c` — Implement `do_hostcontrol_op()` calling `worker_ctrl()`
|
||||
- `controller/include/cluster.h` — Declare `do_hostcontrol_op()`
|
||||
- Regenerate capnp: `ninja -C build`
|
||||
|
||||
- [>] **#7 P0-2b: Implement Go-side ControlHost + fix allFlag race** (blocked by #6)
|
||||
- `backend/clib.go` — Replace `ControlHost()` stub with real implementation via `xcecli_hostctrl()`
|
||||
- `controllers/hosts.go` — Fix data race: remove `var allFlag bool`, return from `preCheckHostControlRequest` as local
|
||||
- `controllers/queues.go` — Same allFlag data race fix (lines 534-536 / 465)
|
||||
|
||||
- [ ] **#8 P0-2c: Register routes + RBAC for host control/select**
|
||||
- `router/routers.go` — `POST /xce/v1/hosts/control` → RBAC `host:control` (cluster_admin)
|
||||
- `router/routers.go` — `POST /xce/v1/hosts/select` → RBAC `host:view` (all authenticated)
|
||||
- `config/rbac.yaml` — Add `host:control` and `host:view` action entries
|
||||
|
||||
- [ ] **#9 P0-2d: Update stub.go with new function stubs**
|
||||
- `backend/stub.go` — Keep `ControlHost` stub (return `errNoCGO`), add `StartHeartbeat(ctx context.Context){}`, `SetHeartbeatInterval(secs int){}`, `EvalSelectForHost(...)` returning `errNoCGO`, `Cleanup(){}`
|
||||
- Add `"context"` to import block
|
||||
|
||||
---
|
||||
|
||||
## P1-1: Handle Resource Value Push
|
||||
|
||||
- [ ] **#10 P1-1: Handle resource value push (OPCode_notify)**
|
||||
- `backend/clib.go` — Add CGO val helpers to preamble (`xce_val_which`, `xce_val_i32`, etc.)
|
||||
- `backend/clib.go` — Add `OPCode_notify` case at top-level switch in `go_push_handler()` (NOT inside `handlePush()`)
|
||||
- `backend/clib.go` — Add `handleNotifyData()` for `NotifyData_data_schedUpdateResvals`
|
||||
- `backend/convert.go` — Add `cResvalToDistribution()` — switch on `Value_u_*` constants, all 7 cases separate
|
||||
|
||||
---
|
||||
|
||||
## P1-2: Host Resource Requirement Select
|
||||
|
||||
- [ ] **#11 P1-2a: C select expression parser (PEG + eval)**
|
||||
- `include/resreq.h` — Replace empty `xce_resreq_select_` with expression tree types, add enums, add extern declarations
|
||||
- `lib/xce_select.peg` — New PEG grammar for select boolean expressions (right-recursive)
|
||||
- `lib/resreq.c` — Implement `parse_select()`, `eval_select()`, `free_select()`; update `kill_primary_resreq()`
|
||||
- `lib/meson.build` — Add `xce_select.peg` to explicit source list
|
||||
|
||||
- [>] **#12 P1-2b: Go EvalSelectForHost + FilterHostByResReqSelect** (blocked by #11)
|
||||
- `backend/clib.go` — Add `EvalSelectForHost()` using `cgo.Handle` for callback context, add `#include "resreq.h"`, extern declarations, `xce_select_destroy` helper
|
||||
- `controllers/hosts.go` — Implement `FilterHostByResReqSelect`, update `preCheckHostRequest()` limit from 4094→1024 bytes
|
||||
|
||||
---
|
||||
|
||||
## P1-3: Heartbeat Keep-Alive
|
||||
|
||||
- [ ] **#13 P1-3: Heartbeat keep-alive implementation**
|
||||
- `backend/clib.go` — Add `heartbeatIntervalSecs int32` (default 30), `SetHeartbeatInterval()`, `heartbeatFn` var, `StartHeartbeat(ctx context.Context)`
|
||||
- `backend/handler.go` — `OnClusterUpdated` calls `SetHeartbeatInterval(cluster.HeartbeatInterval)` after store update
|
||||
- `cmd/main.go` — Call `backend.StartHeartbeat(ctx)` after `backend.RegisterToBackend(...)`
|
||||
|
||||
---
|
||||
|
||||
## Final
|
||||
|
||||
- [>] **#14 Build and test verification** (blocked by all others)
|
||||
- `make test` in `src/frontend/` passes
|
||||
- `ninja -C build` for C components passes
|
||||
- RBAC verification
|
||||
- Input safety verification (1024-byte limit, 256-host limit)
|
||||
Loading…
Add table
Add a link
Reference in a new issue