Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions api/jobs_batch_queue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright IBM Corp. 2015, 2026
// SPDX-License-Identifier: BUSL-1.1

package api

type Workload struct {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This struct might be a little TBD when we start connecting the various PR's

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
}
5 changes: 5 additions & 0 deletions command/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
113 changes: 113 additions & 0 deletions command/job_queue.go
Original file line number Diff line number Diff line change
@@ -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
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really going to be the "TopK" workloads, so maybe mentioning this would be helpful.

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: " | "}))
}
41 changes: 41 additions & 0 deletions command/job_queue_test.go
Original file line number Diff line number Diff line change
@@ -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())
}
Loading