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