From a4d6fc32935c675d0e1028f5f39d69bad49a2837 Mon Sep 17 00:00:00 2001 From: Chris Baker <1675087+cgbaker@users.noreply.github.com> Date: Wed, 3 Feb 2021 19:26:57 +0000 Subject: [PATCH 1/6] support for scaling_policy in global prefix search --- nomad/search_endpoint.go | 5 +++++ nomad/search_endpoint_oss.go | 5 +++++ nomad/search_endpoint_test.go | 39 +++++++++++++++++++++++++++++++++++ nomad/structs/structs.go | 1 + 4 files changed, 50 insertions(+) diff --git a/nomad/search_endpoint.go b/nomad/search_endpoint.go index 478c73b84553..382d109f80e5 100644 --- a/nomad/search_endpoint.go +++ b/nomad/search_endpoint.go @@ -31,6 +31,7 @@ var ( structs.Deployments, structs.Plugins, structs.Volumes, + structs.ScalingPolicies, structs.Namespaces, } ) @@ -68,6 +69,8 @@ func (s *Search) getMatches(iter memdb.ResultIterator, prefix string) ([]string, id = t.ID case *structs.CSIVolume: id = t.ID + case *structs.ScalingPolicy: + id = t.ID case *structs.Namespace: id = t.Name default: @@ -106,6 +109,8 @@ func getResourceIter(context structs.Context, aclObj *acl.ACL, namespace, prefix return state.DeploymentsByIDPrefix(ws, namespace, prefix) case structs.Plugins: return state.CSIPluginsByIDPrefix(ws, prefix) + case structs.ScalingPolicies: + return state.ScalingPoliciesByIDPrefix(ws, namespace, prefix) case structs.Volumes: return state.CSIVolumesByIDPrefix(ws, namespace, prefix) case structs.Namespaces: diff --git a/nomad/search_endpoint_oss.go b/nomad/search_endpoint_oss.go index e3f0fc0abcb8..7c1b3b7a856f 100644 --- a/nomad/search_endpoint_oss.go +++ b/nomad/search_endpoint_oss.go @@ -102,6 +102,7 @@ func searchContexts(aclObj *acl.ACL, namespace string, context structs.Context) acl.NamespaceCapabilityListJobs, acl.NamespaceCapabilityReadJob) volRead := allowVolume(aclObj, namespace) + policyRead := aclObj.AllowNsOp(namespace, acl.NamespaceCapabilityListScalingPolicies) // Filter contexts down to those the ACL grants access to available := make([]structs.Context, 0, len(all)) @@ -111,6 +112,10 @@ func searchContexts(aclObj *acl.ACL, namespace string, context structs.Context) if jobRead { available = append(available, c) } + case structs.ScalingPolicies: + if policyRead || jobRead { + available = append(available, c) + } case structs.Namespaces: if aclObj.AllowNamespace(namespace) { available = append(available, c) diff --git a/nomad/search_endpoint_test.go b/nomad/search_endpoint_test.go index f9a0cdbd1f9c..94ecfe0a08eb 100644 --- a/nomad/search_endpoint_test.go +++ b/nomad/search_endpoint_test.go @@ -989,3 +989,42 @@ func TestSearch_PrefixSearch_Namespace_ACL(t *testing.T) { assert.Len(resp.Matches[structs.Namespaces], 2) } } + +func TestSearch_PrefixSearch_ScalingPolicy(t *testing.T) { + t.Parallel() + require := require.New(t) + + s, cleanupS := TestServer(t, func(c *Config) { + c.NumSchedulers = 0 + }) + defer cleanupS() + codec := rpcClient(t, s) + testutil.WaitForLeader(t, s.RPC) + + job, policy := mock.JobWithScalingPolicy() + prefix := policy.ID + state := s.fsm.State() + + require.NoError(state.UpsertJob(structs.MsgTypeTestSetup, jobIndex, job)) + + req := &structs.SearchRequest{ + Prefix: prefix, + Context: structs.ScalingPolicies, + QueryOptions: structs.QueryOptions{ + Region: "global", + Namespace: job.Namespace, + }, + } + + var resp structs.SearchResponse + require.NoError(msgpackrpc.CallWithCodec(codec, "Search.PrefixSearch", req, &resp)) + require.Equal(1, len(resp.Matches[structs.ScalingPolicies])) + require.Equal(policy.ID, resp.Matches[structs.ScalingPolicies][0]) + require.Equal(uint64(jobIndex), resp.Index) + + req.Context = structs.All + require.NoError(msgpackrpc.CallWithCodec(codec, "Search.PrefixSearch", req, &resp)) + require.Equal(1, len(resp.Matches[structs.ScalingPolicies])) + require.Equal(policy.ID, resp.Matches[structs.ScalingPolicies][0]) + require.Equal(uint64(jobIndex), resp.Index) +} diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 88a2731334b3..f5be489fb842 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -201,6 +201,7 @@ const ( Namespaces Context = "namespaces" Quotas Context = "quotas" Recommendations Context = "recommendations" + ScalingPolicies Context = "scaling_policy" All Context = "all" Plugins Context = "plugins" Volumes Context = "volumes" From 32c7b7d9c31ea85c0ee3d87c8d95278ba21ea371 Mon Sep 17 00:00:00 2001 From: Chris Baker <1675087+cgbaker@users.noreply.github.com> Date: Wed, 3 Feb 2021 21:28:32 +0000 Subject: [PATCH 2/6] api: added scaling_policy context to global search --- api/contexts/contexts.go | 1 + vendor/github.com/hashicorp/nomad/api/contexts/contexts.go | 1 + 2 files changed, 2 insertions(+) diff --git a/api/contexts/contexts.go b/api/contexts/contexts.go index ea4ea1309509..399424df5bba 100644 --- a/api/contexts/contexts.go +++ b/api/contexts/contexts.go @@ -12,6 +12,7 @@ const ( Namespaces Context = "namespaces" Quotas Context = "quotas" Recommendations Context = "recommendations" + ScalingPolicies Context = "scaling_policy" Plugins Context = "plugins" Volumes Context = "volumes" All Context = "all" diff --git a/vendor/github.com/hashicorp/nomad/api/contexts/contexts.go b/vendor/github.com/hashicorp/nomad/api/contexts/contexts.go index ea4ea1309509..399424df5bba 100644 --- a/vendor/github.com/hashicorp/nomad/api/contexts/contexts.go +++ b/vendor/github.com/hashicorp/nomad/api/contexts/contexts.go @@ -12,6 +12,7 @@ const ( Namespaces Context = "namespaces" Quotas Context = "quotas" Recommendations Context = "recommendations" + ScalingPolicies Context = "scaling_policy" Plugins Context = "plugins" Volumes Context = "volumes" All Context = "all" From fbdbd7736c798c02bcb136db2845d2cea98125bf Mon Sep 17 00:00:00 2001 From: Chris Baker <1675087+cgbaker@users.noreply.github.com> Date: Wed, 3 Feb 2021 21:29:05 +0000 Subject: [PATCH 3/6] bad boolean logic for List-on-Info commands --- command/alloc_status.go | 2 +- command/eval_status.go | 2 +- command/job_inspect.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/command/alloc_status.go b/command/alloc_status.go index ed388da23cfc..aabcaaf43a32 100644 --- a/command/alloc_status.go +++ b/command/alloc_status.go @@ -115,7 +115,7 @@ func (c *AllocStatusCommand) Run(args []string) int { } // If args not specified but output format is specified, format and output the allocations data list - if len(args) == 0 && json || len(tmpl) > 0 { + if len(args) == 0 && (json || len(tmpl) > 0) { allocs, _, err := client.Allocations().List(nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error querying allocations: %v", err)) diff --git a/command/eval_status.go b/command/eval_status.go index 881bb9dbe55b..967ff6efd2ad 100644 --- a/command/eval_status.go +++ b/command/eval_status.go @@ -106,7 +106,7 @@ func (c *EvalStatusCommand) Run(args []string) int { } // If args not specified but output format is specified, format and output the evaluations data list - if len(args) == 0 && json || len(tmpl) > 0 { + if len(args) == 0 && (json || len(tmpl) > 0) { evals, _, err := client.Evaluations().List(nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error querying evaluations: %v", err)) diff --git a/command/job_inspect.go b/command/job_inspect.go index 7f030f67a4ce..6966f04e8856 100644 --- a/command/job_inspect.go +++ b/command/job_inspect.go @@ -94,7 +94,7 @@ func (c *JobInspectCommand) Run(args []string) int { } // If args not specified but output format is specified, format and output the jobs data list - if len(args) == 0 && json || len(tmpl) > 0 { + if len(args) == 0 && (json || len(tmpl) > 0) { jobs, _, err := client.Jobs().List(nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error querying jobs: %v", err)) From bfec8a7e4d220d5b181b29dca912fb28a59f6611 Mon Sep 17 00:00:00 2001 From: Chris Baker <1675087+cgbaker@users.noreply.github.com> Date: Wed, 3 Feb 2021 21:29:44 +0000 Subject: [PATCH 4/6] updated "scaling policy info" with prefix search and auto-complete --- command/scaling_policy_info.go | 91 ++++++++++++++++++++++++----- command/scaling_policy_info_test.go | 8 +-- command/scaling_policy_list.go | 27 +++++---- 3 files changed, 94 insertions(+), 32 deletions(-) diff --git a/command/scaling_policy_info.go b/command/scaling_policy_info.go index cf321fe8b964..24123f8f07cc 100644 --- a/command/scaling_policy_info.go +++ b/command/scaling_policy_info.go @@ -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,37 +88,75 @@ func (s *ScalingPolicyInfoCommand) Run(args []string) int { return 1 } - if args = flags.Args(); len(args) != 1 { - s.Ui.Error("This command takes one argument: ") - s.Ui.Error(commandErrorText(s)) + // Get the HTTP client. + client, err := s.Meta.Client() + if err != nil { + s.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) return 1 } - // Get the policy ID. + args = flags.Args() + + // 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 + } + s.Ui.Output(out) + return 0 + } + + if len(args) != 1 { + s.Ui.Error("This command takes one of the following argument conditions:") + s.Ui.Error(" * A single ") + 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 + } - // Get the HTTP client. - client, err := s.Meta.Client() + policyID = sanitizeUUIDPrefix(policyID) + policies, _, err := client.Scaling().ListPolicies(&api.QueryOptions{ + Prefix: policyID, + }) if err != nil { - s.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) + 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(policyID, nil) + policy, _, err := client.Scaling().GetPolicy(policies[0].ID, nil) if err != nil { - s.Ui.Error(fmt.Sprintf("Error listing scaling policies: %s", err)) + s.Ui.Error(fmt.Sprintf("Error querying scaling policy: %s", err)) return 1 } - // 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) if err != nil { s.Ui.Error(err.Error()) return 1 } + s.Ui.Output(out) return 0 } @@ -109,10 +165,13 @@ func (s *ScalingPolicyInfoCommand) Run(args []string) int { // 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 := "" + if len(policy.Policy) > 0 { + out, err = Format(true, "", policy.Policy) + if err != nil { + s.Ui.Error(err.Error()) + return 1 + } } info := []string{ diff --git a/command/scaling_policy_info_test.go b/command/scaling_policy_info_test.go index 0eacbc0254cc..44e8273d9fb0 100644 --- a/command/scaling_policy_info_test.go +++ b/command/scaling_policy_info_test.go @@ -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: ") { + 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. diff --git a/command/scaling_policy_list.go b/command/scaling_policy_list.go index 783655b88cda..e2ecfdb6f715 100644 --- a/command/scaling_policy_list.go +++ b/command/scaling_policy_list.go @@ -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 From b0ccf3ca5cfc90269491e913a811bf506d4f346c Mon Sep 17 00:00:00 2001 From: Chris Baker <1675087+cgbaker@users.noreply.github.com> Date: Thu, 4 Feb 2021 15:08:13 +0000 Subject: [PATCH 5/6] scaling policy -verbose flag, plus testing and other recommendations from review --- command/scaling_policy_info.go | 23 ++++++++++++++++------ command/scaling_policy_info_test.go | 16 +++++++++++++++ command/scaling_policy_list.go | 30 +++++++++++++++++++++-------- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/command/scaling_policy_info.go b/command/scaling_policy_info.go index 24123f8f07cc..d255816ae4fe 100644 --- a/command/scaling_policy_info.go +++ b/command/scaling_policy_info.go @@ -35,6 +35,9 @@ General Options: Policy Info Options: + -verbose + Display full information. + -json Output the scaling policy in its JSON format. @@ -52,8 +55,9 @@ func (s *ScalingPolicyInfoCommand) Synopsis() string { func (s *ScalingPolicyInfoCommand) AutocompleteFlags() complete.Flags { return mergeAutocompleteFlags(s.Meta.AutocompleteFlags(FlagSetClient), complete.Flags{ - "-json": complete.PredictNothing, - "-t": complete.PredictAnything, + "-verbose": complete.PredictNothing, + "-json": complete.PredictNothing, + "-t": complete.PredictAnything, }) } @@ -77,17 +81,24 @@ func (s *ScalingPolicyInfoCommand) Name() string { return "scaling policy info" // Run satisfies the cli.Command Run function. func (s *ScalingPolicyInfoCommand) Run(args []string) int { - var json bool + var json, verbose bool var tmpl string flags := s.Meta.FlagSet(s.Name(), FlagSetClient) flags.Usage = func() { s.Ui.Output(s.Help()) } + flags.BoolVar(&verbose, "verbose", false, "") flags.BoolVar(&json, "json", false, "") flags.StringVar(&tmpl, "t", "", "") if err := flags.Parse(args); err != nil { return 1 } + // Truncate the id unless full length is requested + length := shortId + if verbose { + length = fullId + } + // Get the HTTP client. client, err := s.Meta.Client() if err != nil { @@ -139,8 +150,8 @@ func (s *ScalingPolicyInfoCommand) Run(args []string) int { return 1 } if len(policies) > 1 { - out := formatScalingPolicies(policies) - s.Ui.Output(fmt.Sprintf("Prefix matched multiple scaling policies\n\n%s", out)) + out := formatScalingPolicies(policies, length) + s.Ui.Error(fmt.Sprintf("Prefix matched multiple scaling policies\n\n%s", out)) return 0 } @@ -175,7 +186,7 @@ func (s *ScalingPolicyInfoCommand) Run(args []string) int { } info := []string{ - fmt.Sprintf("ID|%s", policy.ID), + fmt.Sprintf("ID|%s", limit(policy.ID, length)), fmt.Sprintf("Enabled|%v", *policy.Enabled), fmt.Sprintf("Target|%s", formatScalingPolicyTarget(policy.Target)), fmt.Sprintf("Min|%v", *policy.Min), diff --git a/command/scaling_policy_info_test.go b/command/scaling_policy_info_test.go index 44e8273d9fb0..29c93784cde6 100644 --- a/command/scaling_policy_info_test.go +++ b/command/scaling_policy_info_test.go @@ -35,6 +35,14 @@ 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 { + t.Fatalf("expected cmd run exit code 1, got: %d", code) + } + 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) + } + + // Calling with more than one argument should result in an error. if code := cmd.Run([]string{"-address=" + url, "first", "second"}); code != 1 { t.Fatalf("expected cmd run exit code 1, got: %d", code) } @@ -85,4 +93,12 @@ func TestScalingPolicyInfoCommand_Run(t *testing.T) { if out := ui.OutputWriter.String(); !strings.Contains(out, "Policy:") { t.Fatalf("expected policy ID within output: %v", out) } + + prefix := policies[0].ID[:2] + if code := cmd.Run([]string{"-address=" + url, prefix}); code != 0 { + t.Fatalf("expected cmd run exit code 0, got: %d", code) + } + if out := ui.OutputWriter.String(); !strings.Contains(out, "Policy:") { + t.Fatalf("expected policy ID within output: %v", out) + } } diff --git a/command/scaling_policy_list.go b/command/scaling_policy_list.go index e2ecfdb6f715..48d688c61ce8 100644 --- a/command/scaling_policy_list.go +++ b/command/scaling_policy_list.go @@ -42,6 +42,9 @@ Policy Info Options: -type Filter scaling policies by type. + -verbose + Display full information. + -json Output the scaling policy in its JSON format. @@ -59,10 +62,11 @@ func (s *ScalingPolicyListCommand) Synopsis() string { func (s *ScalingPolicyListCommand) AutocompleteFlags() complete.Flags { return mergeAutocompleteFlags(s.Meta.AutocompleteFlags(FlagSetClient), complete.Flags{ - "-job": complete.PredictNothing, - "-type": complete.PredictNothing, - "-json": complete.PredictNothing, - "-t": complete.PredictAnything, + "-verbose": complete.PredictNothing, + "-job": complete.PredictNothing, + "-type": complete.PredictNothing, + "-json": complete.PredictNothing, + "-t": complete.PredictAnything, }) } @@ -71,11 +75,12 @@ func (s *ScalingPolicyListCommand) Name() string { return "scaling policy list" // Run satisfies the cli.Command Run function. func (s *ScalingPolicyListCommand) Run(args []string) int { - var json bool + var json, verbose bool var tmpl, policyType, job string flags := s.Meta.FlagSet(s.Name(), FlagSetClient) flags.Usage = func() { s.Ui.Output(s.Help()) } + flags.BoolVar(&verbose, "verbose", false, "") flags.BoolVar(&json, "json", false, "") flags.StringVar(&tmpl, "t", "", "") flags.StringVar(&policyType, "type", "", "") @@ -90,6 +95,12 @@ func (s *ScalingPolicyListCommand) Run(args []string) int { return 1 } + // Truncate the id unless full length is requested + length := shortId + if verbose { + length = fullId + } + // Get the HTTP client. client, err := s.Meta.Client() if err != nil { @@ -122,12 +133,12 @@ func (s *ScalingPolicyListCommand) Run(args []string) int { return 0 } - output := formatScalingPolicies(policies) + output := formatScalingPolicies(policies, length) s.Ui.Output(output) return 0 } -func formatScalingPolicies(stubs []*api.ScalingPolicyListStub) string { +func formatScalingPolicies(stubs []*api.ScalingPolicyListStub, uuidLength int) string { if len(stubs) == 0 { return "No policies found" } @@ -143,7 +154,10 @@ func formatScalingPolicies(stubs []*api.ScalingPolicyListStub) string { for _, policy := range sortedPolicies.policies { policies = append(policies, fmt.Sprintf( "%s|%v|%s|%s", - policy.ID, policy.Enabled, policy.Type, formatScalingPolicyTarget(policy.Target))) + limit(policy.ID, uuidLength), + policy.Enabled, + policy.Type, + formatScalingPolicyTarget(policy.Target))) } return formatList(policies) } From 2a302c65d99a9bce3d3d2b51eccc9a1629b941e7 Mon Sep 17 00:00:00 2001 From: Chris Baker <1675087+cgbaker@users.noreply.github.com> Date: Thu, 4 Feb 2021 15:11:00 +0000 Subject: [PATCH 6/6] changelog for 9964 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d55860333916..9866903bbfa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,10 @@ FEATURES: * **Terminating Gateways**: Adds built-in support for running Consul Connect terminating gateways [[GH-9829](https://github.com/hashicorp/nomad/pull/9829)] IMPROVEMENTS: + * cli: Improved `scaling policy` commands with -verbose, auto-completion, and prefix-matching [[GH-9964](https://github.com/hashicorp/nomad/issues/9964)] * consul/connect: Made handling of sidecar task container image URLs consistent with the `docker` task driver. [[GH-9580](https://github.com/hashicorp/nomad/issues/9580)] + BUG FIXES: * consul: Fixed a bug where failing tasks with group services would only cause the allocation to restart once instead of respecting the `restart` field. [[GH-9869](https://github.com/hashicorp/nomad/issues/9869)] * consul/connect: Fixed a bug where gateway proxy connection default timeout not set [[GH-9851](https://github.com/hashicorp/nomad/pull/9851)]