Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

recommendations CLI: autocomplete support #9317

Merged
merged 3 commits into from
Nov 11, 2020
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ IMPROVEMENTS:
* api: Added ?resources=true query parameter to /v1/nodes and /v1/allocations to include resource allocations in listings. [[GH-9055](https://github.com/hashicorp/nomad/issues/9055)]
* api: Added ?task_states=false query parameter to /v1/allocations to remove TaskStates from listings. Defaults to being included as before. [[GH-9055](https://github.com/hashicorp/nomad/issues/9055)]
* build: Updated to Go 1.15.4. [[GH-9305](https://github.com/hashicorp/nomad/issues/9305)]
* cli: Added autocompletion for `recommendation` commands [[GH-9317](https://github.com/hashicorp/nomad/issues/9317)]
* cli: Added `scale` and `scaling-events` subcommands to the `job` command. [[GH-9023](https://github.com/hashicorp/nomad/pull/9023)]
* cli: Added `scaling` command for interaction with the scaling API endpoint. [[GH-9025](https://github.com/hashicorp/nomad/pull/9025)]
* client: Batch state store writes to reduce disk IO. [[GH-9093](https://github.com/hashicorp/nomad/issues/9093)]
Expand Down
21 changes: 11 additions & 10 deletions api/contexts/contexts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ package contexts
type Context string

const (
Allocs Context = "allocs"
Deployments Context = "deployment"
Evals Context = "evals"
Jobs Context = "jobs"
Nodes Context = "nodes"
Namespaces Context = "namespaces"
Quotas Context = "quotas"
Plugins Context = "plugins"
Volumes Context = "volumes"
All Context = "all"
Allocs Context = "allocs"
Deployments Context = "deployment"
Evals Context = "evals"
Jobs Context = "jobs"
Nodes Context = "nodes"
Namespaces Context = "namespaces"
Quotas Context = "quotas"
Recommendations Context = "recommendations"
Plugins Context = "plugins"
Volumes Context = "volumes"
All Context = "all"
)
2 changes: 2 additions & 0 deletions command/recommendation_apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"strings"

"github.com/hashicorp/nomad/api"

"github.com/mitchellh/cli"
"github.com/posener/complete"
)
Expand All @@ -15,6 +16,7 @@ var _ cli.Command = &RecommendationApplyCommand{}
// RecommendationApplyCommand implements cli.Command.
type RecommendationApplyCommand struct {
Meta
RecommendationAutocompleteCommand
}

// Help satisfies the cli.Command Help function.
Expand Down
14 changes: 12 additions & 2 deletions command/recommendation_apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"fmt"
"testing"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/testutil"
"github.com/mitchellh/cli"
"github.com/stretchr/testify/require"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/testutil"
)

func TestRecommendationApplyCommand_Run(t *testing.T) {
Expand Down Expand Up @@ -83,3 +84,12 @@ func TestRecommendationApplyCommand_Run(t *testing.T) {
require.NoError(err)
require.Equal(1, *jobResp.TaskGroups[0].Tasks[0].Resources.CPU)
}

func TestRecommendationApplyCommand_AutocompleteArgs(t *testing.T) {
srv, client, url := testServer(t, true, nil)
defer srv.Shutdown()

ui := cli.NewMockUi()
cmd := RecommendationApplyCommand{Meta: Meta{Ui: ui, flagAddress: url}}
testRecommendationAutocompleteCommand(t, client, srv, ui, &cmd.RecommendationAutocompleteCommand)
}
24 changes: 24 additions & 0 deletions command/recommendation_dismiss.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,38 @@ import (

"github.com/mitchellh/cli"
"github.com/posener/complete"

"github.com/hashicorp/nomad/api/contexts"
)

// Ensure RecommendationDismissCommand satisfies the cli.Command interface.
var _ cli.Command = &RecommendationDismissCommand{}

// RecommendationAutocompleteCommand provides AutocompleteArgs for all
// recommendation commands that support prefix-search autocompletion
type RecommendationAutocompleteCommand struct {
Meta
}

func (r *RecommendationAutocompleteCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictFunc(func(a complete.Args) []string {
client, err := r.Meta.Client()
if err != nil {
return nil
}

resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Recommendations, nil)
if err != nil {
return []string{}
}
return resp.Matches[contexts.Recommendations]
})
}

// RecommendationDismissCommand implements cli.Command.
type RecommendationDismissCommand struct {
Meta
RecommendationAutocompleteCommand
}

// Help satisfies the cli.Command Help function.
Expand Down
51 changes: 51 additions & 0 deletions command/recommendation_dismiss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import (
"testing"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/command/agent"
"github.com/hashicorp/nomad/testutil"
"github.com/mitchellh/cli"
"github.com/posener/complete"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -80,3 +83,51 @@ func TestRecommendationDismissCommand_Run(t *testing.T) {
require.Error(err, "not found")
require.Nil(recInfo)
}

func TestRecommendationDismissCommand_AutocompleteArgs(t *testing.T) {
srv, client, url := testServer(t, true, nil)
defer srv.Shutdown()

ui := cli.NewMockUi()
cmd := &RecommendationDismissCommand{Meta: Meta{Ui: ui, flagAddress: url}}

testRecommendationAutocompleteCommand(t, client, srv, ui, &cmd.RecommendationAutocompleteCommand)
}

func testRecommendationAutocompleteCommand(t *testing.T, client *api.Client, srv *agent.TestAgent, ui *cli.MockUi, cmd *RecommendationAutocompleteCommand) {
assert := assert.New(t)
t.Parallel()

// Register a test job to write a recommendation against.
testJob := testJob("recommendation_autocomplete")
regResp, _, err := client.Jobs().Register(testJob, nil)
require.NoError(t, err)
registerCode := waitForSuccess(ui, client, fullId, t, regResp.EvalID)
require.Equal(t, 0, registerCode)

// Write a recommendation.
rec := &api.Recommendation{
JobID: *testJob.ID,
Group: *testJob.TaskGroups[0].Name,
Task: testJob.TaskGroups[0].Tasks[0].Name,
Resource: "CPU",
Value: 1050,
Meta: map[string]interface{}{"test-meta-entry": "test-meta-value"},
Stats: map[string]float64{"p13": 1.13},
}
rec, _, err = client.Recommendations().Upsert(rec, nil)
if srv.Enterprise {
require.NoError(t, err)
} else {
require.Error(t, err, "Nomad Enterprise only endpoint")
return
}

prefix := rec.ID[:5]
args := complete.Args{Last: prefix}
predictor := cmd.AutocompleteArgs()

res := predictor.Predict(args)
assert.Equal(1, len(res))
assert.Equal(rec.ID, res[0])
}
1 change: 1 addition & 0 deletions command/recommendation_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var _ cli.Command = &RecommendationInfoCommand{}
// RecommendationInfoCommand implements cli.Command.
type RecommendationInfoCommand struct {
Meta
RecommendationAutocompleteCommand
}

// Help satisfies the cli.Command Help function.
Expand Down
14 changes: 12 additions & 2 deletions command/recommendation_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"fmt"
"testing"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/testutil"
"github.com/mitchellh/cli"
"github.com/stretchr/testify/require"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/testutil"
)

func TestRecommendationInfoCommand_Run(t *testing.T) {
Expand Down Expand Up @@ -81,3 +82,12 @@ func TestRecommendationInfoCommand_Run(t *testing.T) {
require.Contains(out, recResp.ID)
}
}

func TestRecommendationInfoCommand_AutocompleteArgs(t *testing.T) {
srv, client, url := testServer(t, true, nil)
defer srv.Shutdown()

ui := cli.NewMockUi()
cmd := RecommendationInfoCommand{Meta: Meta{Ui: ui, flagAddress: url}}
testRecommendationAutocompleteCommand(t, client, srv, ui, &cmd.RecommendationAutocompleteCommand)
}
22 changes: 3 additions & 19 deletions command/recommendation_list_test.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,21 @@
package command

import (
"fmt"
"sort"
"testing"

"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/testutil"
"github.com/mitchellh/cli"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/hashicorp/nomad/api"
)

func TestRecommendationListCommand_Run(t *testing.T) {
require := require.New(t)
t.Parallel()
srv, client, url := testServer(t, true, nil)
defer srv.Shutdown()
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")
}
if _, ok := nodes[0].Drivers["mock_driver"]; !ok {
return false, fmt.Errorf("mock_driver not ready")
}
return true, nil
}, func(err error) {
t.Fatalf("err: %s", err)
})

ui := cli.NewMockUi()
cmd := &RecommendationListCommand{Meta: Meta{Ui: ui}}
Expand Down Expand Up @@ -89,7 +73,7 @@ func TestRecommendationListCommand_Run(t *testing.T) {
}
}

func TestRecommendationList_Sort(t *testing.T) {
func TestRecommendationListCommand_Sort(t *testing.T) {
testCases := []struct {
inputRecommendationList []*api.Recommendation
expectedOutputList []*api.Recommendation
Expand Down
21 changes: 11 additions & 10 deletions nomad/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,16 +193,17 @@ var (
type Context string

const (
Allocs Context = "allocs"
Deployments Context = "deployment"
Evals Context = "evals"
Jobs Context = "jobs"
Nodes Context = "nodes"
Namespaces Context = "namespaces"
Quotas Context = "quotas"
All Context = "all"
Plugins Context = "plugins"
Volumes Context = "volumes"
Allocs Context = "allocs"
Deployments Context = "deployment"
Evals Context = "evals"
Jobs Context = "jobs"
Nodes Context = "nodes"
Namespaces Context = "namespaces"
Quotas Context = "quotas"
Recommendations Context = "recommendations"
All Context = "all"
Plugins Context = "plugins"
Volumes Context = "volumes"
)

// NamespacedID is a tuple of an ID and a namespace
Expand Down
21 changes: 11 additions & 10 deletions vendor/github.com/hashicorp/nomad/api/contexts/contexts.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.