updated "scaling policy info" with prefix search and auto-complete

This commit is contained in:
Chris Baker 2021-02-03 21:29:44 +00:00
parent 02bef2df0a
commit 452b738db1
3 changed files with 101 additions and 39 deletions

View File

@ -6,6 +6,9 @@ import (
"github.com/mitchellh/cli"
"github.com/posener/complete"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/api/contexts"
)
// Ensure ScalingPolicyInfoCommand satisfies the cli.Command interface.
@ -54,6 +57,21 @@ func (s *ScalingPolicyInfoCommand) AutocompleteFlags() complete.Flags {
})
}
func (c *ScalingPolicyInfoCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictFunc(func(a complete.Args) []string {
client, err := c.Meta.Client()
if err != nil {
return nil
}
resp, _, err := client.Search().PrefixSearch(a.Last, contexts.ScalingPolicies, nil)
if err != nil {
return []string{}
}
return resp.Matches[contexts.ScalingPolicies]
})
}
// Name returns the name of this command.
func (s *ScalingPolicyInfoCommand) Name() string { return "scaling policy info" }
@ -70,15 +88,6 @@ func (s *ScalingPolicyInfoCommand) Run(args []string) int {
return 1
}
if args = flags.Args(); len(args) != 1 {
s.Ui.Error("This command takes one argument: <policy_id>")
s.Ui.Error(commandErrorText(s))
return 1
}
// Get the policy ID.
policyID := args[0]
// Get the HTTP client.
client, err := s.Meta.Client()
if err != nil {
@ -86,17 +95,16 @@ func (s *ScalingPolicyInfoCommand) Run(args []string) int {
return 1
}
policy, _, err := client.Scaling().GetPolicy(policyID, nil)
if err != nil {
s.Ui.Error(fmt.Sprintf("Error listing scaling policies: %s", err))
return 1
}
args = flags.Args()
// If the user has specified to output the policy as JSON or using a
// template then perform this action for the entire object and exit the
// command.
if json || len(tmpl) > 0 {
out, err := Format(json, tmpl, policy)
// Formatted list mode if no policy ID
if len(args) == 0 && (json || len(tmpl) > 0) {
policies, _, err := client.Scaling().ListPolicies(nil)
if err != nil {
s.Ui.Error(fmt.Sprintf("Error listing scaling policies: %v", err))
return 1
}
out, err := Format(json, tmpl, policies)
if err != nil {
s.Ui.Error(err.Error())
return 1
@ -105,14 +113,65 @@ func (s *ScalingPolicyInfoCommand) Run(args []string) int {
return 0
}
if len(args) != 1 {
s.Ui.Error("This command takes one of the following argument conditions:")
s.Ui.Error(" * A single <policy_id>")
s.Ui.Error(" * No arguments, with output format specified")
s.Ui.Error(commandErrorText(s))
return 1
}
policyID := args[0]
if len(policyID) == 1 {
s.Ui.Error("Identifier must contain at least two characters.")
return 1
}
policyID = sanitizeUUIDPrefix(policyID)
policies, _, err := client.Scaling().ListPolicies(&api.QueryOptions{
Prefix: policyID,
})
if err != nil {
s.Ui.Error(fmt.Sprintf("Error querying scaling policy: %v", err))
return 1
}
if len(policies) == 0 {
s.Ui.Error(fmt.Sprintf("No scaling policies with prefix or id %q found", policyID))
return 1
}
if len(policies) > 1 {
out := formatScalingPolicies(policies)
s.Ui.Output(fmt.Sprintf("Prefix matched multiple scaling policies\n\n%s", out))
return 0
}
policy, _, err := client.Scaling().GetPolicy(policies[0].ID, nil)
if err != nil {
s.Ui.Error(fmt.Sprintf("Error querying scaling policy: %s", err))
return 1
}
if json || len(tmpl) > 0 {
out, err := Format(json, tmpl, policy)
if err != nil {
s.Ui.Error(err.Error())
return 1
}
s.Ui.Output(out)
return 0
}
// Format the policy document which is a freeform map[string]interface{}
// and therefore can only be made pretty to a certain extent. Do this
// before the rest of the formatting so any errors are clearly passed back
// to the CLI.
out, err := Format(true, "", policy.Policy)
if err != nil {
s.Ui.Error(err.Error())
return 1
out := "<empty>"
if len(policy.Policy) > 0 {
out, err = Format(true, "", policy.Policy)
if err != nil {
s.Ui.Error(err.Error())
return 1
}
}
info := []string{

View File

@ -35,10 +35,10 @@ func TestScalingPolicyInfoCommand_Run(t *testing.T) {
cmd := &ScalingPolicyInfoCommand{Meta: Meta{Ui: ui}}
// Calling without the policyID should result in an error.
if code := cmd.Run([]string{"-address=" + url}); code != 1 {
if code := cmd.Run([]string{"-address=" + url, "first", "second"}); code != 1 {
t.Fatalf("expected cmd run exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, "This command takes one argument: <policy_id>") {
if out := ui.ErrorWriter.String(); !strings.Contains(out, "This command takes one of the following argument conditions") {
t.Fatalf("expected argument error within output: %v", out)
}
@ -46,8 +46,8 @@ func TestScalingPolicyInfoCommand_Run(t *testing.T) {
if code := cmd.Run([]string{"-address=" + url, "scaling_policy_info"}); code != 1 {
t.Fatalf("expected cmd run exit code 1, got: %d", code)
}
if out := ui.ErrorWriter.String(); !strings.Contains(out, "404 (policy not found)") {
t.Fatalf("expected 404 not found within output: %v", out)
if out := ui.ErrorWriter.String(); !strings.Contains(out, `No scaling policies with prefix or id "scaling_policy_inf" found`) {
t.Fatalf("expected 'no policies found' within output: %v", out)
}
// Generate a test job.

View File

@ -87,6 +87,7 @@ func (s *ScalingPolicyListCommand) Run(args []string) int {
if args = flags.Args(); len(args) > 0 {
s.Ui.Error("This command takes no arguments")
s.Ui.Error(commandErrorText(s))
return 1
}
// Get the HTTP client.
@ -111,11 +112,6 @@ func (s *ScalingPolicyListCommand) Run(args []string) int {
return 1
}
if len(policies) == 0 {
s.Ui.Output("No policies found")
return 0
}
if json || len(tmpl) > 0 {
out, err := Format(json, tmpl, policies)
if err != nil {
@ -126,23 +122,30 @@ func (s *ScalingPolicyListCommand) Run(args []string) int {
return 0
}
output := formatScalingPolicies(policies)
s.Ui.Output(output)
return 0
}
func formatScalingPolicies(stubs []*api.ScalingPolicyListStub) string {
if len(stubs) == 0 {
return "No policies found"
}
// Create the output table header.
output := []string{"ID|Enabled|Type|Target"}
policies := []string{"ID|Enabled|Type|Target"}
// Sort the list of policies based on their target.
sortedPolicies := scalingPolicyStubList{policies: policies}
sortedPolicies := scalingPolicyStubList{policies: stubs}
sort.Sort(sortedPolicies)
// Iterate the policies and add to the output.
for _, policy := range sortedPolicies.policies {
output = append(output, fmt.Sprintf(
policies = append(policies, fmt.Sprintf(
"%s|%v|%s|%s",
policy.ID, policy.Enabled, policy.Type, formatScalingPolicyTarget(policy.Target)))
}
// Output.
s.Ui.Output(formatList(output))
return 0
return formatList(policies)
}
// scalingPolicyStubList is a wrapper around []*api.ScalingPolicyListStub that