Add preserve-resources flag (#26841)

* Add preserve-resources flag when registering a job

* Add preserve-resources flag to website docs

* Add changelog

* Update tests, docs

* Preserve counts & resources in fsm

* Update doc

* Update preservation of resources/count to happen in StateStore
This commit is contained in:
Allison Larson
2025-10-02 13:56:59 -07:00
committed by GitHub
parent b22b7ab273
commit e40164abce
15 changed files with 387 additions and 61 deletions

View File

@@ -120,12 +120,13 @@ func (j *Jobs) Validate(job *Job, q *WriteOptions) (*JobValidateResponse, *Write
// RegisterOptions is used to pass through job registration parameters
type RegisterOptions struct {
EnforceIndex bool
ModifyIndex uint64
PolicyOverride bool
PreserveCounts bool
EvalPriority int
Submission *JobSubmission
EnforceIndex bool
ModifyIndex uint64
PolicyOverride bool
PreserveCounts bool
PreserveResources bool
EvalPriority int
Submission *JobSubmission
}
// Register is used to register a new job. It returns the ID
@@ -152,6 +153,7 @@ func (j *Jobs) RegisterOpts(job *Job, opts *RegisterOptions, q *WriteOptions) (*
}
req.PolicyOverride = opts.PolicyOverride
req.PreserveCounts = opts.PreserveCounts
req.PreserveResources = opts.PreserveResources
req.EvalPriority = opts.EvalPriority
req.Submission = opts.Submission
}
@@ -1486,10 +1488,11 @@ type JobRegisterRequest struct {
// If EnforceIndex is set then the job will only be registered if the passed
// JobModifyIndex matches the current Jobs index. If the index is zero, the
// register only occurs if the job is new.
EnforceIndex bool `json:",omitempty"`
JobModifyIndex uint64 `json:",omitempty"`
PolicyOverride bool `json:",omitempty"`
PreserveCounts bool `json:",omitempty"`
EnforceIndex bool `json:",omitempty"`
JobModifyIndex uint64 `json:",omitempty"`
PolicyOverride bool `json:",omitempty"`
PreserveCounts bool `json:",omitempty"`
PreserveResources bool `json:",omitempty"`
// EvalPriority is an optional priority to use on any evaluation created as
// a result on this job registration. This value must be between 1-100

View File

@@ -186,6 +186,118 @@ func TestJobs_Register_NoPreserveCounts(t *testing.T) {
must.Eq(t, 3, status.TaskGroups["group3"].Desired) // new => as specified
}
func TestJobs_Register_PreserveResources(t *testing.T) {
testutil.Parallel(t)
c, s := makeClient(t, nil, nil)
defer s.Stop()
jobs := c.Jobs()
// Listing jobs before registering returns nothing
resp, _, err := jobs.List(nil)
must.NoError(t, err)
must.SliceEmpty(t, resp)
// Create a job
task := NewTask("task", "exec").
SetConfig("command", "/bin/echo").
SetLogConfig(&LogConfig{
MaxFiles: pointerOf(1),
MaxFileSizeMB: pointerOf(2),
})
group1 := NewTaskGroup("group1", 1).
AddTask(task).
RequireDisk(&EphemeralDisk{
SizeMB: pointerOf(25),
})
job := NewBatchJob("job", "redis", "global", 1).
AddDatacenter("dc1").
AddTaskGroup(group1)
// Create a job and register it
resp2, wm, err := jobs.Register(job, nil)
must.NoError(t, err)
must.NotNil(t, resp2)
must.UUIDv4(t, resp2.EvalID)
assertWriteMeta(t, wm)
// Update the job, new groups to test PreserveCounts
task.Resources = &Resources{
CPU: pointerOf(50),
MemoryMB: pointerOf(128),
}
// Update the job, with PreserveResources = true
_, _, err = jobs.RegisterOpts(job, &RegisterOptions{
PreserveResources: true,
}, nil)
must.NoError(t, err)
// Query the job scale status
registered, _, err := jobs.Info(*job.ID, nil)
must.NoError(t, err)
must.Eq(t, 100, *registered.TaskGroups[0].Tasks[0].Resources.CPU) // preserved
must.Eq(t, 300, *registered.TaskGroups[0].Tasks[0].Resources.MemoryMB) // preserved
}
func TestJobs_Register_NoPreserveResources(t *testing.T) {
testutil.Parallel(t)
c, s := makeClient(t, nil, nil)
defer s.Stop()
jobs := c.Jobs()
// Listing jobs before registering returns nothing
resp, _, err := jobs.List(nil)
must.NoError(t, err)
must.SliceEmpty(t, resp)
// Create a job
task := NewTask("task", "exec").
SetConfig("command", "/bin/echo").
SetLogConfig(&LogConfig{
MaxFiles: pointerOf(1),
MaxFileSizeMB: pointerOf(2),
})
group1 := NewTaskGroup("group1", 1).
AddTask(task).
RequireDisk(&EphemeralDisk{
SizeMB: pointerOf(25),
})
job := NewBatchJob("job", "redis", "global", 1).
AddDatacenter("dc1").
AddTaskGroup(group1)
// Create a job and register it
resp2, wm, err := jobs.Register(job, nil)
must.NoError(t, err)
must.NotNil(t, resp2)
must.UUIDv4(t, resp2.EvalID)
assertWriteMeta(t, wm)
// Update the job, new groups to test PreserveCounts
task.Resources = &Resources{
CPU: pointerOf(50),
MemoryMB: pointerOf(128),
}
// Update the job, with PreserveResources = true
_, _, err = jobs.RegisterOpts(job, &RegisterOptions{
PreserveResources: false,
}, nil)
must.NoError(t, err)
// Query the job scale status
registered, _, err := jobs.Info(*job.ID, nil)
must.NoError(t, err)
must.Eq(t, 50, *registered.TaskGroups[0].Tasks[0].Resources.CPU) // updated
must.Eq(t, 128, *registered.TaskGroups[0].Tasks[0].Resources.MemoryMB) // updated
}
func TestJobs_Register_EvalPriority(t *testing.T) {
testutil.Parallel(t)