Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nomad eval list command #11675

Merged
merged 8 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/11675.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
cli: Added a `nomad eval list` command.
```
5 changes: 5 additions & 0 deletions command/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ func Commands(metaPtr *Meta, agentUi cli.Ui) map[string]cli.CommandFactory {
Meta: meta,
}, nil
},
"eval list": func() (cli.Command, error) {
return &EvalListCommand{
Meta: meta,
}, nil
},
"eval status": func() (cli.Command, error) {
return &EvalStatusCommand{
Meta: meta,
Expand Down
213 changes: 213 additions & 0 deletions command/eval_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package command

import (
"fmt"
"os"
"strings"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/api/contexts"
"github.com/posener/complete"
)

type EvalListCommand struct {
Meta
}

func (c *EvalListCommand) Help() string {
helpText := `
Usage: nomad eval list [options]

List is used to list the set of evaluations processed by Nomad.

General Options:

` + generalOptionsUsage(usageOptsDefault) + `

Eval List Options:

-verbose
Show full information.

-per-page
How many results to show per page.

-page-token
Where to start pagination.

-job
Only show evaluations for this job ID.

-status
Only show evaluations with this status.

-json
Output the evaluation in its JSON format.

-t
Format and display evaluation using a Go template.
`

return strings.TrimSpace(helpText)
}

func (c *EvalListCommand) Synopsis() string {
return "List the set of evaluations processed by Nomad"
}

func (c *EvalListCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
"-json": complete.PredictNothing,
"-t": complete.PredictAnything,
"-verbose": complete.PredictNothing,
"-job": complete.PredictAnything,
"-status": complete.PredictAnything,
"-per-page": complete.PredictAnything,
"-page-token": complete.PredictAnything,
})
}

func (c *EvalListCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictFunc(func(a complete.Args) []string {
client, err := c.Meta.Client()
if err != nil {
return nil
}

resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Evals, nil)
if err != nil {
return []string{}
}
return resp.Matches[contexts.Evals]
})
}

func (c *EvalListCommand) Name() string { return "eval list" }

func (c *EvalListCommand) Run(args []string) int {
var monitor, verbose, json bool
var perPage int
var tmpl, pageToken, filterJobID, filterStatus string

flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.BoolVar(&monitor, "monitor", false, "")
flags.BoolVar(&verbose, "verbose", false, "")
flags.BoolVar(&json, "json", false, "")
flags.StringVar(&tmpl, "t", "", "")
flags.IntVar(&perPage, "per-page", 0, "")
flags.StringVar(&pageToken, "page-token", "", "")
flags.StringVar(&filterJobID, "job", "", "")
flags.StringVar(&filterStatus, "status", "", "")

if err := flags.Parse(args); err != nil {
return 1
}

tgross marked this conversation as resolved.
Show resolved Hide resolved
// Check that we got no arguments
args = flags.Args()
if l := len(args); l != 0 {
c.Ui.Error("This command takes no arguments")
c.Ui.Error(commandErrorText(c))
return 1
}

client, err := c.Meta.Client()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
return 1
}

opts := &api.QueryOptions{
PerPage: int32(perPage),
NextToken: pageToken,
Params: map[string]string{},
}
if filterJobID != "" {
opts.Params["job"] = filterJobID
}
if filterStatus != "" {
opts.Params["status"] = filterStatus
}

evals, qm, err := client.Evaluations().List(opts)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error querying evaluations: %v", err))
return 1
}

// If args not specified but output format is specified, format
// and output the evaluations data list
if json || len(tmpl) > 0 {
out, err := Format(json, tmpl, evals)
if err != nil {
c.Ui.Error(err.Error())
return 1
}

c.Ui.Output(out)
return 0
}

if len(evals) == 0 {
c.Ui.Output("No evals found")
return 0
}

// Truncate the id unless full length is requested
length := shortId
if verbose {
length = fullId
}

out := make([]string, len(evals)+1)
out[0] = "ID|Priority|Triggered By|Job ID|Status|Placement Failures"
for i, eval := range evals {
failures, _ := evalFailureStatus(eval)
out[i+1] = fmt.Sprintf("%s|%d|%s|%s|%s|%s",
limit(eval.ID, length),
eval.Priority,
eval.TriggeredBy,
eval.JobID,
eval.Status,
failures,
)
}
c.Ui.Output(formatList(out))

if qm.NextToken != "" {
c.Ui.Output(fmt.Sprintf(`
Results have been paginated. To get the next page run:

%s -page-token %s`, argsWithoutPageToken(os.Args), qm.NextToken))
}

return 0
}

// argsWithoutPageToken strips out of the -page-token argument and
// returns the joined string
func argsWithoutPageToken(osArgs []string) string {
args := []string{}
i := 0
for {
if i >= len(osArgs) {
break
}
arg := osArgs[i]

if strings.HasPrefix(arg, "-page-token") {
if strings.Contains(arg, "=") {
i += 1
} else {
i += 2
}
continue
}

args = append(args, arg)
i++
}
return strings.Join(args, " ")
}
60 changes: 60 additions & 0 deletions command/eval_list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package command

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestEvalList_ArgsWithoutPageToken(t *testing.T) {

cases := []struct {
cli string
expected string
}{
{
cli: "nomad eval list -page-token=abcdef",
expected: "nomad eval list",
},
{
cli: "nomad eval list -page-token abcdef",
expected: "nomad eval list",
},
{
cli: "nomad eval list -per-page 3 -page-token abcdef",
expected: "nomad eval list -per-page 3",
},
{
cli: "nomad eval list -page-token abcdef -per-page 3",
expected: "nomad eval list -per-page 3",
},
{
cli: "nomad eval list -per-page=3 -page-token abcdef",
expected: "nomad eval list -per-page=3",
},
{
cli: "nomad eval list -verbose -page-token abcdef",
expected: "nomad eval list -verbose",
},
{
cli: "nomad eval list -page-token abcdef -verbose",
expected: "nomad eval list -verbose",
},
{
cli: "nomad eval list -verbose -page-token abcdef -per-page 3",
expected: "nomad eval list -verbose -per-page 3",
},
{
cli: "nomad eval list -page-token abcdef -verbose -per-page 3",
expected: "nomad eval list -verbose -per-page 3",
},
}

for _, tc := range cases {
args := strings.Split(tc.cli, " ")
assert.Equal(t, tc.expected, argsWithoutPageToken(args),
"for input: %s", tc.cli)
}

}
23 changes: 23 additions & 0 deletions website/content/docs/commands/eval/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
layout: docs
page_title: 'Commands: eval'
description: |
The eval command is used to interact with evals.
---

# Command: eval

The `eval` command is used to interact with evals.

## Usage

Usage: `nomad eval <subcommand> [options]`

Run `nomad eval <subcommand> -h` for help on that subcommand. The following
subcommands are available:

- [`eval list`][list] - List all evals
- [`eval status`][status] - Display the status of a eval

[list]: /docs/commands/eval/list 'List all evals'
[status]: /docs/commands/eval/status 'Display the status of a eval'
51 changes: 51 additions & 0 deletions website/content/docs/commands/eval/list.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
layout: docs
page_title: 'Commands: eval list'
description: |
The eval list command is used to list evaluations.
---

# Command: eval list

The `eval list` command is used list all evaluations.

## Usage

```plaintext
nomad eval list [options]
```

The `eval list` command requires no arguments.

When ACLs are enabled, this command requires a token with the `read-job`
capability for the requested namespace.

## General Options

@include 'general_options.mdx'

## List Options

- `-verbose`: Show full information.
- `-per-page`: How many results to show per page.
- `-page-token`: Where to start pagination.
- `-job`: Only show evaluations for this job ID.
- `-status`: Only show evaluations with this status.
- `-json`: Output the evaluation in its JSON format.
- `-t`: Format and display evaluation using a Go template.

## Examples

List all tracked evaluations:

```shell-session
$ nomad eval list -per-page 3 -status complete
ID Priority Triggered By Job ID Status Placement Failures
456e37aa 50 deployment-watcher example complete false
1a1eafe6 50 alloc-stop example complete false
3411e37b 50 job-register example complete false

Results have been paginated. To get the next page run:

nomad eval list -page-token 9ecffbba-73be-d909-5d7e-ac2694c10e0c
```
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ indicated by exit code 1.

- `-monitor`: Monitor an outstanding evaluation
- `-verbose`: Show full information.
- `-json` : Output the evaluation in its JSON format.
- `-json` : Output a list of all evaluations in JSON format. This
behavior is deprecated and has been replaced by `nomad eval list
-json`. In Nomad 1.4.0 the behavior of this option will change to
output only the selected evaluation in JSON.
- `-t` : Format and display evaluation using a Go template.

## Examples
Expand Down
10 changes: 10 additions & 0 deletions website/content/docs/upgrade/upgrade-specific.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ upgrade. However, specific versions of Nomad may have more details provided for
their upgrades as a result of new features or changed behavior. This page is
used to document those details separately from the standard upgrade flow.

## Nomad 1.2.4

#### `nomad eval status -json` deprecated

Nomad 1.2.4 includes a new `nomad eval list` command that has the
option to display the results in JSON format with the `-json`
flag. This replaces the existing `nomad eval status -json` option. In
Nomad 1.4.0, `nomad eval status -json` will be changed to display only
the selected evaluation in JSON format.

## Nomad 1.2.2

### Panic on node class filtering for system and sysbatch jobs fixed
Expand Down
Loading