mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 10:25:42 +03:00
core: allow setting and propagation of eval priority on job de/registration (#11532)
This change modifies the Nomad job register and deregister RPCs to accept an updated option set which includes eval priority. This param is optional and override the use of the job priority to set the eval priority. In order to ensure all evaluations as a result of the request use the same eval priority, the priority is shared to the allocReconciler and deploymentWatcher. This creates a new distinction between eval priority and job priority. The Nomad agent HTTP API has been modified to allow setting the eval priority on job update and delete. To keep consistency with the current v1 API, job update accepts this as a payload param; job delete accepts this as a query param. Any user supplied value is validated within the agent HTTP handler removing the need to pass invalid requests to the server. The register and deregister opts functions now all for setting the eval priority on requests. The change includes a small change to the DeregisterOpts function which handles nil opts. This brings the function inline with the RegisterOpts.
This commit is contained in:
35
api/jobs.go
35
api/jobs.go
@@ -91,6 +91,7 @@ type RegisterOptions struct {
|
||||
ModifyIndex uint64
|
||||
PolicyOverride bool
|
||||
PreserveCounts bool
|
||||
EvalPriority int
|
||||
}
|
||||
|
||||
// Register is used to register a new job. It returns the ID
|
||||
@@ -105,8 +106,8 @@ func (j *Jobs) EnforceRegister(job *Job, modifyIndex uint64, q *WriteOptions) (*
|
||||
return j.RegisterOpts(job, &opts, q)
|
||||
}
|
||||
|
||||
// Register is used to register a new job. It returns the ID
|
||||
// of the evaluation, along with any errors encountered.
|
||||
// RegisterOpts is used to register a new job with the passed RegisterOpts. It
|
||||
// returns the ID of the evaluation, along with any errors encountered.
|
||||
func (j *Jobs) RegisterOpts(job *Job, opts *RegisterOptions, q *WriteOptions) (*JobRegisterResponse, *WriteMeta, error) {
|
||||
// Format the request
|
||||
req := &JobRegisterRequest{
|
||||
@@ -119,6 +120,7 @@ func (j *Jobs) RegisterOpts(job *Job, opts *RegisterOptions, q *WriteOptions) (*
|
||||
}
|
||||
req.PolicyOverride = opts.PolicyOverride
|
||||
req.PreserveCounts = opts.PreserveCounts
|
||||
req.EvalPriority = opts.EvalPriority
|
||||
}
|
||||
|
||||
var resp JobRegisterResponse
|
||||
@@ -290,14 +292,31 @@ type DeregisterOptions struct {
|
||||
// If Global is set to true, all regions of a multiregion job will be
|
||||
// stopped.
|
||||
Global bool
|
||||
|
||||
// EvalPriority is an optional priority to use on any evaluation created as
|
||||
// a result on this job deregistration. This value must be between 1-100
|
||||
// inclusively, where a larger value corresponds to a higher priority. This
|
||||
// is useful when an operator wishes to push through a job deregistration
|
||||
// in busy clusters with a large evaluation backlog.
|
||||
EvalPriority int
|
||||
}
|
||||
|
||||
// DeregisterOpts is used to remove an existing job. See DeregisterOptions
|
||||
// for parameters.
|
||||
func (j *Jobs) DeregisterOpts(jobID string, opts *DeregisterOptions, q *WriteOptions) (string, *WriteMeta, error) {
|
||||
var resp JobDeregisterResponse
|
||||
wm, err := j.client.delete(fmt.Sprintf("/v1/job/%v?purge=%t&global=%t",
|
||||
url.PathEscape(jobID), opts.Purge, opts.Global), &resp, q)
|
||||
|
||||
// The base endpoint to add query params to.
|
||||
endpoint := "/v1/job/" + url.PathEscape(jobID)
|
||||
|
||||
// Protect against nil opts. url.Values expects a string, and so using
|
||||
// fmt.Sprintf is the best way to do this.
|
||||
if opts != nil {
|
||||
endpoint += fmt.Sprintf("?purge=%t&global=%t&eval_priority=%v",
|
||||
opts.Purge, opts.Global, opts.EvalPriority)
|
||||
}
|
||||
|
||||
wm, err := j.client.delete(endpoint, &resp, q)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@@ -1170,6 +1189,14 @@ type JobRegisterRequest struct {
|
||||
PolicyOverride bool `json:",omitempty"`
|
||||
PreserveCounts 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
|
||||
// inclusively, where a larger value corresponds to a higher priority. This
|
||||
// is useful when an operator wishes to push through a job registration in
|
||||
// busy clusters with a large evaluation backlog. This avoids needing to
|
||||
// change the job priority which also impacts preemption.
|
||||
EvalPriority int `json:",omitempty"`
|
||||
|
||||
WriteRequest
|
||||
}
|
||||
|
||||
|
||||
116
api/jobs_test.go
116
api/jobs_test.go
@@ -187,6 +187,60 @@ func TestJobs_Register_NoPreserveCounts(t *testing.T) {
|
||||
require.Equal(3, status.TaskGroups["group3"].Desired) // new => as specified
|
||||
}
|
||||
|
||||
func TestJobs_Register_EvalPriority(t *testing.T) {
|
||||
t.Parallel()
|
||||
requireAssert := require.New(t)
|
||||
|
||||
c, s := makeClient(t, nil, nil)
|
||||
defer s.Stop()
|
||||
|
||||
// Listing jobs before registering returns nothing
|
||||
listResp, _, err := c.Jobs().List(nil)
|
||||
requireAssert.Nil(err)
|
||||
requireAssert.Len(listResp, 0)
|
||||
|
||||
// Create a job and register it with an eval priority.
|
||||
job := testJob()
|
||||
registerResp, wm, err := c.Jobs().RegisterOpts(job, &RegisterOptions{EvalPriority: 99}, nil)
|
||||
requireAssert.Nil(err)
|
||||
requireAssert.NotNil(registerResp)
|
||||
requireAssert.NotEmpty(registerResp.EvalID)
|
||||
assertWriteMeta(t, wm)
|
||||
|
||||
// Check the created job evaluation has a priority that matches our desired
|
||||
// value.
|
||||
evalInfo, _, err := c.Evaluations().Info(registerResp.EvalID, nil)
|
||||
requireAssert.NoError(err)
|
||||
requireAssert.Equal(99, evalInfo.Priority)
|
||||
}
|
||||
|
||||
func TestJobs_Register_NoEvalPriority(t *testing.T) {
|
||||
t.Parallel()
|
||||
requireAssert := require.New(t)
|
||||
|
||||
c, s := makeClient(t, nil, nil)
|
||||
defer s.Stop()
|
||||
|
||||
// Listing jobs before registering returns nothing
|
||||
listResp, _, err := c.Jobs().List(nil)
|
||||
requireAssert.Nil(err)
|
||||
requireAssert.Len(listResp, 0)
|
||||
|
||||
// Create a job and register it with an eval priority.
|
||||
job := testJob()
|
||||
registerResp, wm, err := c.Jobs().RegisterOpts(job, nil, nil)
|
||||
requireAssert.Nil(err)
|
||||
requireAssert.NotNil(registerResp)
|
||||
requireAssert.NotEmpty(registerResp.EvalID)
|
||||
assertWriteMeta(t, wm)
|
||||
|
||||
// Check the created job evaluation has a priority that matches the job
|
||||
// priority.
|
||||
evalInfo, _, err := c.Evaluations().Info(registerResp.EvalID, nil)
|
||||
requireAssert.NoError(err)
|
||||
requireAssert.Equal(*job.Priority, evalInfo.Priority)
|
||||
}
|
||||
|
||||
func TestJobs_Validate(t *testing.T) {
|
||||
t.Parallel()
|
||||
c, s := makeClient(t, nil, nil)
|
||||
@@ -1628,6 +1682,68 @@ func TestJobs_Deregister(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobs_Deregister_EvalPriority(t *testing.T) {
|
||||
t.Parallel()
|
||||
requireAssert := require.New(t)
|
||||
|
||||
c, s := makeClient(t, nil, nil)
|
||||
defer s.Stop()
|
||||
|
||||
// Listing jobs before registering returns nothing
|
||||
listResp, _, err := c.Jobs().List(nil)
|
||||
requireAssert.Nil(err)
|
||||
requireAssert.Len(listResp, 0)
|
||||
|
||||
// Create a job and register it.
|
||||
job := testJob()
|
||||
registerResp, wm, err := c.Jobs().Register(job, nil)
|
||||
requireAssert.Nil(err)
|
||||
requireAssert.NotNil(registerResp)
|
||||
requireAssert.NotEmpty(registerResp.EvalID)
|
||||
assertWriteMeta(t, wm)
|
||||
|
||||
// Deregister the job with an eval priority.
|
||||
evalID, _, err := c.Jobs().DeregisterOpts(*job.ID, &DeregisterOptions{EvalPriority: 97}, nil)
|
||||
requireAssert.NoError(err)
|
||||
requireAssert.NotEmpty(t, evalID)
|
||||
|
||||
// Lookup the eval and check the priority on it.
|
||||
evalInfo, _, err := c.Evaluations().Info(evalID, nil)
|
||||
requireAssert.NoError(err)
|
||||
requireAssert.Equal(97, evalInfo.Priority)
|
||||
}
|
||||
|
||||
func TestJobs_Deregister_NoEvalPriority(t *testing.T) {
|
||||
t.Parallel()
|
||||
requireAssert := require.New(t)
|
||||
|
||||
c, s := makeClient(t, nil, nil)
|
||||
defer s.Stop()
|
||||
|
||||
// Listing jobs before registering returns nothing
|
||||
listResp, _, err := c.Jobs().List(nil)
|
||||
requireAssert.Nil(err)
|
||||
requireAssert.Len(listResp, 0)
|
||||
|
||||
// Create a job and register it.
|
||||
job := testJob()
|
||||
registerResp, wm, err := c.Jobs().Register(job, nil)
|
||||
requireAssert.Nil(err)
|
||||
requireAssert.NotNil(registerResp)
|
||||
requireAssert.NotEmpty(registerResp.EvalID)
|
||||
assertWriteMeta(t, wm)
|
||||
|
||||
// Deregister the job with an eval priority.
|
||||
evalID, _, err := c.Jobs().DeregisterOpts(*job.ID, &DeregisterOptions{}, nil)
|
||||
requireAssert.NoError(err)
|
||||
requireAssert.NotEmpty(t, evalID)
|
||||
|
||||
// Lookup the eval and check the priority on it.
|
||||
evalInfo, _, err := c.Evaluations().Info(evalID, nil)
|
||||
requireAssert.NoError(err)
|
||||
requireAssert.Equal(*job.Priority, evalInfo.Priority)
|
||||
}
|
||||
|
||||
func TestJobs_ForceEvaluate(t *testing.T) {
|
||||
t.Parallel()
|
||||
c, s := makeClient(t, nil, nil)
|
||||
|
||||
Reference in New Issue
Block a user