diff --git a/api/evaluations.go b/api/evaluations.go index 8cc42cb853ba..5741ca2736b2 100644 --- a/api/evaluations.go +++ b/api/evaluations.go @@ -26,6 +26,16 @@ func (e *Evaluations) List(q *QueryOptions) ([]*Evaluation, *QueryMeta, error) { return resp, qm, nil } +// Count is used to get a count of evaluations. +func (e *Evaluations) Count(q *QueryOptions) (int, *QueryMeta, error) { + var resp map[string]int + qm, err := e.client.query("/v1/evaluations?count=true", &resp, q) + if err != nil { + return 0, nil, err + } + return resp["Count"], qm, nil +} + func (e *Evaluations) PrefixList(prefix string) ([]*Evaluation, *QueryMeta, error) { return e.List(&QueryOptions{Prefix: prefix}) } diff --git a/command/agent/eval_endpoint.go b/command/agent/eval_endpoint.go index 619b84daa360..bf0d16317187 100644 --- a/command/agent/eval_endpoint.go +++ b/command/agent/eval_endpoint.go @@ -34,6 +34,14 @@ func (s *HTTPServer) evalsListRequest(resp http.ResponseWriter, req *http.Reques args.FilterEvalStatus = query.Get("status") args.FilterJobID = query.Get("job") + countOnly, err := parseBool(req, "count") + if err != nil { + return nil, err + } + if countOnly != nil { + args.CountOnly = *countOnly + } + var out structs.EvalListResponse if err := s.agent.RPC("Eval.List", &args, &out); err != nil { return nil, err @@ -43,6 +51,11 @@ func (s *HTTPServer) evalsListRequest(resp http.ResponseWriter, req *http.Reques if out.Evaluations == nil { out.Evaluations = make([]*structs.Evaluation, 0) } + + if args.CountOnly { + return map[string]int{"Count": out.Count}, nil + } + return out.Evaluations, nil } diff --git a/command/eval_delete.go b/command/eval_delete.go index f8d1da7bcf69..0915e8fe03d0 100644 --- a/command/eval_delete.go +++ b/command/eval_delete.go @@ -294,28 +294,26 @@ func correctGrammar(word string, num int) string { func (e *EvalDeleteCommand) handleDeleteByFilter(filterExpr string) (int, error) { - // TODO: querying for millions of evals is very expensive... can we add a count RPC? - - // evals, _, err := e.client.Evaluations().List(&api.QueryOptions{ - // Filter: filterExpr, - // }) - // if err != nil { - // return 1, err - // } - // evals := []string{} - // If the user did not wish to bypass the confirmation step, ask this now // and handle the response. - // if !e.yes && !e.deleteByArg { - // code, deleteEvals := e.askQuestion(fmt.Sprintf( - // "Are you sure you want to delete %v evals? [y/N]", - // len(evals)), "Cancelling eval deletion") - // e.Ui.Output("") - - // if !deleteEvals { - // return code, nil - // } - // } + if !e.yes && !e.deleteByArg { + + count, _, err := e.client.Evaluations().Count(&api.QueryOptions{ + Filter: filterExpr, + }) + if err != nil { + return 1, err + } + + code, deleteEvals := e.askQuestion(fmt.Sprintf( + "Are you sure you want to delete %d evals? [y/N]", + count), "Cancelling eval deletion") + e.Ui.Output("") + + if !deleteEvals { + return code, nil + } + } resp, _, err := e.client.Evaluations().DeleteOpts(&api.EvalDeleteRequest{ Filter: filterExpr, diff --git a/nomad/eval_endpoint.go b/nomad/eval_endpoint.go index 4e9c76560565..5f4280637e36 100644 --- a/nomad/eval_endpoint.go +++ b/nomad/eval_endpoint.go @@ -687,10 +687,14 @@ func (e *Eval) List(args *structs.EvalListRequest, reply *structs.EvalListRespon } var evals []*structs.Evaluation + count := 0 paginator, err := paginator.NewPaginator(iter, tokenizer, filters, args.QueryOptions, func(raw interface{}) error { - eval := raw.(*structs.Evaluation) - evals = append(evals, eval) + if !args.CountOnly { + eval := raw.(*structs.Evaluation) + evals = append(evals, eval) + } + count++ return nil }) if err != nil { @@ -706,6 +710,7 @@ func (e *Eval) List(args *structs.EvalListRequest, reply *structs.EvalListRespon reply.QueryMeta.NextToken = nextToken reply.Evaluations = evals + reply.Count = count } // Use the last index that affected the jobs table diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index badff0418f6b..14acb28d9e8d 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -890,6 +890,7 @@ type EvalDequeueRequest struct { type EvalListRequest struct { FilterJobID string FilterEvalStatus string + CountOnly bool QueryOptions } @@ -1602,6 +1603,7 @@ type DeploymentListResponse struct { // EvalListResponse is used for a list request type EvalListResponse struct { Evaluations []*Evaluation + Count int QueryMeta }