diff --git a/command/agent/resources_endpoint.go b/command/agent/resources_endpoint.go index 40106d3c5..36e0054fe 100644 --- a/command/agent/resources_endpoint.go +++ b/command/agent/resources_endpoint.go @@ -6,7 +6,7 @@ import ( ) // ResourcesRequest accepts a prefix and context and returns a list of matching -// prefixes for that context. +// IDs for that context. func (s *HTTPServer) ResourcesRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { if req.Method == "POST" || req.Method == "PUT" { return s.resourcesRequest(resp, req) diff --git a/command/agent/resources_endpoint_test.go b/command/agent/resources_endpoint_test.go index 60662f9ca..f658cf936 100644 --- a/command/agent/resources_endpoint_test.go +++ b/command/agent/resources_endpoint_test.go @@ -43,7 +43,7 @@ func TestHTTP_Resources_POST(t *testing.T) { httpTest(t, nil, func(s *TestAgent) { createJobForTest(testJob, s, t) - data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "job"} + data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "jobs"} req, err := http.NewRequest("POST", "/v1/resources", encodeReq(data)) if err != nil { @@ -60,11 +60,13 @@ func TestHTTP_Resources_POST(t *testing.T) { assert.Equal(t, 1, len(res.Matches)) - j := res.Matches["job"] + j := res.Matches["jobs"] assert.Equal(t, 1, len(j)) assert.Equal(t, j[0], testJob) + assert.Equal(t, res.Truncations["job"], false) + assert.NotEqual(t, "0", respW.HeaderMap.Get("X-Nomad-Index")) }) } @@ -75,7 +77,7 @@ func TestHTTP_Resources_PUT(t *testing.T) { httpTest(t, nil, func(s *TestAgent) { createJobForTest(testJob, s, t) - data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "job"} + data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "jobs"} req, err := http.NewRequest("PUT", "/v1/resources", encodeReq(data)) if err != nil { @@ -92,11 +94,13 @@ func TestHTTP_Resources_PUT(t *testing.T) { assert.Equal(t, 1, len(res.Matches)) - j := res.Matches["job"] + j := res.Matches["jobs"] assert.Equal(t, 1, len(j)) assert.Equal(t, j[0], testJob) + assert.Equal(t, res.Truncations["job"], false) + assert.NotEqual(t, "0", respW.HeaderMap.Get("X-Nomad-Index")) }) } @@ -113,7 +117,7 @@ func TestHTTP_Resources_MultipleJobs(t *testing.T) { createJobForTest(testJobB, s, t) createJobForTest(testJobC, s, t) - data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "job"} + data := structs.ResourcesRequest{Prefix: testJobPrefix, Context: "jobs"} req, err := http.NewRequest("POST", "/v1/resources", encodeReq(data)) if err != nil { @@ -130,12 +134,15 @@ func TestHTTP_Resources_MultipleJobs(t *testing.T) { assert.Equal(t, 1, len(res.Matches)) - j := res.Matches["job"] + j := res.Matches["jobs"] assert.Equal(t, 2, len(j)) assert.Contains(t, j, testJobA) assert.Contains(t, j, testJobB) assert.NotContains(t, j, testJobC) + + assert.Equal(t, res.Truncations["job"], false) + assert.NotEqual(t, "0", respW.HeaderMap.Get("X-Nomad-Index")) }) } @@ -145,15 +152,14 @@ func TestHTTP_ResoucesList_Evaluation(t *testing.T) { state := s.Agent.server.State() eval1 := mock.Eval() eval2 := mock.Eval() - err := state.UpsertEvals(1000, + err := state.UpsertEvals(9000, []*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"} + prefix := eval1.ID[:len(eval1.ID)-2] + data := structs.ResourcesRequest{Prefix: prefix, Context: "evals"} req, err := http.NewRequest("POST", "/v1/resources", encodeReq(data)) if err != nil { t.Fatalf("err: %v", err) @@ -169,19 +175,20 @@ func TestHTTP_ResoucesList_Evaluation(t *testing.T) { assert.Equal(t, 1, len(res.Matches)) - j := res.Matches["eval"] - + j := res.Matches["evals"] assert.Equal(t, 1, len(j)) assert.Contains(t, j, eval1.ID) assert.NotContains(t, j, eval2.ID) - assert.Equal(t, res.Truncations["eval"], false) + + assert.Equal(t, res.Truncations["evals"], false) + assert.Equal(t, "9000", respW.HeaderMap.Get("X-Nomad-Index")) }) } func TestHTTP_Resources_NoJob(t *testing.T) { t.Parallel() httpTest(t, nil, func(s *TestAgent) { - data := structs.ResourcesRequest{Prefix: "12345", Context: "job"} + data := structs.ResourcesRequest{Prefix: "12345", Context: "jobs"} req, err := http.NewRequest("POST", "/v1/resources", encodeReq(data)) if err != nil { @@ -198,6 +205,8 @@ func TestHTTP_Resources_NoJob(t *testing.T) { assert.Equal(t, 1, len(res.Matches)) assert.Equal(t, 0, len(res.Matches["jobs"])) + + assert.Equal(t, "0", respW.HeaderMap.Get("X-Nomad-Index")) }) } @@ -211,7 +220,7 @@ func TestHTTP_Resources_NoContext(t *testing.T) { state := s.Agent.server.State() eval1 := mock.Eval() eval1.ID = testJobID - err := state.UpsertEvals(1000, + err := state.UpsertEvals(9000, []*structs.Evaluation{eval1}) if err != nil { t.Fatalf("err: %v", err) @@ -232,8 +241,8 @@ func TestHTTP_Resources_NoContext(t *testing.T) { res := resp.(structs.ResourcesResponse) - matchedJobs := res.Matches["job"] - matchedEvals := res.Matches["eval"] + matchedJobs := res.Matches["jobs"] + matchedEvals := res.Matches["evals"] assert.Equal(t, 1, len(matchedJobs)) assert.Equal(t, 1, len(matchedEvals)) diff --git a/nomad/resources_endpoint.go b/nomad/resources_endpoint.go index f0c165d87..cdf7f3757 100644 --- a/nomad/resources_endpoint.go +++ b/nomad/resources_endpoint.go @@ -39,7 +39,7 @@ func getMatches(iter memdb.ResultIterator) ([]string, bool) { case *structs.Node: return i.(*structs.Node).ID, nil default: - return "", fmt.Errorf("invalid context") + return "", fmt.Errorf("invalid type") } } @@ -62,13 +62,13 @@ func getMatches(iter memdb.ResultIterator) ([]string, bool) { // that context func getResourceIter(context, prefix string, ws memdb.WatchSet, state *state.StateStore) (memdb.ResultIterator, error) { switch context { - case "job": + case "jobs": return state.JobsByIDPrefix(ws, prefix) - case "eval": + case "evals": return state.EvalsByIDPrefix(ws, prefix) - case "alloc": + case "allocs": return state.AllocsByIDPrefix(ws, prefix) - case "node": + case "nodes": return state.NodesByIDPrefix(ws, prefix) default: return nil, fmt.Errorf("invalid context") @@ -97,7 +97,7 @@ func (r *Resources) List(args *structs.ResourcesRequest, } iters[args.Context] = iter } else { - for _, e := range []string{"alloc", "node", "job", "eval"} { + for _, e := range []string{"allocs", "nodes", "jobs", "evals"} { iter, err := getResourceIter(e, args.Prefix, ws, state) if err != nil { return err @@ -106,7 +106,7 @@ func (r *Resources) List(args *structs.ResourcesRequest, } } - // Return jobs matching given prefix + // Return matches for the given prefix for k, v := range iters { res, isTrunc := getMatches(v) reply.Matches[k] = res @@ -123,6 +123,7 @@ func (r *Resources) List(args *structs.ResourcesRequest, for k, v := range reply.Matches { if len(v) != 0 { index, err = state.Index(k) + break } } } diff --git a/nomad/resources_endpoint_test.go b/nomad/resources_endpoint_test.go index 4b1e75343..a6774379b 100644 --- a/nomad/resources_endpoint_test.go +++ b/nomad/resources_endpoint_test.go @@ -10,12 +10,14 @@ import ( "testing" ) +const jobIndex = 1000 + func registerAndVerifyJob(s *Server, t *testing.T, prefix string, counter int) string { job := mock.Job() job.ID = prefix + strconv.Itoa(counter) state := s.fsm.State() - err := state.UpsertJob(1000, job) + err := state.UpsertJob(jobIndex, job) if err != nil { t.Fatalf("err: %v", err) } @@ -39,7 +41,7 @@ func TestResourcesEndpoint_List(t *testing.T) { req := &structs.ResourcesRequest{ Prefix: prefix, - Context: "job", + Context: "jobs", } var resp structs.ResourcesResponse @@ -47,9 +49,9 @@ func TestResourcesEndpoint_List(t *testing.T) { t.Fatalf("err: %v", err) } - assert.Equal(t, 1, len(resp.Matches["job"])) - assert.Equal(t, jobID, resp.Matches["job"][0]) - assert.NotEqual(t, 0, resp.Index) + assert.Equal(t, 1, len(resp.Matches["jobs"])) + assert.Equal(t, jobID, resp.Matches["jobs"][0]) + assert.Equal(t, uint64(jobIndex), resp.Index) } // truncate should limit results to 20 @@ -71,7 +73,7 @@ func TestResourcesEndpoint_List_Truncate(t *testing.T) { req := &structs.ResourcesRequest{ Prefix: prefix, - Context: "job", + Context: "jobs", } var resp structs.ResourcesResponse @@ -79,9 +81,9 @@ func TestResourcesEndpoint_List_Truncate(t *testing.T) { t.Fatalf("err: %v", err) } - assert.Equal(t, 20, len(resp.Matches["job"])) - assert.Equal(t, resp.Truncations["job"], true) - assert.NotEqual(t, 0, resp.Index) + assert.Equal(t, 20, len(resp.Matches["jobs"])) + assert.Equal(t, resp.Truncations["jobs"], true) + assert.Equal(t, uint64(jobIndex), resp.Index) } func TestResourcesEndpoint_List_Evals(t *testing.T) { @@ -95,13 +97,13 @@ func TestResourcesEndpoint_List_Evals(t *testing.T) { testutil.WaitForLeader(t, s.RPC) eval1 := mock.Eval() - s.fsm.State().UpsertEvals(1000, []*structs.Evaluation{eval1}) + s.fsm.State().UpsertEvals(2000, []*structs.Evaluation{eval1}) prefix := eval1.ID[:len(eval1.ID)-2] req := &structs.ResourcesRequest{ Prefix: prefix, - Context: "eval", + Context: "evals", } var resp structs.ResourcesResponse @@ -109,11 +111,11 @@ func TestResourcesEndpoint_List_Evals(t *testing.T) { t.Fatalf("err: %v", err) } - assert.Equal(t, 1, len(resp.Matches["eval"])) - assert.Equal(t, eval1.ID, resp.Matches["eval"][0]) - assert.Equal(t, resp.Truncations["job"], false) + assert.Equal(t, 1, len(resp.Matches["evals"])) + assert.Equal(t, eval1.ID, resp.Matches["evals"][0]) + assert.Equal(t, resp.Truncations["evals"], false) - assert.NotEqual(t, 0, resp.Index) + assert.Equal(t, uint64(2000), resp.Index) } func TestResourcesEndpoint_List_Allocation(t *testing.T) { @@ -133,7 +135,7 @@ func TestResourcesEndpoint_List_Allocation(t *testing.T) { if err := state.UpsertJobSummary(999, summary); err != nil { t.Fatalf("err: %v", err) } - if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { + if err := state.UpsertAllocs(90, []*structs.Allocation{alloc}); err != nil { t.Fatalf("err: %v", err) } @@ -141,7 +143,7 @@ func TestResourcesEndpoint_List_Allocation(t *testing.T) { req := &structs.ResourcesRequest{ Prefix: prefix, - Context: "alloc", + Context: "allocs", } var resp structs.ResourcesResponse @@ -149,11 +151,11 @@ func TestResourcesEndpoint_List_Allocation(t *testing.T) { t.Fatalf("err: %v", err) } - assert.Equal(t, 1, len(resp.Matches["alloc"])) - assert.Equal(t, alloc.ID, resp.Matches["alloc"][0]) - assert.Equal(t, resp.Truncations["alloc"], false) + assert.Equal(t, 1, len(resp.Matches["allocs"])) + assert.Equal(t, alloc.ID, resp.Matches["allocs"][0]) + assert.Equal(t, resp.Truncations["allocs"], false) - assert.NotEqual(t, 0, resp.Index) + assert.Equal(t, uint64(90), resp.Index) } func TestResourcesEndpoint_List_Node(t *testing.T) { @@ -177,7 +179,7 @@ func TestResourcesEndpoint_List_Node(t *testing.T) { req := &structs.ResourcesRequest{ Prefix: prefix, - Context: "node", + Context: "nodes", } var resp structs.ResourcesResponse @@ -185,9 +187,11 @@ func TestResourcesEndpoint_List_Node(t *testing.T) { t.Fatalf("err: %v", err) } - assert.Equal(t, 1, len(resp.Matches["node"])) - assert.Equal(t, node.ID, resp.Matches["node"][0]) - assert.Equal(t, resp.Truncations["node"], false) + assert.Equal(t, 1, len(resp.Matches["nodes"])) + assert.Equal(t, node.ID, resp.Matches["nodes"][0]) + assert.Equal(t, false, resp.Truncations["nodes"]) + + assert.Equal(t, uint64(100), resp.Index) } func TestResourcesEndpoint_List_InvalidContext(t *testing.T) { @@ -209,7 +213,7 @@ func TestResourcesEndpoint_List_InvalidContext(t *testing.T) { err := msgpackrpc.CallWithCodec(codec, "Resources.List", req, &resp) assert.Equal(t, err.Error(), "invalid context") - assert.NotEqual(t, 0, resp.Index) + assert.Equal(t, uint64(0), resp.Index) } func TestResourcesEndpoint_List_NoContext(t *testing.T) { @@ -247,13 +251,13 @@ func TestResourcesEndpoint_List_NoContext(t *testing.T) { t.Fatalf("err: %v", err) } - assert.Equal(t, 1, len(resp.Matches["node"])) - assert.Equal(t, 1, len(resp.Matches["eval"])) + assert.Equal(t, 1, len(resp.Matches["nodes"])) + assert.Equal(t, 1, len(resp.Matches["evals"])) - assert.Equal(t, node.ID, resp.Matches["node"][0]) - assert.Equal(t, eval1.ID, resp.Matches["eval"][0]) + assert.Equal(t, node.ID, resp.Matches["nodes"][0]) + assert.Equal(t, eval1.ID, resp.Matches["evals"][0]) - assert.NotEqual(t, 0, resp.Index) + assert.NotEqual(t, uint64(0), resp.Index) } // Tests that the top 20 matches are returned when no prefix is set @@ -273,7 +277,7 @@ func TestResourcesEndpoint_List_NoPrefix(t *testing.T) { req := &structs.ResourcesRequest{ Prefix: "", - Context: "job", + Context: "jobs", } var resp structs.ResourcesResponse @@ -281,9 +285,9 @@ func TestResourcesEndpoint_List_NoPrefix(t *testing.T) { t.Fatalf("err: %v", err) } - assert.Equal(t, 1, len(resp.Matches["job"])) - assert.Equal(t, jobID, resp.Matches["job"][0]) - assert.NotEqual(t, 0, resp.Index) + assert.Equal(t, 1, len(resp.Matches["jobs"])) + assert.Equal(t, jobID, resp.Matches["jobs"][0]) + assert.Equal(t, uint64(jobIndex), resp.Index) } // Tests that the zero matches are returned when a prefix has no matching @@ -302,7 +306,7 @@ func TestResourcesEndpoint_List_NoMatches(t *testing.T) { req := &structs.ResourcesRequest{ Prefix: prefix, - Context: "job", + Context: "jobs", } var resp structs.ResourcesResponse @@ -310,6 +314,6 @@ func TestResourcesEndpoint_List_NoMatches(t *testing.T) { t.Fatalf("err: %v", err) } - assert.Equal(t, 0, len(resp.Matches["job"])) + assert.Equal(t, 0, len(resp.Matches["jobs"])) assert.Equal(t, uint64(0), resp.Index) }