diff --git a/command/agent/resources_endpoint_test.go b/command/agent/resources_endpoint_test.go index e19b7d411..b0652e6db 100644 --- a/command/agent/resources_endpoint_test.go +++ b/command/agent/resources_endpoint_test.go @@ -45,7 +45,7 @@ func TestHTTP_ResourcesWithSingleJob(t *testing.T) { httpTest(t, nil, func(s *TestAgent) { createJobForTest(testJob, s, t) - data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "jobs"} + data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "job"} req, err := http.NewRequest("POST", "/v1/resources", encodeReq(data)) if err != nil { @@ -63,7 +63,7 @@ func TestHTTP_ResourcesWithSingleJob(t *testing.T) { t.Fatalf("No expected key values in resources list") } - j := res.Matches["jobs"] + j := res.Matches["job"] if j == nil || len(j) != 1 { t.Fatalf("The number of jobs that were returned does not equal the number of jobs we expected (1)", j) } @@ -85,7 +85,7 @@ func TestHTTP_ResourcesWithMultipleJobs(t *testing.T) { createJobForTest(testJobB, s, t) createJobForTest(testJobC, s, t) - data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "jobs"} + data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "job"} req, err := http.NewRequest("POST", "/v1/resources", encodeReq(data)) if err != nil { @@ -103,7 +103,7 @@ func TestHTTP_ResourcesWithMultipleJobs(t *testing.T) { t.Fatalf("No expected key values in resources list") } - j := res.Matches["jobs"] + j := res.Matches["job"] if j == nil || len(j) != 2 { t.Fatalf("The number of jobs that were returned does not equal the number of jobs we expected (2)", j) } @@ -114,6 +114,47 @@ func TestHTTP_ResourcesWithMultipleJobs(t *testing.T) { }) } +func TestHTTP_ResoucesListForEvaluations(t *testing.T) { + t.Parallel() + httpTest(t, nil, func(s *TestAgent) { + state := s.Agent.server.State() + eval1 := mock.Eval() + eval2 := mock.Eval() + err := state.UpsertEvals(1000, + []*structs.Evaluation{eval1, eval2}) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Make the HTTP request + evalPrefix := eval1.ID[:len(eval1.ID)-2] + data := structs.ResourcesRequest{Prefix: evalPrefix, Context: "eval"} + req, err := http.NewRequest("POST", "/v1/resources", encodeReq(data)) + if err != nil { + t.Fatalf("err: %v", err) + } + respW := httptest.NewRecorder() + + resp, err := s.Server.ResourcesRequest(respW, req) + if err != nil { + t.Fatalf("err: %v", err) + } + + res := resp.(structs.ResourcesResponse) + if len(res.Matches) != 1 { + t.Fatalf("No expected key values in resources list") + } + + j := res.Matches["eval"] + if len(j) != 1 { + t.Fatalf("The number of evaluations that were returned does not equal the number we expected (1)", j) + } + + assert.Contains(t, j, eval1.ID) + assert.NotContains(t, j, eval2.ID) + }) +} + // TODO //func TestHTTP_ResourcesWithNoJob(t *testing.T) { //} diff --git a/nomad/resources_endpoint.go b/nomad/resources_endpoint.go index eabc9e4c8..7414fe9aa 100644 --- a/nomad/resources_endpoint.go +++ b/nomad/resources_endpoint.go @@ -28,23 +28,47 @@ func (r *Resources) List(args *structs.ResourcesRequest, // return jobs matching given prefix var err error var iter memdb.ResultIterator - iter, err = state.JobsByIDPrefix(ws, args.Prefix) - if err != nil { - return err - } - var jobs []string - for i := 0; i < 20; i++ { - raw := iter.Next() - if raw == nil { - break + if args.Context == "job" { + iter, err = state.JobsByIDPrefix(ws, args.Prefix) + if err != nil { + return err } - job := raw.(*structs.Job) - jobs = append(jobs, job.ID) + var jobs []string + for i := 0; i < 20; i++ { + raw := iter.Next() + if raw == nil { + break + } + + job := raw.(*structs.Job) + jobs = append(jobs, job.ID) + } + + matches["job"] = jobs + } + + if args.Context == "eval" { + iter, err = state.EvalsByIDPrefix(ws, args.Prefix) + if err != nil { + return err + } + + var evals []string + for i := 0; i < 20; i++ { // TODO extract magic number + raw := iter.Next() + if raw == nil { + break + } + + eval := raw.(*structs.Evaluation) + evals = append(evals, eval.ID) + } + + matches["eval"] = evals } - matches["jobs"] = jobs reply.Matches = matches return nil diff --git a/nomad/resources_endpoint_test.go b/nomad/resources_endpoint_test.go index 73b7a743a..5e64c0156 100644 --- a/nomad/resources_endpoint_test.go +++ b/nomad/resources_endpoint_test.go @@ -48,12 +48,12 @@ func TestResourcesEndpoint_List(t *testing.T) { t.Fatalf("err: %v", err) } - num_matches := len(resp.Matches["jobs"]) + num_matches := len(resp.Matches["job"]) if num_matches != 1 { t.Fatalf(fmt.Sprintf("err: the number of jobs expected %d does not match the number of jobs registered %d", 1, num_matches)) } - assert.Equal(t, jobID, resp.Matches["jobs"][0]) + assert.Equal(t, jobID, resp.Matches["job"][0]) } func TestResourcesEndpoint_List_ShouldTruncateResultsToUnder20(t *testing.T) { @@ -82,8 +82,44 @@ func TestResourcesEndpoint_List_ShouldTruncateResultsToUnder20(t *testing.T) { t.Fatalf("err: %v", err) } - num_matches := len(resp.Matches["jobs"]) + num_matches := len(resp.Matches["job"]) if num_matches != 20 { t.Fatalf(fmt.Sprintf("err: the number of jobs expected %d does not match the number of jobs returned %d", 20, num_matches)) } } + +func TestResourcesEndpoint_List_ShouldReturnEvals(t *testing.T) { + t.Parallel() + s := testServer(t, func(c *Config) { + c.NumSchedulers = 0 // Prevent automatic dequeue + }) + + defer s.Shutdown() + codec := rpcClient(t, s) + testutil.WaitForLeader(t, s.RPC) + + eval1 := mock.Eval() + s.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}) + + prefix := eval1.ID[:len(eval1.ID)-2] + + req := &structs.ResourcesRequest{ + Prefix: prefix, + Context: "eval", + } + + var resp structs.ResourcesResponse + if err := msgpackrpc.CallWithCodec(codec, "Resources.List", req, &resp); err != nil { + t.Fatalf("err: %v", err) + } + + numMatches := len(resp.Matches["eval"]) + if numMatches != 1 { + t.Fatalf(fmt.Sprintf("err: the number of evaluations expected %d does not match the number expected %d", 1, numMatches)) + } + + recEval := resp.Matches["eval"][0] + if recEval != eval1.ID { + t.Fatalf(fmt.Sprintf("err: expected %s evaluation but received %s", eval1.ID, recEval)) + } +}