From dac14df7ceef9c29f176daee32acdeea4159d3ec Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 6 Aug 2015 14:17:18 -0700 Subject: [PATCH] nomad: job deregister creates an evaluation --- nomad/job_endpoint.go | 34 +++++++++++++++++++++++++++++++--- nomad/job_endpoint_test.go | 30 +++++++++++++++++++++++++++++- nomad/structs/structs.go | 11 ++++++++++- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/nomad/job_endpoint.go b/nomad/job_endpoint.go index 839cc0b8f..f07ca9be9 100644 --- a/nomad/job_endpoint.go +++ b/nomad/job_endpoint.go @@ -79,7 +79,7 @@ func (j *Job) Register(args *structs.JobRegisterRequest, reply *structs.JobRegis } // Deregister is used to remove a job the cluster. -func (j *Job) Deregister(args *structs.JobDeregisterRequest, reply *structs.GenericResponse) error { +func (j *Job) Deregister(args *structs.JobDeregisterRequest, reply *structs.JobDeregisterResponse) error { if done, err := j.srv.forward("Job.Deregister", args, args, reply); done { return err } @@ -92,8 +92,36 @@ func (j *Job) Deregister(args *structs.JobDeregisterRequest, reply *structs.Gene return err } - // Set the reply index - reply.Index = index + // Create a new evaluation + // XXX: The job priority / type is strange for this, since it's not a high + // priority even if the job was. The scheduler itself also doesn't matter, + // since all should be able to handle deregistration in the same way. + eval := &structs.Evaluation{ + ID: generateUUID(), + Priority: structs.JobDefaultPriority, + Type: structs.JobTypeService, + TriggeredBy: structs.EvalTriggerJobDeregister, + JobID: args.JobID, + JobModifyIndex: index, + Status: structs.EvalStatusPending, + } + update := &structs.EvalUpdateRequest{ + Eval: eval, + WriteRequest: structs.WriteRequest{Region: args.Region}, + } + + // Commit this evaluation via Raft + _, evalIndex, err := j.srv.raftApply(structs.EvalUpdateRequestType, update) + if err != nil { + j.srv.logger.Printf("[ERR] nomad.job: Eval create failed: %v", err) + return err + } + + // Setup the reply + reply.EvalID = eval.ID + reply.EvalCreateIndex = evalIndex + reply.JobModifyIndex = index + reply.Index = evalIndex return nil } diff --git a/nomad/job_endpoint_test.go b/nomad/job_endpoint_test.go index 712467cba..f14cab699 100644 --- a/nomad/job_endpoint_test.go +++ b/nomad/job_endpoint_test.go @@ -178,7 +178,7 @@ func TestJobEndpoint_Deregister(t *testing.T) { JobID: job.ID, WriteRequest: structs.WriteRequest{Region: "region1"}, } - var resp2 structs.GenericResponse + var resp2 structs.JobDeregisterResponse if err := msgpackrpc.CallWithCodec(codec, "Job.Deregister", dereg, &resp2); err != nil { t.Fatalf("err: %v", err) } @@ -195,6 +195,34 @@ func TestJobEndpoint_Deregister(t *testing.T) { if out != nil { t.Fatalf("unexpected job") } + + // Lookup the evaluation + eval, err := state.GetEvalByID(resp2.EvalID) + if err != nil { + t.Fatalf("err: %v", err) + } + if eval == nil { + t.Fatalf("expected eval") + } + if eval.CreateIndex != resp2.EvalCreateIndex { + t.Fatalf("index mis-match") + } + + if eval.Priority != structs.JobDefaultPriority { + t.Fatalf("bad: %#v", eval) + } + if eval.Type != structs.JobTypeService { + t.Fatalf("bad: %#v", eval) + } + if eval.TriggeredBy != structs.EvalTriggerJobDeregister { + t.Fatalf("bad: %#v", eval) + } + if eval.JobID != job.ID { + t.Fatalf("bad: %#v", eval) + } + if eval.JobModifyIndex != resp2.JobModifyIndex { + t.Fatalf("bad: %#v", eval) + } } func TestJobEndpoint_GetJob(t *testing.T) { diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 9eac13b70..160ae9ae6 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -218,6 +218,14 @@ type JobRegisterResponse struct { QueryMeta } +// JobDeregisterResponse is used to respond to a job deregistration +type JobDeregisterResponse struct { + EvalID string + EvalCreateIndex uint64 + JobModifyIndex uint64 + QueryMeta +} + // SingleNodeResponse is used to return a single node type SingleNodeResponse struct { Node *Node @@ -615,7 +623,8 @@ const ( ) const ( - EvalTriggerJobRegister = "job-register" + EvalTriggerJobRegister = "job-register" + EvalTriggerJobDeregister = "job-deregister" ) // Evaluation is used anytime we need to apply business logic as a result