diff --git a/.changelog/18925.txt b/.changelog/18925.txt new file mode 100644 index 000000000..ee29d77eb --- /dev/null +++ b/.changelog/18925.txt @@ -0,0 +1,3 @@ +```release-note:improvement +cli: Added -json option on job status command +``` diff --git a/command/job_status.go b/command/job_status.go index e897bc1ab..4de0d6e19 100644 --- a/command/job_status.go +++ b/command/job_status.go @@ -26,6 +26,21 @@ type JobStatusCommand struct { evals bool allAllocs bool verbose bool + json bool + tmpl string +} + +// NamespacedID is a tuple of an ID and a namespace +type NamespacedID struct { + ID string + Namespace string +} + +type JobJson struct { + Summary *api.JobSummary + Allocations []*api.AllocationListStub + LatestDeployment *api.Deployment + Evaluations []*api.Evaluation } func (c *JobStatusCommand) Help() string { @@ -101,6 +116,8 @@ func (c *JobStatusCommand) Run(args []string) int { flags.BoolVar(&short, "short", false, "") flags.BoolVar(&c.evals, "evals", false, "") flags.BoolVar(&c.allAllocs, "all-allocs", false, "") + flags.BoolVar(&c.json, "json", false, "") + flags.StringVar(&c.tmpl, "t", "", "") flags.BoolVar(&c.verbose, "verbose", false, "") if err := flags.Parse(args); err != nil { @@ -143,7 +160,29 @@ func (c *JobStatusCommand) Run(args []string) int { // No output if we have no jobs c.Ui.Output("No running jobs") } else { - c.Ui.Output(createStatusListOutput(jobs, allNamespaces)) + if c.json || len(c.tmpl) > 0 { + pairs := make([]NamespacedID, len(jobs)) + + for i, j := range jobs { + pairs[i] = NamespacedID{ID: j.ID, Namespace: j.Namespace} + } + + jsonJobs, err := createJsonJobsOutput(client, c.allAllocs, pairs...) + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + + out, err := Format(true, c.tmpl, jsonJobs) + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + + c.Ui.Output(out) + } else { + c.Ui.Output(createStatusListOutput(jobs, allNamespaces)) + } } return 0 } @@ -172,6 +211,26 @@ func (c *JobStatusCommand) Run(args []string) int { nodePool = *job.NodePool } + if c.json || len(c.tmpl) > 0 { + jsonJobs, err := createJsonJobsOutput(client, c.allAllocs, + NamespacedID{ID: *job.ID, Namespace: *job.Namespace}) + + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + + out, err := Format(true, c.tmpl, jsonJobs) + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + + c.Ui.Output(out) + + return 0 + } + // Format the job info basic := []string{ fmt.Sprintf("ID|%s", *job.ID), @@ -666,6 +725,43 @@ func (c *JobStatusCommand) outputFailedPlacements(failedEval *api.Evaluation) { } } +func createJsonJobsOutput(client *api.Client, allAllocs bool, jobs ...NamespacedID) ([]JobJson, error) { + jsonJobs := make([]JobJson, len(jobs)) + + for i, pair := range jobs { + q := &api.QueryOptions{Namespace: pair.Namespace} + + summary, _, err := client.Jobs().Summary(pair.ID, q) + if err != nil { + return nil, fmt.Errorf("Error querying job summary: %s", err) + } + + allocations, _, err := client.Jobs().Allocations(pair.ID, allAllocs, q) + if err != nil { + return nil, fmt.Errorf("Error querying job allocations: %s", err) + } + + latestDeployment, _, err := client.Jobs().LatestDeployment(pair.ID, q) + if err != nil { + return nil, fmt.Errorf("Error querying latest job deployment: %s", err) + } + + evals, _, err := client.Jobs().Evaluations(pair.ID, q) + if err != nil { + return nil, fmt.Errorf("Error querying job evaluations: %s", err) + } + + jsonJobs[i] = JobJson{ + Summary: summary, + Allocations: allocations, + LatestDeployment: latestDeployment, + Evaluations: evals, + } + } + + return jsonJobs, nil +} + // list general information about a list of jobs func createStatusListOutput(jobs []*api.JobListStub, displayNS bool) string { out := make([]string, len(jobs)+1) diff --git a/website/content/docs/commands/job/status.mdx b/website/content/docs/commands/job/status.mdx index 5842f8059..dfcbc885a 100644 --- a/website/content/docs/commands/job/status.mdx +++ b/website/content/docs/commands/job/status.mdx @@ -44,6 +44,10 @@ run the command with a job prefix instead of the exact job ID. - `-short`: Display short output. Used only when a single node is being queried. Drops verbose node allocation data from the output. +- `-json`: Output the job status in JSON format. + +- `-t`: Format and display the job status using a Go template. + - `-verbose`: Show full information. Allocation create and modify times are shown in `yyyy/mm/dd hh:mm:ss` format.