From 3c6235b6dfd7eb215d575a8db948492264a278cf Mon Sep 17 00:00:00 2001 From: James Rasell Date: Fri, 8 May 2020 16:51:40 +0200 Subject: [PATCH] api: validate scale count value is not negative. An operator could submit a scale request including a negative count value. This negative value caused the Nomad server to panic. The fix adds validation to the submitted count, returning an error to the caller if it is negative. --- nomad/job_endpoint.go | 3 +++ nomad/job_endpoint_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/nomad/job_endpoint.go b/nomad/job_endpoint.go index a564efb33..536a051ee 100644 --- a/nomad/job_endpoint.go +++ b/nomad/job_endpoint.go @@ -905,6 +905,9 @@ func (j *Job) Scale(args *structs.JobScaleRequest, reply *structs.JobRegisterRes if args.Error && args.Count != nil { return structs.NewErrRPCCoded(400, "scaling action should not contain count if error is true") } + if args.Count != nil && *args.Count < 0 { + return structs.NewErrRPCCoded(400, "scaling action count can't be negative") + } // Check for submit-job permissions if aclObj, err := j.srv.ResolveToken(args.AuthToken); err != nil { diff --git a/nomad/job_endpoint_test.go b/nomad/job_endpoint_test.go index f0468db1c..2f3af3fd9 100644 --- a/nomad/job_endpoint_test.go +++ b/nomad/job_endpoint_test.go @@ -5617,6 +5617,36 @@ func TestJobEndpoint_Scale_NoEval(t *testing.T) { require.Greater(eventsIndex, jobCreateIndex) } +func TestJobEndpoint_InvalidCount(t *testing.T) { + t.Parallel() + require := require.New(t) + + s1, cleanupS1 := TestServer(t, nil) + defer cleanupS1() + codec := rpcClient(t, s1) + testutil.WaitForLeader(t, s1.RPC) + state := s1.fsm.State() + + job := mock.Job() + err := state.UpsertJob(1000, job) + require.Nil(err) + + scale := &structs.JobScaleRequest{ + JobID: job.ID, + Target: map[string]string{ + structs.ScalingTargetGroup: job.TaskGroups[0].Name, + }, + Count: helper.Int64ToPtr(int64(-1)), + WriteRequest: structs.WriteRequest{ + Region: "global", + Namespace: job.Namespace, + }, + } + var resp structs.JobRegisterResponse + err = msgpackrpc.CallWithCodec(codec, "Job.Scale", scale, &resp) + require.Error(err) +} + func TestJobEndpoint_GetScaleStatus(t *testing.T) { t.Parallel() require := require.New(t)