diff --git a/api/jobs_test.go b/api/jobs_test.go index d696f2c6e678..a2659a667732 100644 --- a/api/jobs_test.go +++ b/api/jobs_test.go @@ -266,8 +266,9 @@ func TestJobs_Deregister(t *testing.T) { assertWriteMeta(t, wm) // Attempting delete on non-existing job returns an error - if _, _, err = jobs.Deregister("nope", nil); err == nil { - t.Fatalf("expected error deregistering job") + if _, _, err = jobs.Deregister("nope", nil); err != nil { + t.Fatalf("unexpected error deregistering job: %v", err) + } // Deleting an existing job works diff --git a/nomad/job_endpoint.go b/nomad/job_endpoint.go index eb6205e06e02..87df42a4bdb8 100644 --- a/nomad/job_endpoint.go +++ b/nomad/job_endpoint.go @@ -179,9 +179,6 @@ func (j *Job) Deregister(args *structs.JobDeregisterRequest, reply *structs.JobD if err != nil { return err } - if job == nil { - return fmt.Errorf("job not found") - } // Commit this update via Raft _, index, err := j.srv.raftApply(structs.JobDeregisterRequestType, args) @@ -194,7 +191,7 @@ func (j *Job) Deregister(args *structs.JobDeregisterRequest, reply *structs.JobD reply.JobModifyIndex = index // If the job is periodic, we don't create an eval. - if job.IsPeriodic() { + if job != nil && job.IsPeriodic() { return nil } diff --git a/nomad/job_endpoint_test.go b/nomad/job_endpoint_test.go index 7c313e8d01a9..16131414cba5 100644 --- a/nomad/job_endpoint_test.go +++ b/nomad/job_endpoint_test.go @@ -463,6 +463,61 @@ func TestJobEndpoint_Deregister(t *testing.T) { } } +func TestJobEndpoint_Deregister_NonExistent(t *testing.T) { + s1 := testServer(t, func(c *Config) { + c.NumSchedulers = 0 // Prevent automatic dequeue + }) + defer s1.Shutdown() + codec := rpcClient(t, s1) + testutil.WaitForLeader(t, s1.RPC) + + // Deregister + jobID := "foo" + dereg := &structs.JobDeregisterRequest{ + JobID: jobID, + WriteRequest: structs.WriteRequest{Region: "global"}, + } + var resp2 structs.JobDeregisterResponse + if err := msgpackrpc.CallWithCodec(codec, "Job.Deregister", dereg, &resp2); err != nil { + t.Fatalf("err: %v", err) + } + if resp2.JobModifyIndex == 0 { + t.Fatalf("bad index: %d", resp2.Index) + } + + // Lookup the evaluation + state := s1.fsm.State() + eval, err := state.EvalByID(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 != jobID { + t.Fatalf("bad: %#v", eval) + } + if eval.JobModifyIndex != resp2.JobModifyIndex { + t.Fatalf("bad: %#v", eval) + } + if eval.Status != structs.EvalStatusPending { + t.Fatalf("bad: %#v", eval) + } +} + func TestJobEndpoint_Deregister_Periodic(t *testing.T) { s1 := testServer(t, func(c *Config) { c.NumSchedulers = 0 // Prevent automatic dequeue