fix(apiserver): thread from_host through the CGO conversion layer (bug-1676, gitea #44)

modelJobToSubmit/freeJobSubmit (submit direction) and
cJobToModel/cJobArrayToModels (receive direction, both single-job and
array-job paths) now carry from_host across the CGO boundary.
rawSubmitData/rawJobToModel (the pure-Go, CGO-free mapping layer) gain
the field too, completing the round-trip so JobInfo.FromHost reflects
whatever the controller actually has -- which, as of the prior two
commits, is now always the client-asserted hostname. backend/handler.go
needs no change: its existing blind overwrite in OnJobUpdated is
correct by construction once every controller push genuinely carries
the right value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
This commit is contained in:
Rongsong Shen 2026-08-24 15:14:49 +00:00
parent 363709b032
commit 1a61b04ab6
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
3 changed files with 28 additions and 0 deletions

View file

@ -53,6 +53,7 @@ func cJobArrayToModels(jobArray *C.xce_job_submit_t) []*models.JobInfo {
resReq: goString(s.resreq),
minTasks: int(s.mintasks),
maxTasks: int(s.maxtasks),
fromHost: goString(s.from_host),
}
if s.start_info != nil {
si := s.start_info
@ -93,6 +94,7 @@ func cJobToModel(job *C.xce_job_t) *models.JobInfo {
resReq: goString(s.resreq),
minTasks: int(s.mintasks),
maxTasks: int(s.maxtasks),
fromHost: goString(s.from_host),
}
if s.start_info != nil {
si := s.start_info
@ -278,6 +280,9 @@ func modelJobToSubmit(job *models.JobInfo) (*C.xce_job_submit_t, *C.job_submit_d
if job.ResReq != "" {
sd.resreq = C.CString(job.ResReq)
}
if job.FromHost != "" {
sd.from_host = C.CString(job.FromHost)
}
sd.mintasks = C.uint(job.NumProcessors)
if sd.mintasks == 0 {
sd.mintasks = 1
@ -313,6 +318,7 @@ func freeJobSubmit(js *C.xce_job_submit_t, sd *C.job_submit_data_t, si *C.job_st
C.free(unsafe.Pointer(sd.user_group))
C.free(unsafe.Pointer(sd.job_description))
C.free(unsafe.Pointer(sd.resreq))
C.free(unsafe.Pointer(sd.from_host))
C.free(unsafe.Pointer(sd))
}
if js != nil {

View file

@ -127,6 +127,7 @@ type rawSubmitData struct {
minTasks int
maxTasks int
startInfo *rawStartInfo
fromHost string
}
// rawJobData mirrors the C xce_job_t fields used by the Go model.
@ -197,6 +198,7 @@ func rawJobToModel(r rawJobData) *models.JobInfo {
info.ResReq = s.resReq
info.NumProcessors = s.minTasks
info.MaxNumProcessors = s.maxTasks
info.FromHost = s.fromHost
if s.startInfo != nil {
si := s.startInfo
info.Command = si.cmdline

View file

@ -16,6 +16,7 @@ func TestRawJobToModel_BasicFields(t *testing.T) {
jobName: "myjob",
minTasks: 1,
maxTasks: 4,
fromHost: "203.0.113.7",
startInfo: &rawStartInfo{
cmdline: "sleep 60",
},
@ -54,6 +55,25 @@ func TestRawJobToModel_BasicFields(t *testing.T) {
if info.RunTime != 42 {
t.Errorf("RunTime: got %d, want 42", info.RunTime)
}
if info.FromHost != "203.0.113.7" {
t.Errorf("FromHost: got %q, want %q", info.FromHost, "203.0.113.7")
}
}
// bug-1676: FromHost must round-trip through rawSubmitData into JobInfo like
// every other submit-time field, and must be empty-safe (no submit data, or
// submit data with no from_host, must not panic and must leave FromHost "").
func TestRawJobToModel_FromHost_EmptySafe(t *testing.T) {
r := rawJobData{
jobID: 1,
submit: &rawSubmitData{queue: "normal"},
}
info := rawJobToModel(r)
if info.FromHost != "" {
t.Errorf("FromHost: got %q, want empty string when submit.fromHost is unset", info.FromHost)
}
}
func TestRawJobToModel_NilSubmit(t *testing.T) {