Merge pull request #3026 from hashicorp/f-autocomplete-job-eval-node
Add autocomplete for nodes, evals, and jobs
This commit is contained in:
commit
1ff04de2a7
|
@ -8,6 +8,8 @@ import (
|
|||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/hashicorp/nomad/testutil"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAllocStatusCommand_Implements(t *testing.T) {
|
||||
|
@ -142,3 +144,43 @@ func TestAllocStatusCommand_Run(t *testing.T) {
|
|||
}
|
||||
ui.OutputWriter.Reset()
|
||||
}
|
||||
|
||||
func TestAllocStatusCommand_AutocompleteArgs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
t.Parallel()
|
||||
|
||||
srv, client, url := testServer(t, true, nil)
|
||||
defer srv.Shutdown()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
cmd := &AllocStatusCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
||||
|
||||
jobID := "job1_sfx"
|
||||
job1 := testJob(jobID)
|
||||
resp, _, err := client.Jobs().Register(job1, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if code := waitForSuccess(ui, client, fullId, t, resp.EvalID); code != 0 {
|
||||
t.Fatalf("status code non zero saw %d", code)
|
||||
}
|
||||
|
||||
// get an alloc id
|
||||
allocID := ""
|
||||
if allocs, _, err := client.Jobs().Allocations(jobID, false, nil); err == nil {
|
||||
if len(allocs) > 0 {
|
||||
allocID = allocs[0].ID
|
||||
}
|
||||
}
|
||||
if allocID == "" {
|
||||
t.Fatal("unable to find an allocation")
|
||||
}
|
||||
|
||||
prefix := allocID[:len(allocID)-5]
|
||||
args := complete.Args{Last: prefix}
|
||||
predictor := cmd.AutocompleteArgs()
|
||||
|
||||
res := predictor.Predict(args)
|
||||
assert.Equal(1, len(res))
|
||||
assert.Equal(allocID, res[0])
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/hashicorp/nomad/api"
|
||||
"github.com/hashicorp/nomad/api/contexts"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
type EvalStatusCommand struct {
|
||||
|
@ -218,6 +220,21 @@ func (c *EvalStatusCommand) Run(args []string) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (c *EvalStatusCommand) AutocompleteFlags() complete.Flags {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *EvalStatusCommand) AutocompleteArgs() complete.Predictor {
|
||||
client, _ := c.Meta.Client()
|
||||
return complete.PredictFunc(func(a complete.Args) []string {
|
||||
resp, err := client.Search().PrefixSearch(a.Last, contexts.Evals)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
return resp.Matches[contexts.Evals]
|
||||
})
|
||||
}
|
||||
|
||||
func sortedTaskGroupFromMetrics(groups map[string]*api.AllocationMetric) []string {
|
||||
tgs := make([]string, 0, len(groups))
|
||||
for tg, _ := range groups {
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEvalStatusCommand_Implements(t *testing.T) {
|
||||
|
@ -56,3 +58,43 @@ func TestEvalStatusCommand_Fails(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEvalStatusCommand_AutocompleteArgs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
t.Parallel()
|
||||
|
||||
srv, client, url := testServer(t, true, nil)
|
||||
defer srv.Shutdown()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
cmd := &EvalStatusCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
||||
|
||||
jobID := "job1_sfx"
|
||||
job1 := testJob(jobID)
|
||||
resp, _, err := client.Jobs().Register(job1, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if code := waitForSuccess(ui, client, fullId, t, resp.EvalID); code != 0 {
|
||||
t.Fatalf("status code non zero saw %d", code)
|
||||
}
|
||||
|
||||
// get an eval id
|
||||
evalID := ""
|
||||
if evals, _, err := client.Jobs().Evaluations(jobID, nil); err == nil {
|
||||
if len(evals) > 0 {
|
||||
evalID = evals[0].ID
|
||||
}
|
||||
}
|
||||
if evalID == "" {
|
||||
t.Fatal("unable to find an evaluation")
|
||||
}
|
||||
|
||||
prefix := evalID[:len(evalID)-5]
|
||||
args := complete.Args{Last: prefix}
|
||||
predictor := cmd.AutocompleteArgs()
|
||||
|
||||
res := predictor.Predict(args)
|
||||
assert.Equal(1, len(res))
|
||||
assert.Equal(evalID, res[0])
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/hashicorp/nomad/api"
|
||||
"github.com/hashicorp/nomad/api/contexts"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -525,6 +527,21 @@ func (c *JobStatusCommand) outputFailedPlacements(failedEval *api.Evaluation) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *JobStatusCommand) AutocompleteFlags() complete.Flags {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *JobStatusCommand) AutocompleteArgs() complete.Predictor {
|
||||
client, _ := c.Meta.Client()
|
||||
return complete.PredictFunc(func(a complete.Args) []string {
|
||||
resp, err := client.Search().PrefixSearch(a.Last, contexts.Jobs)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
return resp.Matches[contexts.Jobs]
|
||||
})
|
||||
}
|
||||
|
||||
// list general information about a list of jobs
|
||||
func createStatusListOutput(jobs []*api.JobListStub) string {
|
||||
out := make([]string, len(jobs)+1)
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
|
||||
"github.com/hashicorp/nomad/api"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJobStatusCommand_Implements(t *testing.T) {
|
||||
|
@ -188,6 +190,35 @@ func TestJobStatusCommand_Fails(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestJobStatusCommand_AutocompleteArgs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
t.Parallel()
|
||||
|
||||
srv, client, url := testServer(t, true, nil)
|
||||
defer srv.Shutdown()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
cmd := &JobStatusCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
||||
|
||||
jobID := "job1_sfx"
|
||||
job1 := testJob(jobID)
|
||||
resp, _, err := client.Jobs().Register(job1, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if code := waitForSuccess(ui, client, fullId, t, resp.EvalID); code != 0 {
|
||||
t.Fatalf("status code non zero saw %d", code)
|
||||
}
|
||||
|
||||
prefix := jobID[:len(jobID)-5]
|
||||
args := complete.Args{Last: prefix}
|
||||
predictor := cmd.AutocompleteArgs()
|
||||
|
||||
res := predictor.Predict(args)
|
||||
assert.Equal(1, len(res))
|
||||
assert.Equal(jobID, res[0])
|
||||
}
|
||||
|
||||
func waitForSuccess(ui cli.Ui, client *api.Client, length int, t *testing.T, evalId string) int {
|
||||
mon := newMonitor(ui, client, length)
|
||||
monErr := mon.monitor(evalId, false)
|
||||
|
|
|
@ -7,10 +7,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
humanize "github.com/dustin/go-humanize"
|
||||
"github.com/mitchellh/colorstring"
|
||||
"github.com/posener/complete"
|
||||
|
||||
"github.com/hashicorp/nomad/api"
|
||||
"github.com/hashicorp/nomad/api/contexts"
|
||||
"github.com/hashicorp/nomad/helper"
|
||||
)
|
||||
|
||||
|
@ -436,6 +438,21 @@ func (c *NodeStatusCommand) printDiskStats(hostStats *api.HostStats) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *NodeStatusCommand) AutocompleteFlags() complete.Flags {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *NodeStatusCommand) AutocompleteArgs() complete.Predictor {
|
||||
client, _ := c.Meta.Client()
|
||||
return complete.PredictFunc(func(a complete.Args) []string {
|
||||
resp, err := client.Search().PrefixSearch(a.Last, contexts.Nodes)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
return resp.Matches[contexts.Nodes]
|
||||
})
|
||||
}
|
||||
|
||||
// getRunningAllocs returns a slice of allocation id's running on the node
|
||||
func getRunningAllocs(client *api.Client, nodeID string) ([]*api.Allocation, error) {
|
||||
var allocs []*api.Allocation
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
"github.com/hashicorp/nomad/command/agent"
|
||||
"github.com/hashicorp/nomad/testutil"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNodeStatusCommand_Implements(t *testing.T) {
|
||||
|
@ -213,3 +215,38 @@ func TestNodeStatusCommand_Fails(t *testing.T) {
|
|||
t.Fatalf("expected getting formatter error, got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeStatusCommand_AutocompleteArgs(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
t.Parallel()
|
||||
|
||||
srv, client, url := testServer(t, true, nil)
|
||||
defer srv.Shutdown()
|
||||
|
||||
// Wait for a node to appear
|
||||
var nodeID string
|
||||
testutil.WaitForResult(func() (bool, error) {
|
||||
nodes, _, err := client.Nodes().List(nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return false, fmt.Errorf("missing node")
|
||||
}
|
||||
nodeID = nodes[0].ID
|
||||
return true, nil
|
||||
}, func(err error) {
|
||||
t.Fatalf("err: %s", err)
|
||||
})
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
cmd := &NodeStatusCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
||||
|
||||
prefix := nodeID[:len(nodeID)-5]
|
||||
args := complete.Args{Last: prefix}
|
||||
predictor := cmd.AutocompleteArgs()
|
||||
|
||||
res := predictor.Predict(args)
|
||||
assert.Equal(1, len(res))
|
||||
assert.Equal(nodeID, res[0])
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue