From da8b145980d6d2fed99fff44700face32b92a184 Mon Sep 17 00:00:00 2001 From: Lucas Severo Alves Date: Thu, 1 Dec 2022 15:05:54 +0100 Subject: [PATCH] use plugin registry and prepare for conversion (#1003) * use plugin registry and prepare for conersion * Register plugins explicitly to a registry * check interface impl instead of struc var * setup plugins at top level * treat plugin type combinations * pass registry as arg of V1alpha1ToInternal * move registry yet another level up * check interface type separately --- cmd/descheduler/app/server.go | 6 + cmd/descheduler/descheduler.go | 6 +- pkg/descheduler/descheduler.go | 11 +- pkg/descheduler/descheduler_test.go | 11 +- pkg/descheduler/policyconfig.go | 62 +++++++---- pkg/descheduler/policyconfig_test.go | 4 +- pkg/descheduler/setupplugins.go | 50 +++++++++ pkg/descheduler/strategy_migration.go | 105 ------------------ .../plugins/defaultevictor/defaultevictor.go | 9 +- pkg/framework/plugins/defaultevictor/types.go | 19 ++-- .../defaultevictor/zz_generated.deepcopy.go | 5 +- .../plugins/nodeutilization/types.go | 21 ++-- .../plugins/pluginbuilder/pluginbuilder.go | 48 ++++++++ pkg/framework/plugins/podlifetime/types.go | 10 +- .../plugins/removeduplicates/types.go | 6 +- .../plugins/removefailedpods/types.go | 14 +-- .../removepodshavingtoomanyrestarts/types.go | 10 +- .../types.go | 6 +- .../removepodsviolatingnodeaffinity/types.go | 8 +- .../removepodsviolatingnodetaints/types.go | 10 +- .../types.go | 8 +- test/e2e/e2e_leaderelection_test.go | 1 + 22 files changed, 234 insertions(+), 196 deletions(-) create mode 100644 pkg/descheduler/setupplugins.go create mode 100644 pkg/framework/plugins/pluginbuilder/pluginbuilder.go diff --git a/cmd/descheduler/app/server.go b/cmd/descheduler/app/server.go index ab3e29984..4009f5eff 100644 --- a/cmd/descheduler/app/server.go +++ b/cmd/descheduler/app/server.go @@ -20,6 +20,7 @@ package app import ( "context" "io" + "os" "os/signal" "syscall" @@ -112,3 +113,8 @@ func NewDeschedulerCommand(out io.Writer) *cobra.Command { func Run(ctx context.Context, rs *options.DeschedulerServer) error { return descheduler.Run(ctx, rs) } + +func SetupLogs() { + klog.SetOutput(os.Stdout) + klog.InitFlags(nil) +} diff --git a/cmd/descheduler/descheduler.go b/cmd/descheduler/descheduler.go index e788b4d71..f143a118b 100644 --- a/cmd/descheduler/descheduler.go +++ b/cmd/descheduler/descheduler.go @@ -20,13 +20,13 @@ import ( "os" "k8s.io/component-base/cli" - "k8s.io/klog/v2" "sigs.k8s.io/descheduler/cmd/descheduler/app" + "sigs.k8s.io/descheduler/pkg/descheduler" ) func init() { - klog.SetOutput(os.Stdout) - klog.InitFlags(nil) + app.SetupLogs() + descheduler.SetupPlugins() } func main() { diff --git a/pkg/descheduler/descheduler.go b/pkg/descheduler/descheduler.go index 672c6ebd8..8611e5491 100644 --- a/pkg/descheduler/descheduler.go +++ b/pkg/descheduler/descheduler.go @@ -45,6 +45,7 @@ import ( podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod" "sigs.k8s.io/descheduler/pkg/framework" "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" + "sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder" "sigs.k8s.io/descheduler/pkg/utils" ) @@ -58,7 +59,7 @@ func Run(ctx context.Context, rs *options.DeschedulerServer) error { rs.Client = rsclient rs.EventClient = eventClient - deschedulerPolicy, err := LoadPolicyConfig(rs.PolicyConfigFile, rs.Client) + deschedulerPolicy, err := LoadPolicyConfig(rs.PolicyConfigFile, rs.Client, pluginbuilder.PluginRegistry) if err != nil { return err } @@ -357,11 +358,15 @@ func RunDeschedulerStrategies(ctx context.Context, rs *options.DeschedulerServer klog.ErrorS(fmt.Errorf("unable to get plugin config"), "skipping plugin", "plugin", plugin) continue } - pgFnc, ok := pluginsMap[plugin] + registryPlugin, ok := pluginbuilder.PluginRegistry[plugin] + pgFnc := registryPlugin.PluginBuilder if !ok { klog.ErrorS(fmt.Errorf("unable to find plugin in the pluginsMap"), "skipping plugin", "plugin", plugin) } - pg := pgFnc(pc.Args, handle) + pg, err := pgFnc(pc.Args, handle) + if err != nil { + klog.ErrorS(err, "unable to initialize a plugin", "pluginName", plugin) + } if pg != nil { switch v := pg.(type) { case framework.DeschedulePlugin: diff --git a/pkg/descheduler/descheduler_test.go b/pkg/descheduler/descheduler_test.go index e2f6b3bf2..c00512f7b 100644 --- a/pkg/descheduler/descheduler_test.go +++ b/pkg/descheduler/descheduler_test.go @@ -15,10 +15,15 @@ import ( "sigs.k8s.io/descheduler/cmd/descheduler/app/options" "sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api/v1alpha1" + "sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingnodetaints" "sigs.k8s.io/descheduler/test" ) func TestTaintsUpdated(t *testing.T) { + pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry() + pluginbuilder.Register(removepodsviolatingnodetaints.PluginName, removepodsviolatingnodetaints.New, &removepodsviolatingnodetaints.RemovePodsViolatingNodeTaintsArgs{}, pluginbuilder.PluginRegistry) ctx := context.Background() n1 := test.BuildTestNode("n1", 2000, 3000, 10, nil) n2 := test.BuildTestNode("n2", 2000, 3000, 10, nil) @@ -69,7 +74,7 @@ func TestTaintsUpdated(t *testing.T) { var evictedPods []string client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods)) - internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp) + internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp, pluginbuilder.PluginRegistry) if err != nil { t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err) } @@ -84,6 +89,8 @@ func TestTaintsUpdated(t *testing.T) { } func TestDuplicate(t *testing.T) { + pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry() + pluginbuilder.Register(removeduplicates.PluginName, removeduplicates.New, &removeduplicates.RemoveDuplicatesArgs{}, pluginbuilder.PluginRegistry) ctx := context.Background() node1 := test.BuildTestNode("n1", 2000, 3000, 10, nil) node2 := test.BuildTestNode("n2", 2000, 3000, 10, nil) @@ -129,7 +136,7 @@ func TestDuplicate(t *testing.T) { var evictedPods []string client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods)) - internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp) + internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp, pluginbuilder.PluginRegistry) if err != nil { t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err) } diff --git a/pkg/descheduler/policyconfig.go b/pkg/descheduler/policyconfig.go index dab515be1..080140229 100644 --- a/pkg/descheduler/policyconfig.go +++ b/pkg/descheduler/policyconfig.go @@ -28,11 +28,13 @@ import ( "sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api/v1alpha1" "sigs.k8s.io/descheduler/pkg/descheduler/scheme" + "sigs.k8s.io/descheduler/pkg/framework" "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" + "sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder" "sigs.k8s.io/descheduler/pkg/utils" ) -func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api.DeschedulerPolicy, error) { +func LoadPolicyConfig(policyConfigFile string, client clientset.Interface, registry pluginbuilder.Registry) (*api.DeschedulerPolicy, error) { if policyConfigFile == "" { klog.V(1).InfoS("Policy config file not specified") return nil, nil @@ -51,8 +53,7 @@ func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api } // Build profiles - // TODO(jchaloup): replace this with v1alpha1 -> v1alpha2 conversion - internalPolicy, err := V1alpha1ToInternal(client, versionedPolicy) + internalPolicy, err := V1alpha1ToInternal(client, versionedPolicy, registry) if err != nil { return nil, fmt.Errorf("failed converting versioned policy to internal policy version: %v", err) } @@ -63,20 +64,8 @@ func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api func V1alpha1ToInternal( client clientset.Interface, deschedulerPolicy *v1alpha1.DeschedulerPolicy, + registry pluginbuilder.Registry, ) (*api.DeschedulerPolicy, error) { - validStrategyNames := map[v1alpha1.StrategyName]interface{}{ - "RemoveDuplicates": nil, - "LowNodeUtilization": nil, - "HighNodeUtilization": nil, - "RemovePodsViolatingInterPodAntiAffinity": nil, - "RemovePodsViolatingNodeAffinity": nil, - "RemovePodsViolatingNodeTaints": nil, - "RemovePodsHavingTooManyRestarts": nil, - "PodLifeTime": nil, - "RemovePodsViolatingTopologySpreadConstraint": nil, - "RemoveFailedPods": nil, - } - var evictLocalStoragePods bool if deschedulerPolicy.EvictLocalStoragePods != nil { evictLocalStoragePods = *deschedulerPolicy.EvictLocalStoragePods @@ -107,7 +96,7 @@ func V1alpha1ToInternal( // Build profiles for name, strategy := range deschedulerPolicy.Strategies { - if _, ok := validStrategyNames[name]; ok { + if _, ok := pluginbuilder.PluginRegistry[string(name)]; ok { if strategy.Enabled { params := strategy.Params if params == nil { @@ -175,13 +164,16 @@ func V1alpha1ToInternal( }, } - // Plugins have either of the two extension points - switch pluginToExtensionPoint[pluginConfig.Name] { - case descheduleEP: - profile.Plugins.Deschedule.Enabled = []string{pluginConfig.Name} - case balanceEP: - profile.Plugins.Balance.Enabled = []string{pluginConfig.Name} + pluginArgs := registry[string(name)].PluginArgInstance + pluginInstance, err := registry[string(name)].PluginBuilder(pluginArgs, &handleImpl{}) + if err != nil { + klog.ErrorS(fmt.Errorf("could not build plugin"), "plugin build error", "plugin", name) + return nil, fmt.Errorf("could not build plugin: %v", name) } + + // pluginInstance can be of any of each type, or both + profilePlugins := profile.Plugins + profile.Plugins = enableProfilePluginsByType(profilePlugins, pluginInstance, pluginConfig) profiles = append(profiles, profile) } } else { @@ -197,3 +189,27 @@ func V1alpha1ToInternal( MaxNoOfPodsToEvictPerNamespace: deschedulerPolicy.MaxNoOfPodsToEvictPerNamespace, }, nil } + +func enableProfilePluginsByType(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins { + profilePlugins = checkBalance(profilePlugins, pluginInstance, pluginConfig) + profilePlugins = checkDeschedule(profilePlugins, pluginInstance, pluginConfig) + return profilePlugins +} + +func checkBalance(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins { + switch p := pluginInstance.(type) { + case framework.BalancePlugin: + klog.V(3).Info("converting Balance plugin: %s", p.Name()) + profilePlugins.Balance.Enabled = []string{pluginConfig.Name} + } + return profilePlugins +} + +func checkDeschedule(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins { + switch p := pluginInstance.(type) { + case framework.DeschedulePlugin: + klog.V(3).Info("converting Deschedule plugin: %s", p.Name()) + profilePlugins.Deschedule.Enabled = []string{pluginConfig.Name} + } + return profilePlugins +} diff --git a/pkg/descheduler/policyconfig_test.go b/pkg/descheduler/policyconfig_test.go index 6e3d38195..26922fc05 100644 --- a/pkg/descheduler/policyconfig_test.go +++ b/pkg/descheduler/policyconfig_test.go @@ -27,6 +27,7 @@ import ( "sigs.k8s.io/descheduler/pkg/api/v1alpha1" "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" "sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization" + "sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder" "sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates" "sigs.k8s.io/descheduler/pkg/framework/plugins/removefailedpods" "sigs.k8s.io/descheduler/pkg/framework/plugins/removepodshavingtoomanyrestarts" @@ -38,6 +39,7 @@ import ( ) func TestV1alpha1ToV1alpha2(t *testing.T) { + SetupPlugins() defaultEvictorPluginConfig := api.PluginConfig{ Name: defaultevictor.PluginName, Args: &defaultevictor.DefaultEvictorArgs{ @@ -680,7 +682,7 @@ func TestV1alpha1ToV1alpha2(t *testing.T) { for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { client := fakeclientset.NewSimpleClientset() - result, err := V1alpha1ToInternal(client, tc.policy) + result, err := V1alpha1ToInternal(client, tc.policy, pluginbuilder.PluginRegistry) if err != nil { if err.Error() != tc.err.Error() { t.Errorf("unexpected error: %s", err.Error()) diff --git a/pkg/descheduler/setupplugins.go b/pkg/descheduler/setupplugins.go new file mode 100644 index 000000000..35cf01b12 --- /dev/null +++ b/pkg/descheduler/setupplugins.go @@ -0,0 +1,50 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package descheduler + +import ( + "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" + "sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization" + "sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder" + "sigs.k8s.io/descheduler/pkg/framework/plugins/podlifetime" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removefailedpods" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removepodshavingtoomanyrestarts" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingnodeaffinity" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingnodetaints" + "sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint" +) + +func SetupPlugins() { + pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry() + RegisterDefaultPlugins(pluginbuilder.PluginRegistry) +} + +func RegisterDefaultPlugins(registry pluginbuilder.Registry) { + pluginbuilder.Register(defaultevictor.PluginName, defaultevictor.New, &defaultevictor.DefaultEvictorArgs{}, registry) + pluginbuilder.Register(nodeutilization.LowNodeUtilizationPluginName, nodeutilization.NewLowNodeUtilization, &nodeutilization.LowNodeUtilizationArgs{}, registry) + pluginbuilder.Register(nodeutilization.HighNodeUtilizationPluginName, nodeutilization.NewHighNodeUtilization, &nodeutilization.HighNodeUtilizationArgs{}, registry) + pluginbuilder.Register(podlifetime.PluginName, podlifetime.New, &podlifetime.PodLifeTimeArgs{}, registry) + pluginbuilder.Register(removeduplicates.PluginName, removeduplicates.New, &removeduplicates.RemoveDuplicatesArgs{}, registry) + pluginbuilder.Register(removefailedpods.PluginName, removefailedpods.New, &removefailedpods.RemoveFailedPodsArgs{}, registry) + pluginbuilder.Register(removepodshavingtoomanyrestarts.PluginName, removepodshavingtoomanyrestarts.New, &removepodshavingtoomanyrestarts.RemovePodsHavingTooManyRestartsArgs{}, registry) + pluginbuilder.Register(removepodsviolatinginterpodantiaffinity.PluginName, removepodsviolatinginterpodantiaffinity.New, &removepodsviolatinginterpodantiaffinity.RemovePodsViolatingInterPodAntiAffinityArgs{}, registry) + pluginbuilder.Register(removepodsviolatingnodeaffinity.PluginName, removepodsviolatingnodeaffinity.New, &removepodsviolatingnodeaffinity.RemovePodsViolatingNodeAffinityArgs{}, registry) + pluginbuilder.Register(removepodsviolatingnodetaints.PluginName, removepodsviolatingnodetaints.New, &removepodsviolatingnodetaints.RemovePodsViolatingNodeTaintsArgs{}, registry) + pluginbuilder.Register(removepodsviolatingtopologyspreadconstraint.PluginName, removepodsviolatingtopologyspreadconstraint.New, &removepodsviolatingtopologyspreadconstraint.RemovePodsViolatingTopologySpreadConstraintArgs{}, registry) +} diff --git a/pkg/descheduler/strategy_migration.go b/pkg/descheduler/strategy_migration.go index 64e98e2d7..09fafac9d 100644 --- a/pkg/descheduler/strategy_migration.go +++ b/pkg/descheduler/strategy_migration.go @@ -19,11 +19,9 @@ package descheduler import ( "fmt" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/klog/v2" "sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api/v1alpha1" - "sigs.k8s.io/descheduler/pkg/framework" "sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization" "sigs.k8s.io/descheduler/pkg/framework/plugins/podlifetime" "sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates" @@ -250,106 +248,3 @@ func v1alpha1ThresholdToInternal(thresholds v1alpha1.ResourceThresholds) api.Res } return internal } - -type extensionPoint string - -const ( - descheduleEP extensionPoint = "deschedule" - balanceEP extensionPoint = "balance" -) - -var pluginToExtensionPoint = map[string]extensionPoint{ - removepodsviolatingnodetaints.PluginName: descheduleEP, - removefailedpods.PluginName: descheduleEP, - removepodsviolatingnodeaffinity.PluginName: descheduleEP, - removepodsviolatinginterpodantiaffinity.PluginName: descheduleEP, - removepodshavingtoomanyrestarts.PluginName: descheduleEP, - podlifetime.PluginName: descheduleEP, - removeduplicates.PluginName: balanceEP, - removepodsviolatingtopologyspreadconstraint.PluginName: balanceEP, - nodeutilization.HighNodeUtilizationPluginName: balanceEP, - nodeutilization.LowNodeUtilizationPluginName: balanceEP, -} - -var pluginsMap = map[string]func(args runtime.Object, handle *handleImpl) framework.Plugin{ - removepodsviolatingnodetaints.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := removepodsviolatingnodetaints.New(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingnodetaints.PluginName) - return nil - } - return pg - }, - removefailedpods.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := removefailedpods.New(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removefailedpods.PluginName) - return nil - } - return pg - }, - removepodsviolatingnodeaffinity.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := removepodsviolatingnodeaffinity.New(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingnodeaffinity.PluginName) - return nil - } - return pg - }, - removepodsviolatinginterpodantiaffinity.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := removepodsviolatinginterpodantiaffinity.New(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatinginterpodantiaffinity.PluginName) - return nil - } - return pg - }, - removepodshavingtoomanyrestarts.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := removepodshavingtoomanyrestarts.New(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodshavingtoomanyrestarts.PluginName) - return nil - } - return pg - }, - podlifetime.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := podlifetime.New(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", podlifetime.PluginName) - return nil - } - return pg - }, - removeduplicates.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := removeduplicates.New(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removeduplicates.PluginName) - return nil - } - return pg - }, - removepodsviolatingtopologyspreadconstraint.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := removepodsviolatingtopologyspreadconstraint.New(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingtopologyspreadconstraint.PluginName) - return nil - } - return pg - }, - nodeutilization.HighNodeUtilizationPluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := nodeutilization.NewHighNodeUtilization(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", nodeutilization.HighNodeUtilizationPluginName) - return nil - } - return pg - }, - nodeutilization.LowNodeUtilizationPluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin { - pg, err := nodeutilization.NewLowNodeUtilization(args, handle) - if err != nil { - klog.ErrorS(err, "unable to initialize a plugin", "pluginName", nodeutilization.LowNodeUtilizationPluginName) - return nil - } - return pg - }, -} diff --git a/pkg/framework/plugins/defaultevictor/defaultevictor.go b/pkg/framework/plugins/defaultevictor/defaultevictor.go index 19c4ade82..ab0bbab7a 100644 --- a/pkg/framework/plugins/defaultevictor/defaultevictor.go +++ b/pkg/framework/plugins/defaultevictor/defaultevictor.go @@ -19,6 +19,7 @@ import ( "fmt" v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/errors" @@ -129,9 +130,13 @@ func New(args runtime.Object, handle framework.Handle) (framework.Plugin, error) return nil }) } - if defaultEvictorArgs.LabelSelector != nil && !defaultEvictorArgs.LabelSelector.Empty() { + selector, err := metav1.LabelSelectorAsSelector(defaultEvictorArgs.LabelSelector) + if err != nil { + return nil, fmt.Errorf("could not get selector from label selector") + } + if defaultEvictorArgs.LabelSelector != nil && !selector.Empty() { ev.constraints = append(ev.constraints, func(pod *v1.Pod) error { - if !defaultEvictorArgs.LabelSelector.Matches(labels.Set(pod.Labels)) { + if !selector.Matches(labels.Set(pod.Labels)) { return fmt.Errorf("pod labels do not match the labelSelector filter in the policy parameter") } return nil diff --git a/pkg/framework/plugins/defaultevictor/types.go b/pkg/framework/plugins/defaultevictor/types.go index 24bf0b251..0f9b4f66d 100644 --- a/pkg/framework/plugins/defaultevictor/types.go +++ b/pkg/framework/plugins/defaultevictor/types.go @@ -15,7 +15,6 @@ package defaultevictor import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/descheduler/pkg/api" ) @@ -24,14 +23,14 @@ import ( // DefaultEvictorArgs holds arguments used to configure DefaultEvictor plugin. type DefaultEvictorArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - NodeSelector string - EvictLocalStoragePods bool - EvictSystemCriticalPods bool - IgnorePvcPods bool - EvictFailedBarePods bool - LabelSelector labels.Selector - PriorityThreshold *api.PriorityThreshold - NodeFit bool + NodeSelector string `json:"nodeSelector"` + EvictLocalStoragePods bool `json:"evictLocalStoragePods"` + EvictSystemCriticalPods bool `json:"evictSystemCriticalPods"` + IgnorePvcPods bool `json:"ignorePvcPods"` + EvictFailedBarePods bool `json:"evictFailedBarePods"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` + PriorityThreshold *api.PriorityThreshold `json:"priorityThreshold"` + NodeFit bool `json:"nodeFit"` } diff --git a/pkg/framework/plugins/defaultevictor/zz_generated.deepcopy.go b/pkg/framework/plugins/defaultevictor/zz_generated.deepcopy.go index a9ff801aa..ed30617fb 100644 --- a/pkg/framework/plugins/defaultevictor/zz_generated.deepcopy.go +++ b/pkg/framework/plugins/defaultevictor/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ limitations under the License. package defaultevictor import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" api "sigs.k8s.io/descheduler/pkg/api" ) @@ -31,7 +32,9 @@ func (in *DefaultEvictorArgs) DeepCopyInto(out *DefaultEvictorArgs) { *out = *in out.TypeMeta = in.TypeMeta if in.LabelSelector != nil { - out.LabelSelector = in.LabelSelector.DeepCopySelector() + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) } if in.PriorityThreshold != nil { in, out := &in.PriorityThreshold, &out.PriorityThreshold diff --git a/pkg/framework/plugins/nodeutilization/types.go b/pkg/framework/plugins/nodeutilization/types.go index 8bdd694c1..81b98aaf8 100644 --- a/pkg/framework/plugins/nodeutilization/types.go +++ b/pkg/framework/plugins/nodeutilization/types.go @@ -22,28 +22,29 @@ import ( // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type LowNodeUtilizationArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` + + UseDeviationThresholds bool `json:"useDeviationThresholds"` + Thresholds api.ResourceThresholds `json:"thresholds"` + TargetThresholds api.ResourceThresholds `json:"targetThresholds"` + NumberOfNodes int `json:"numberOfNodes"` - UseDeviationThresholds bool - Thresholds api.ResourceThresholds - TargetThresholds api.ResourceThresholds - NumberOfNodes int // Naming this one differently since namespaces are still // considered while considering resoures used by pods // but then filtered out before eviction - EvictableNamespaces *api.Namespaces + EvictableNamespaces *api.Namespaces `json:"evictableNamespaces"` } // +k8s:deepcopy-gen=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type HighNodeUtilizationArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Thresholds api.ResourceThresholds - NumberOfNodes int + Thresholds api.ResourceThresholds `json:"thresholds"` + NumberOfNodes int `json:"numberOfNodes"` // Naming this one differently since namespaces are still // considered while considering resoures used by pods // but then filtered out before eviction - EvictableNamespaces *api.Namespaces + EvictableNamespaces *api.Namespaces `json:"evictableNamespaces"` } diff --git a/pkg/framework/plugins/pluginbuilder/pluginbuilder.go b/pkg/framework/plugins/pluginbuilder/pluginbuilder.go new file mode 100644 index 000000000..d7971f462 --- /dev/null +++ b/pkg/framework/plugins/pluginbuilder/pluginbuilder.go @@ -0,0 +1,48 @@ +/* +Copyright 2022 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pluginbuilder + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "sigs.k8s.io/descheduler/pkg/framework" +) + +var PluginRegistry Registry + +type PluginBuilderAndArgsInstance struct { + PluginBuilder PluginBuilder + // Just an example instance of this PluginArg so we can avoid having + // to deal with reflect Types + PluginArgInstance runtime.Object +} + +type PluginBuilder = func(args runtime.Object, handle framework.Handle) (framework.Plugin, error) + +type Registry = map[string]PluginBuilderAndArgsInstance + +func NewRegistry() Registry { + return Registry{} +} + +func Register(name string, builderFunc PluginBuilder, exampleArg runtime.Object, registry Registry) { + if _, ok := registry[name]; ok { + klog.V(10).InfoS("Plugin already registered", "plugin", name) + } else { + registry[name] = PluginBuilderAndArgsInstance{ + PluginBuilder: builderFunc, + PluginArgInstance: exampleArg, + } + } +} diff --git a/pkg/framework/plugins/podlifetime/types.go b/pkg/framework/plugins/podlifetime/types.go index c95d0ea3d..8c3079f57 100644 --- a/pkg/framework/plugins/podlifetime/types.go +++ b/pkg/framework/plugins/podlifetime/types.go @@ -23,10 +23,10 @@ import ( // PodLifeTimeArgs holds arguments used to configure PodLifeTime plugin. type PodLifeTimeArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces - LabelSelector *metav1.LabelSelector - MaxPodLifeTimeSeconds *uint - States []string + Namespaces *api.Namespaces `json:"namespaces"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` + MaxPodLifeTimeSeconds *uint `json:"maxPodLifeTimeSeconds"` + States []string `json:"states"` } diff --git a/pkg/framework/plugins/removeduplicates/types.go b/pkg/framework/plugins/removeduplicates/types.go index 981ddba0e..759a48a33 100644 --- a/pkg/framework/plugins/removeduplicates/types.go +++ b/pkg/framework/plugins/removeduplicates/types.go @@ -22,8 +22,8 @@ import ( // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type RemoveDuplicatesArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces - ExcludeOwnerKinds []string + Namespaces *api.Namespaces `json:"namespaces"` + ExcludeOwnerKinds []string `json:"excludeOwnerKinds"` } diff --git a/pkg/framework/plugins/removefailedpods/types.go b/pkg/framework/plugins/removefailedpods/types.go index 985f83398..313021a79 100644 --- a/pkg/framework/plugins/removefailedpods/types.go +++ b/pkg/framework/plugins/removefailedpods/types.go @@ -23,12 +23,12 @@ import ( // RemoveFailedPodsArgs holds arguments used to configure RemoveFailedPods plugin. type RemoveFailedPodsArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces - LabelSelector *metav1.LabelSelector - ExcludeOwnerKinds []string - MinPodLifetimeSeconds *uint - Reasons []string - IncludingInitContainers bool + Namespaces *api.Namespaces `json:"namespaces"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` + ExcludeOwnerKinds []string `json:"excludeOwnerKinds"` + MinPodLifetimeSeconds *uint `json:"minPodLifetimeSeconds"` + Reasons []string `json:"reasons"` + IncludingInitContainers bool `json:"includingInitContainers"` } diff --git a/pkg/framework/plugins/removepodshavingtoomanyrestarts/types.go b/pkg/framework/plugins/removepodshavingtoomanyrestarts/types.go index bc159a31a..45c29f252 100644 --- a/pkg/framework/plugins/removepodshavingtoomanyrestarts/types.go +++ b/pkg/framework/plugins/removepodshavingtoomanyrestarts/types.go @@ -23,10 +23,10 @@ import ( // RemovePodsHavingTooManyRestartsArgs holds arguments used to configure RemovePodsHavingTooManyRestarts plugin. type RemovePodsHavingTooManyRestartsArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces - LabelSelector *metav1.LabelSelector - PodRestartThreshold int32 - IncludingInitContainers bool + Namespaces *api.Namespaces `json:"namespaces"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` + PodRestartThreshold int32 `json:"podRestartThreshold"` + IncludingInitContainers bool `json:"includingInitContainers"` } diff --git a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/types.go b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/types.go index fbaa585cf..7ae5cb237 100644 --- a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/types.go +++ b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/types.go @@ -26,8 +26,8 @@ import ( // RemovePodsViolatingInterPodAntiAffinity holds arguments used to configure RemovePodsViolatingInterPodAntiAffinity plugin. type RemovePodsViolatingInterPodAntiAffinityArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces - LabelSelector *metav1.LabelSelector + Namespaces *api.Namespaces `json:"namespaces"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` } diff --git a/pkg/framework/plugins/removepodsviolatingnodeaffinity/types.go b/pkg/framework/plugins/removepodsviolatingnodeaffinity/types.go index a0836d81b..c167ab479 100644 --- a/pkg/framework/plugins/removepodsviolatingnodeaffinity/types.go +++ b/pkg/framework/plugins/removepodsviolatingnodeaffinity/types.go @@ -26,9 +26,9 @@ import ( // RemovePodsViolatingNodeAffinityArgs holds arguments used to configure RemovePodsViolatingNodeAffinity plugin. type RemovePodsViolatingNodeAffinityArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces - LabelSelector *metav1.LabelSelector - NodeAffinityType []string + Namespaces *api.Namespaces `json:"namespaces"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` + NodeAffinityType []string `json:"nodeAffinityType"` } diff --git a/pkg/framework/plugins/removepodsviolatingnodetaints/types.go b/pkg/framework/plugins/removepodsviolatingnodetaints/types.go index 41a72b21f..06d146048 100644 --- a/pkg/framework/plugins/removepodsviolatingnodetaints/types.go +++ b/pkg/framework/plugins/removepodsviolatingnodetaints/types.go @@ -26,10 +26,10 @@ import ( // RemovePodsViolatingNodeTaintsArgs holds arguments used to configure the RemovePodsViolatingNodeTaints plugin. type RemovePodsViolatingNodeTaintsArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces - LabelSelector *metav1.LabelSelector - IncludePreferNoSchedule bool - ExcludedTaints []string + Namespaces *api.Namespaces `json:"namespaces"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` + IncludePreferNoSchedule bool `json:"includePreferNoSchedule"` + ExcludedTaints []string `json:"excludedTaints"` } diff --git a/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/types.go b/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/types.go index 40f2dec86..a661608b9 100644 --- a/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/types.go +++ b/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/types.go @@ -26,9 +26,9 @@ import ( // RemovePodsViolatingTopologySpreadConstraintArgs holds arguments used to configure RemovePodsViolatingTopologySpreadConstraint plugin. type RemovePodsViolatingTopologySpreadConstraintArgs struct { - metav1.TypeMeta + metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces - LabelSelector *metav1.LabelSelector - IncludeSoftConstraints bool + Namespaces *api.Namespaces `json:"namespaces"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` + IncludeSoftConstraints bool `json:"includeSoftConstraints"` } diff --git a/test/e2e/e2e_leaderelection_test.go b/test/e2e/e2e_leaderelection_test.go index e92c4321e..4c43aa8de 100644 --- a/test/e2e/e2e_leaderelection_test.go +++ b/test/e2e/e2e_leaderelection_test.go @@ -38,6 +38,7 @@ import ( ) func TestLeaderElection(t *testing.T) { + descheduler.SetupPlugins() ctx := context.Background() clientSet, _, _, _, stopCh := initializeClient(t)