diff --git a/.gitignore b/.gitignore index 70040664..8e817a73 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ debug hack/kind/autoscaler .vscode +.idea __debug_bin node_modules /dist diff --git a/cmd/controller.go b/cmd/controller.go index ab33019c..b1047b52 100644 --- a/cmd/controller.go +++ b/cmd/controller.go @@ -31,6 +31,7 @@ var includeNamespaces []string var ignoreControllerKind []string var excludeNamespaces []string var dryRun bool +var vpaRecommenders []string func init() { rootCmd.AddCommand(controllerCmd) @@ -39,6 +40,7 @@ func init() { controllerCmd.PersistentFlags().StringSliceVar(&includeNamespaces, "include-namespaces", []string{}, "Comma delimited list of namespaces to include from recommendations.") controllerCmd.PersistentFlags().StringSliceVar(&excludeNamespaces, "exclude-namespaces", []string{}, "Comma delimited list of namespaces to exclude from recommendations.") controllerCmd.PersistentFlags().StringSliceVar(&ignoreControllerKind, "ignore-controller-kind", []string{}, "Comma delimited list of controller kinds to exclude from recommendations.") + controllerCmd.PersistentFlags().StringSliceVar(&vpaRecommenders, "vpa-recommenders", []string{}, "Comma-separated list of VPA recommender names to set on created VerticalPodAutoscaler resources (autoscaling.k8s.io/v1 spec.recommenders). Empty uses the default recommender.") } var controllerCmd = &cobra.Command{ @@ -51,6 +53,7 @@ var controllerCmd = &cobra.Command{ vpaReconciler.IncludeNamespaces = includeNamespaces vpaReconciler.ExcludeNamespaces = excludeNamespaces vpaReconciler.IgnoreControllerKind = ignoreControllerKind + vpaReconciler.RecommenderNames = vpaRecommenders klog.V(4).Infof("Starting controller with Reconciler: %+v", vpaReconciler) diff --git a/pkg/vpa/vpa.go b/pkg/vpa/vpa.go index 73e0a7c8..002e1565 100644 --- a/pkg/vpa/vpa.go +++ b/pkg/vpa/vpa.go @@ -54,6 +54,7 @@ type Reconciler struct { IncludeNamespaces []string ExcludeNamespaces []string IgnoreControllerKind []string + RecommenderNames []string } type Controller struct { @@ -365,6 +366,7 @@ func (r Reconciler) getVPAObject(existingVPA *vpav1.VerticalPodAutoscaler, ns *c UpdateMode: updateMode, }, ResourcePolicy: resourcePolicy, + Recommenders: recommenderSelectors(r.RecommenderNames), } if minReplicas != nil { @@ -377,6 +379,21 @@ func (r Reconciler) getVPAObject(existingVPA *vpav1.VerticalPodAutoscaler, ns *c return desiredVPA } +func recommenderSelectors(names []string) []*vpav1.VerticalPodAutoscalerRecommenderSelector { + var out []*vpav1.VerticalPodAutoscalerRecommenderSelector + for _, n := range names { + n = strings.TrimSpace(n) + if n == "" { + continue + } + out = append(out, &vpav1.VerticalPodAutoscalerRecommenderSelector{Name: n}) + } + if len(out) == 0 { + return nil + } + return out +} + var allowedUpdateModes = []vpav1.UpdateMode{ vpav1.UpdateModeOff, vpav1.UpdateModeInitial, diff --git a/pkg/vpa/vpa_test.go b/pkg/vpa/vpa_test.go index 08676adb..4614d30c 100644 --- a/pkg/vpa/vpa_test.go +++ b/pkg/vpa/vpa_test.go @@ -158,6 +158,34 @@ func Test_getVPAObject(t *testing.T) { } } +func Test_getVPAObject_recommenders(t *testing.T) { + setupVPAForTests(t) + rec := GetInstance() + t.Cleanup(func() { rec.RecommenderNames = nil }) + + rec.RecommenderNames = []string{"extra-recommender", "another-recommender"} + + mode, _ := vpaUpdateModeForResource(&nsLabeledTrueUpdateModeAuto) + resourcePolicy, _ := vpaResourcePolicyForResource(&nsLabeledTrueUpdateModeAuto) + minReplicas, _ := vpaMinReplicasForResource(&nsLabeledTrueUpdateModeAuto) + controller := Controller{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "hamster", + Unstructured: nil, + } + vpaObj := rec.getVPAObject(nil, &nsLabeledTrueUpdateModeAuto, controller, mode, resourcePolicy, minReplicas) + + a := assert.New(t) + a.Len(vpaObj.Spec.Recommenders, 2) + a.Equal("extra-recommender", vpaObj.Spec.Recommenders[0].Name) + a.Equal("another-recommender", vpaObj.Spec.Recommenders[1].Name) + + rec.RecommenderNames = nil + vpaObj = rec.getVPAObject(nil, &nsLabeledTrueUpdateModeAuto, controller, mode, resourcePolicy, minReplicas) + a.Nil(vpaObj.Spec.Recommenders) +} + func Test_createVPA(t *testing.T) { setupVPAForTests(t) VPAClient := GetInstance().VPAClient