diff --git a/api/jobs_batch_queue.go b/api/jobs_batch_queue.go new file mode 100644 index 00000000000..bd205ff427e --- /dev/null +++ b/api/jobs_batch_queue.go @@ -0,0 +1,26 @@ +// Copyright IBM Corp. 2015, 2026 +// SPDX-License-Identifier: BUSL-1.1 + +package api + +type Workload struct { + JobID string + Tenant string + Priority int +} + +type BatchQueueStatusResponse struct { + Workloads []Workload +} + +type BatchQueueStatusOptions struct{} + +// BatchQueueStatus is used to query the current batch job queue. +func (j *Jobs) BatchQueueStatus(opts *BatchQueueStatusOptions, q *QueryOptions) (*BatchQueueStatusResponse, *QueryMeta, error) { + var resp BatchQueueStatusResponse + qm, err := j.client.query("/v1/jobs/queue/status", &resp, q) + if err != nil { + return nil, nil, err + } + return &resp, qm, nil +} diff --git a/command/commands.go b/command/commands.go index 344d898e86b..de786f55bb5 100644 --- a/command/commands.go +++ b/command/commands.go @@ -501,6 +501,11 @@ func Commands(metaPtr *Meta, agentUi cli.Ui) map[string]cli.CommandFactory { Meta: meta, }, nil }, + "job queue": func() (cli.Command, error) { + return &JobQueueCommand{ + Meta: meta, + }, nil + }, "job revert": func() (cli.Command, error) { return &JobRevertCommand{ Meta: meta, diff --git a/command/job_queue.go b/command/job_queue.go new file mode 100644 index 00000000000..aba2042aa9b --- /dev/null +++ b/command/job_queue.go @@ -0,0 +1,113 @@ +// Copyright IBM Corp. 2015, 2026 +// SPDX-License-Identifier: BUSL-1.1 + +package command + +import ( + "fmt" + "strings" + + "github.com/hashicorp/nomad/api" + "github.com/posener/complete" + "github.com/ryanuber/columnize" +) + +type JobQueueCommand struct { + Meta +} + +func (c *JobQueueCommand) Help() string { + helpText := ` +Usage: nomad job queue [options] + + View the current status of workloads queued in a batch job queue. + + When ACLs are enabled, this command requires a token with either TBD + capabilities. Probably at least 'list-jobs'. + +General Options: + + ` + generalOptionsUsage(usageOptsDefault) + ` + +Eval Options: + + -limit + The maximum number of workloads to return + + -verbose + Display full output + +` + return strings.TrimSpace(helpText) +} + +func (c *JobQueueCommand) Synopsis() string { + return "View the status of a batch job queue" +} + +func (c *JobQueueCommand) AutocompleteFlags() complete.Flags { + return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), + complete.Flags{ + "-verbose": complete.PredictNothing, + "-limit": complete.PredictNothing, + }) +} + +func (c *JobQueueCommand) AutocompleteArgs() complete.Predictor { + return JobPredictor(c.Meta.Client) +} + +func (c *JobQueueCommand) Name() string { return "job queue" } + +func (c *JobQueueCommand) Run(args []string) int { + var verbose bool + var limit int + flags := c.Meta.FlagSet(c.Name(), FlagSetClient) + flags.Usage = func() { c.Ui.Output(c.Help()) } + flags.BoolVar(&verbose, "verbose", false, "") + flags.IntVar(&limit, "limit", 0, "") + + if err := flags.Parse(args); err != nil { + return 1 + } + + // Get the HTTP client + client, err := c.Meta.Client() + if err != nil { + c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) + return 255 + } + + // Setup the options + qo := &api.QueryOptions{} + + if limit > 0 { + qo.Params["limit"] = fmt.Sprintf("%d", limit) + } + + // Submit the request + resp, _, err := client.Jobs().BatchQueueStatus(nil, qo) + if err != nil { + c.Ui.Error(fmt.Sprintf("Error during batch queue request: %s", err)) + return 255 + } + + c.printOutput(resp) + return 0 +} + +func (c *JobQueueCommand) printOutput(resp *api.BatchQueueStatusResponse) { + if resp == nil { + c.Ui.Error("Empty batch queue response") + } + + out := make([]string, len(resp.Workloads)+2) + out[0] = "JobID|Tenant|Priority" + out[1] = "-----|------|--------" + + for i, v := range resp.Workloads { + out[i+2] = fmt.Sprintf("%s|%s|%d", v.JobID, v.Tenant, v.Priority) + } + + c.Ui.Output(columnize.Format(out, &columnize.Config{Glue: " | "})) +} diff --git a/command/job_queue_test.go b/command/job_queue_test.go new file mode 100644 index 00000000000..936f6095a2a --- /dev/null +++ b/command/job_queue_test.go @@ -0,0 +1,41 @@ +// Copyright IBM Corp. 2015, 2026 +// SPDX-License-Identifier: BUSL-1.1 + +package command + +import ( + "testing" + + "github.com/hashicorp/cli" + "github.com/hashicorp/nomad/api" + "github.com/hashicorp/nomad/ci" + "github.com/shoenig/test/must" +) + +func TestJobQueue_Implements(t *testing.T) { + ci.Parallel(t) + var _ cli.Command = &JobQueueCommand{} +} + +func TestJobQueue_printOutput(t *testing.T) { + ci.Parallel(t) + ui := cli.NewMockUi() + cmd := &JobQueueCommand{Meta: Meta{Ui: ui}} + + testResp := &api.BatchQueueStatusResponse{ + Workloads: []api.Workload{ + { + JobID: "123", + Tenant: "testTenant1", + Priority: 5, + }, + }, + } + cmd.printOutput(testResp) + + expect := "JobID | Tenant | Priority\n" + + "----- | ------ | --------\n" + + "123 | testTenant1 | 5\n" + + must.Eq(t, expect, ui.OutputWriter.String()) +}