github.com/hernad/nomad@v1.6.112/command/job_inspect.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package command 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/hernad/nomad/api" 11 "github.com/hernad/nomad/api/contexts" 12 "github.com/posener/complete" 13 ) 14 15 type JobInspectCommand struct { 16 Meta 17 } 18 19 func (c *JobInspectCommand) Help() string { 20 helpText := ` 21 Usage: nomad job inspect [options] <job> 22 Alias: nomad inspect 23 24 Inspect is used to see the specification of a submitted job. 25 26 When ACLs are enabled, this command requires a token with the 'read-job' 27 capability for the job's namespace. The 'list-jobs' capability is required to 28 run the command with a job prefix instead of the exact job ID. 29 30 General Options: 31 32 ` + generalOptionsUsage(usageOptsDefault) + ` 33 34 Inspect Options: 35 36 -version <job version> 37 Display the job at the given job version. 38 39 -json 40 Output the job in its JSON format. 41 42 -t 43 Format and display job using a Go template. 44 ` 45 return strings.TrimSpace(helpText) 46 } 47 48 func (c *JobInspectCommand) Synopsis() string { 49 return "Inspect a submitted job" 50 } 51 52 func (c *JobInspectCommand) AutocompleteFlags() complete.Flags { 53 return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), 54 complete.Flags{ 55 "-version": complete.PredictAnything, 56 "-json": complete.PredictNothing, 57 "-t": complete.PredictAnything, 58 }) 59 } 60 61 func (c *JobInspectCommand) AutocompleteArgs() complete.Predictor { 62 return complete.PredictFunc(func(a complete.Args) []string { 63 client, err := c.Meta.Client() 64 if err != nil { 65 return nil 66 } 67 68 resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) 69 if err != nil { 70 return []string{} 71 } 72 return resp.Matches[contexts.Jobs] 73 }) 74 } 75 76 func (c *JobInspectCommand) Name() string { return "job inspect" } 77 78 func (c *JobInspectCommand) Run(args []string) int { 79 var json bool 80 var tmpl, versionStr string 81 82 flags := c.Meta.FlagSet(c.Name(), FlagSetClient) 83 flags.Usage = func() { c.Ui.Output(c.Help()) } 84 flags.BoolVar(&json, "json", false, "") 85 flags.StringVar(&tmpl, "t", "", "") 86 flags.StringVar(&versionStr, "version", "", "") 87 88 if err := flags.Parse(args); err != nil { 89 return 1 90 } 91 args = flags.Args() 92 93 // Get the HTTP client 94 client, err := c.Meta.Client() 95 if err != nil { 96 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 97 return 1 98 } 99 100 // If args not specified but output format is specified, format and output the jobs data list 101 if len(args) == 0 && (json || len(tmpl) > 0) { 102 jobs, _, err := client.Jobs().List(nil) 103 if err != nil { 104 c.Ui.Error(fmt.Sprintf("Error querying jobs: %v", err)) 105 return 1 106 } 107 108 out, err := Format(json, tmpl, jobs) 109 if err != nil { 110 c.Ui.Error(err.Error()) 111 return 1 112 } 113 114 c.Ui.Output(out) 115 return 0 116 } 117 118 // Check that we got exactly one job 119 if len(args) != 1 { 120 c.Ui.Error("This command takes one argument: <job>") 121 c.Ui.Error(commandErrorText(c)) 122 return 1 123 } 124 125 // Check if the job exists 126 jobIDPrefix := strings.TrimSpace(args[0]) 127 jobID, namespace, err := c.JobIDByPrefix(client, jobIDPrefix, nil) 128 if err != nil { 129 c.Ui.Error(err.Error()) 130 return 1 131 } 132 133 var version *uint64 134 if versionStr != "" { 135 v, _, err := parseVersion(versionStr) 136 if err != nil { 137 c.Ui.Error(fmt.Sprintf("Error parsing version value %q: %v", versionStr, err)) 138 return 1 139 } 140 141 version = &v 142 } 143 144 // Prefix lookup matched a single job 145 job, err := getJob(client, namespace, jobID, version) 146 if err != nil { 147 c.Ui.Error(fmt.Sprintf("Error inspecting job: %s", err)) 148 return 1 149 } 150 151 // If output format is specified, format and output the data 152 if json || len(tmpl) > 0 { 153 out, err := Format(json, tmpl, job) 154 if err != nil { 155 c.Ui.Error(err.Error()) 156 return 1 157 } 158 159 c.Ui.Output(out) 160 return 0 161 } 162 163 // Print the contents of the job 164 req := struct { 165 Job *api.Job 166 }{ 167 Job: job, 168 } 169 f, err := DataFormat("json", "") 170 if err != nil { 171 c.Ui.Error(fmt.Sprintf("Error getting formatter: %s", err)) 172 return 1 173 } 174 175 out, err := f.TransformData(req) 176 if err != nil { 177 c.Ui.Error(fmt.Sprintf("Error formatting the data: %s", err)) 178 return 1 179 } 180 c.Ui.Output(out) 181 return 0 182 } 183 184 // getJob retrieves the job optionally at a particular version. 185 func getJob(client *api.Client, namespace, jobID string, version *uint64) (*api.Job, error) { 186 var q *api.QueryOptions 187 if namespace != "" { 188 q = &api.QueryOptions{Namespace: namespace} 189 } 190 if version == nil { 191 job, _, err := client.Jobs().Info(jobID, q) 192 return job, err 193 } 194 195 versions, _, _, err := client.Jobs().Versions(jobID, false, q) 196 if err != nil { 197 return nil, err 198 } 199 200 for _, j := range versions { 201 if *j.Version != *version { 202 continue 203 } 204 return j, nil 205 } 206 207 return nil, fmt.Errorf("job %q with version %d couldn't be found", jobID, *version) 208 }