github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/command/eval_list.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 8 "github.com/hashicorp/nomad/api" 9 "github.com/hashicorp/nomad/api/contexts" 10 "github.com/posener/complete" 11 ) 12 13 type EvalListCommand struct { 14 Meta 15 } 16 17 func (c *EvalListCommand) Help() string { 18 helpText := ` 19 Usage: nomad eval list [options] 20 21 List is used to list the set of evaluations processed by Nomad. 22 23 General Options: 24 25 ` + generalOptionsUsage(usageOptsDefault) + ` 26 27 Eval List Options: 28 29 -verbose 30 Show full information. 31 32 -per-page 33 How many results to show per page. 34 35 -page-token 36 Where to start pagination. 37 38 -filter 39 Specifies an expression used to filter query results. 40 41 -job 42 Only show evaluations for this job ID. 43 44 -status 45 Only show evaluations with this status. 46 47 -json 48 Output the evaluation in its JSON format. 49 50 -t 51 Format and display evaluation using a Go template. 52 ` 53 54 return strings.TrimSpace(helpText) 55 } 56 57 func (c *EvalListCommand) Synopsis() string { 58 return "List the set of evaluations processed by Nomad" 59 } 60 61 func (c *EvalListCommand) AutocompleteFlags() complete.Flags { 62 return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), 63 complete.Flags{ 64 "-json": complete.PredictNothing, 65 "-t": complete.PredictAnything, 66 "-verbose": complete.PredictNothing, 67 "-filter": complete.PredictAnything, 68 "-job": complete.PredictAnything, 69 "-status": complete.PredictAnything, 70 "-per-page": complete.PredictAnything, 71 "-page-token": complete.PredictAnything, 72 }) 73 } 74 75 func (c *EvalListCommand) AutocompleteArgs() complete.Predictor { 76 return complete.PredictFunc(func(a complete.Args) []string { 77 client, err := c.Meta.Client() 78 if err != nil { 79 return nil 80 } 81 82 resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Evals, nil) 83 if err != nil { 84 return []string{} 85 } 86 return resp.Matches[contexts.Evals] 87 }) 88 } 89 90 func (c *EvalListCommand) Name() string { return "eval list" } 91 92 func (c *EvalListCommand) Run(args []string) int { 93 var monitor, verbose, json bool 94 var perPage int 95 var tmpl, pageToken, filter, filterJobID, filterStatus string 96 97 flags := c.Meta.FlagSet(c.Name(), FlagSetClient) 98 flags.Usage = func() { c.Ui.Output(c.Help()) } 99 flags.BoolVar(&monitor, "monitor", false, "") 100 flags.BoolVar(&verbose, "verbose", false, "") 101 flags.BoolVar(&json, "json", false, "") 102 flags.StringVar(&tmpl, "t", "", "") 103 flags.IntVar(&perPage, "per-page", 0, "") 104 flags.StringVar(&pageToken, "page-token", "", "") 105 flags.StringVar(&filter, "filter", "", "") 106 flags.StringVar(&filterJobID, "job", "", "") 107 flags.StringVar(&filterStatus, "status", "", "") 108 109 if err := flags.Parse(args); err != nil { 110 return 1 111 } 112 113 // Check that we got no arguments 114 args = flags.Args() 115 if l := len(args); l != 0 { 116 c.Ui.Error("This command takes no arguments") 117 c.Ui.Error(commandErrorText(c)) 118 return 1 119 } 120 121 client, err := c.Meta.Client() 122 if err != nil { 123 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 124 return 1 125 } 126 127 opts := &api.QueryOptions{ 128 Filter: filter, 129 PerPage: int32(perPage), 130 NextToken: pageToken, 131 Params: map[string]string{}, 132 } 133 if filterJobID != "" { 134 opts.Params["job"] = filterJobID 135 } 136 if filterStatus != "" { 137 opts.Params["status"] = filterStatus 138 } 139 140 evals, qm, err := client.Evaluations().List(opts) 141 if err != nil { 142 c.Ui.Error(fmt.Sprintf("Error querying evaluations: %v", err)) 143 return 1 144 } 145 146 // If args not specified but output format is specified, format 147 // and output the evaluations data list 148 if json || len(tmpl) > 0 { 149 out, err := Format(json, tmpl, evals) 150 if err != nil { 151 c.Ui.Error(err.Error()) 152 return 1 153 } 154 155 c.Ui.Output(out) 156 return 0 157 } 158 159 if len(evals) == 0 { 160 c.Ui.Output("No evals found") 161 return 0 162 } 163 164 c.Ui.Output(formatEvalList(evals, verbose)) 165 166 if qm.NextToken != "" { 167 c.Ui.Output(fmt.Sprintf(` 168 Results have been paginated. To get the next page run: 169 170 %s -page-token %s`, argsWithoutPageToken(os.Args), qm.NextToken)) 171 } 172 173 return 0 174 } 175 176 // argsWithoutPageToken strips out of the -page-token argument and 177 // returns the joined string 178 func argsWithoutPageToken(osArgs []string) string { 179 args := []string{} 180 i := 0 181 for { 182 if i >= len(osArgs) { 183 break 184 } 185 arg := osArgs[i] 186 187 if strings.HasPrefix(arg, "-page-token") { 188 if strings.Contains(arg, "=") { 189 i += 1 190 } else { 191 i += 2 192 } 193 continue 194 } 195 196 args = append(args, arg) 197 i++ 198 } 199 return strings.Join(args, " ") 200 } 201 202 func formatEvalList(evals []*api.Evaluation, verbose bool) string { 203 // Truncate IDs unless full length is requested 204 length := shortId 205 if verbose { 206 length = fullId 207 } 208 209 out := make([]string, len(evals)+1) 210 out[0] = "ID|Priority|Triggered By|Job ID|Namespace|Node ID|Status|Placement Failures" 211 for i, eval := range evals { 212 failures, _ := evalFailureStatus(eval) 213 out[i+1] = fmt.Sprintf("%s|%d|%s|%s|%s|%s|%s|%s", 214 limit(eval.ID, length), 215 eval.Priority, 216 eval.TriggeredBy, 217 eval.JobID, 218 eval.Namespace, 219 limit(eval.NodeID, length), 220 eval.Status, 221 failures, 222 ) 223 } 224 225 return formatList(out) 226 }