From 137f3b20dc098d7d6afc05a0a1bb440deb84cf17 Mon Sep 17 00:00:00 2001 From: Lucas Severo Alves Date: Tue, 17 Jan 2023 17:10:34 +0100 Subject: [PATCH] add v1alpha2 registry based conversion (#1006) * add v1alpha2 registry based conversion * test defaults, set our 1st explicit default * fix typos and dates * move pluginregistry to its own dir * remove unused v1alpha2.Namespace type * move migration code folders, remove switch * validate internalPolicy a single time * remove structured logs * simplify return * check for nil methods * properly check before adding default evictor * add TODO comment * bump copyright year --- pkg/api/conversion.go | 17 + pkg/api/v1alpha1/conversion.go | 244 ++++++++++++++ .../v1alpha1/strategymigration.go} | 41 ++- .../v1alpha1/strategymigration_test.go} | 225 +++++++------ pkg/api/v1alpha2/conversion.go | 136 ++++++++ pkg/api/v1alpha2/defaults.go | 23 ++ pkg/api/v1alpha2/doc.go | 24 ++ pkg/api/v1alpha2/register.go | 61 ++++ pkg/api/v1alpha2/sort.go | 26 ++ pkg/api/v1alpha2/types.go | 66 ++++ pkg/api/v1alpha2/zz_generated.conversion.go | 277 ++++++++++++++++ pkg/api/v1alpha2/zz_generated.deepcopy.go | 163 ++++++++++ pkg/api/v1alpha2/zz_generated.defaults.go | 33 ++ pkg/descheduler/descheduler.go | 38 ++- pkg/descheduler/descheduler_test.go | 14 +- pkg/descheduler/policyconfig.go | 245 ++++++-------- pkg/descheduler/policyconfig_test.go | 304 +++++++++++++++++- pkg/descheduler/scheme/scheme.go | 28 +- pkg/descheduler/setupplugins.go | 30 +- .../pluginregistry.go} | 30 +- .../plugins/defaultevictor/defaults.go | 35 +- .../plugins/defaultevictor/validation.go | 30 ++ .../defaultevictor/zz_generated.defaults.go | 5 - .../plugins/nodeutilization/defaults.go | 30 +- .../plugins/nodeutilization/validation.go | 7 +- .../nodeutilization/zz_generated.defaults.go | 10 - pkg/framework/plugins/podlifetime/defaults.go | 19 +- .../plugins/podlifetime/validation.go | 5 +- .../podlifetime/zz_generated.defaults.go | 5 - .../plugins/removeduplicates/defaults.go | 11 +- .../plugins/removeduplicates/validation.go | 5 +- .../removeduplicates/zz_generated.defaults.go | 5 - .../plugins/removefailedpods/defaults.go | 28 +- .../plugins/removefailedpods/validation.go | 4 +- .../removefailedpods/zz_generated.defaults.go | 5 - .../defaults.go | 19 +- .../validation.go | 4 +- .../zz_generated.defaults.go | 7 - .../defaults.go | 11 +- .../validation.go | 4 +- .../zz_generated.defaults.go | 7 - .../defaults.go | 11 +- .../validation.go | 4 +- .../zz_generated.defaults.go | 7 - .../removepodsviolatingnodetaints/defaults.go | 19 +- .../validation.go | 4 +- .../zz_generated.defaults.go | 7 - .../defaults.go | 15 +- .../validation.go | 4 +- .../zz_generated.defaults.go | 7 - 50 files changed, 1867 insertions(+), 492 deletions(-) create mode 100644 pkg/api/conversion.go create mode 100644 pkg/api/v1alpha1/conversion.go rename pkg/{descheduler/strategy_migration.go => api/v1alpha1/strategymigration.go} (85%) rename pkg/{descheduler/strategy_migration_test.go => api/v1alpha1/strategymigration_test.go} (79%) create mode 100644 pkg/api/v1alpha2/conversion.go create mode 100644 pkg/api/v1alpha2/defaults.go create mode 100644 pkg/api/v1alpha2/doc.go create mode 100644 pkg/api/v1alpha2/register.go create mode 100644 pkg/api/v1alpha2/sort.go create mode 100644 pkg/api/v1alpha2/types.go create mode 100644 pkg/api/v1alpha2/zz_generated.conversion.go create mode 100644 pkg/api/v1alpha2/zz_generated.deepcopy.go create mode 100644 pkg/api/v1alpha2/zz_generated.defaults.go rename pkg/framework/{plugins/pluginbuilder/pluginbuilder.go => pluginregistry/pluginregistry.go} (62%) create mode 100644 pkg/framework/plugins/defaultevictor/validation.go diff --git a/pkg/api/conversion.go b/pkg/api/conversion.go new file mode 100644 index 000000000..0f4f59e71 --- /dev/null +++ b/pkg/api/conversion.go @@ -0,0 +1,17 @@ +/* +Copyright 2023 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 api diff --git a/pkg/api/v1alpha1/conversion.go b/pkg/api/v1alpha1/conversion.go new file mode 100644 index 000000000..a805e3b9b --- /dev/null +++ b/pkg/api/v1alpha1/conversion.go @@ -0,0 +1,244 @@ +/* +Copyright 2023 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 v1alpha1 + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/client-go/informers" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" + "sigs.k8s.io/descheduler/pkg/api" + "sigs.k8s.io/descheduler/pkg/descheduler/evictions" + podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod" + "sigs.k8s.io/descheduler/pkg/framework" + "sigs.k8s.io/descheduler/pkg/framework/pluginregistry" + "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" + "sigs.k8s.io/descheduler/pkg/utils" +) + +// evictorImpl implements the Evictor interface so plugins +// can evict a pod without importing a specific pod evictor +type evictorImpl struct { + podEvictor *evictions.PodEvictor + evictorFilter framework.EvictorPlugin +} + +var _ framework.Evictor = &evictorImpl{} + +// Filter checks if a pod can be evicted +func (ei *evictorImpl) Filter(pod *v1.Pod) bool { + return ei.evictorFilter.Filter(pod) +} + +// PreEvictionFilter checks if pod can be evicted right before eviction +func (ei *evictorImpl) PreEvictionFilter(pod *v1.Pod) bool { + return ei.evictorFilter.PreEvictionFilter(pod) +} + +// Evict evicts a pod (no pre-check performed) +func (ei *evictorImpl) Evict(ctx context.Context, pod *v1.Pod, opts evictions.EvictOptions) bool { + return ei.podEvictor.EvictPod(ctx, pod, opts) +} + +func (ei *evictorImpl) NodeLimitExceeded(node *v1.Node) bool { + return ei.podEvictor.NodeLimitExceeded(node) +} + +// handleImpl implements the framework handle which gets passed to plugins +type handleImpl struct { + clientSet clientset.Interface + getPodsAssignedToNodeFunc podutil.GetPodsAssignedToNodeFunc + sharedInformerFactory informers.SharedInformerFactory + evictor *evictorImpl +} + +var _ framework.Handle = &handleImpl{} + +// ClientSet retrieves kube client set +func (hi *handleImpl) ClientSet() clientset.Interface { + return hi.clientSet +} + +// GetPodsAssignedToNodeFunc retrieves GetPodsAssignedToNodeFunc implementation +func (hi *handleImpl) GetPodsAssignedToNodeFunc() podutil.GetPodsAssignedToNodeFunc { + return hi.getPodsAssignedToNodeFunc +} + +// SharedInformerFactory retrieves shared informer factory +func (hi *handleImpl) SharedInformerFactory() informers.SharedInformerFactory { + return hi.sharedInformerFactory +} + +// Evictor retrieves evictor so plugins can filter and evict pods +func (hi *handleImpl) Evictor() framework.Evictor { + return hi.evictor +} + +func V1alpha1ToInternal( + client clientset.Interface, + deschedulerPolicy *DeschedulerPolicy, + registry pluginregistry.Registry, +) (*api.DeschedulerPolicy, error) { + var evictLocalStoragePods bool + if deschedulerPolicy.EvictLocalStoragePods != nil { + evictLocalStoragePods = *deschedulerPolicy.EvictLocalStoragePods + } + + evictBarePods := false + if deschedulerPolicy.EvictFailedBarePods != nil { + evictBarePods = *deschedulerPolicy.EvictFailedBarePods + if evictBarePods { + klog.V(1).Info("Warning: EvictFailedBarePods is set to True. This could cause eviction of pods without ownerReferences.") + } + } + + evictSystemCriticalPods := false + if deschedulerPolicy.EvictSystemCriticalPods != nil { + evictSystemCriticalPods = *deschedulerPolicy.EvictSystemCriticalPods + if evictSystemCriticalPods { + klog.V(1).Info("Warning: EvictSystemCriticalPods is set to True. This could cause eviction of Kubernetes system pods.") + } + } + + ignorePvcPods := false + if deschedulerPolicy.IgnorePVCPods != nil { + ignorePvcPods = *deschedulerPolicy.IgnorePVCPods + } + + var profiles []api.Profile + + // Build profiles + for name, strategy := range deschedulerPolicy.Strategies { + if _, ok := pluginregistry.PluginRegistry[string(name)]; ok { + if strategy.Enabled { + params := strategy.Params + if params == nil { + params = &StrategyParameters{} + } + + nodeFit := false + if name != "PodLifeTime" { + nodeFit = params.NodeFit + } + + if params.ThresholdPriority != nil && params.ThresholdPriorityClassName != "" { + klog.ErrorS(fmt.Errorf("priority threshold misconfigured"), "only one of priorityThreshold fields can be set", "pluginName", name) + return nil, fmt.Errorf("priority threshold misconfigured for plugin %v", name) + } + + var priorityThreshold *api.PriorityThreshold + if strategy.Params != nil { + priorityThreshold = &api.PriorityThreshold{ + Value: strategy.Params.ThresholdPriority, + Name: strategy.Params.ThresholdPriorityClassName, + } + } + thresholdPriority, err := utils.GetPriorityFromStrategyParams(context.TODO(), client, priorityThreshold) + if err != nil { + klog.ErrorS(err, "Failed to get threshold priority from strategy's params") + return nil, fmt.Errorf("failed to get threshold priority from strategy's params: %v", err) + } + + var pluginConfig *api.PluginConfig + if pcFnc, exists := StrategyParamsToPluginArgs[string(name)]; exists { + pluginConfig, err = pcFnc(params) + if err != nil { + klog.ErrorS(err, "skipping strategy", "strategy", name) + return nil, fmt.Errorf("failed to get plugin config for strategy %v: %v", name, err) + } + } else { + klog.ErrorS(fmt.Errorf("unknown strategy name"), "skipping strategy", "strategy", name) + return nil, fmt.Errorf("unknown strategy name: %v", name) + } + + profile := api.Profile{ + Name: fmt.Sprintf("strategy-%v-profile", name), + PluginConfigs: []api.PluginConfig{ + { + Name: defaultevictor.PluginName, + Args: &defaultevictor.DefaultEvictorArgs{ + EvictLocalStoragePods: evictLocalStoragePods, + EvictSystemCriticalPods: evictSystemCriticalPods, + IgnorePvcPods: ignorePvcPods, + EvictFailedBarePods: evictBarePods, + NodeFit: nodeFit, + PriorityThreshold: &api.PriorityThreshold{ + Value: &thresholdPriority, + }, + }, + }, + *pluginConfig, + }, + Plugins: api.Plugins{ + Evict: api.PluginSet{ + Enabled: []string{defaultevictor.PluginName}, + }, + }, + } + + 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 { + klog.ErrorS(fmt.Errorf("unknown strategy name"), "skipping strategy", "strategy", name) + return nil, fmt.Errorf("unknown strategy name: %v", name) + } + } + + return &api.DeschedulerPolicy{ + Profiles: profiles, + NodeSelector: deschedulerPolicy.NodeSelector, + MaxNoOfPodsToEvictPerNode: deschedulerPolicy.MaxNoOfPodsToEvictPerNode, + 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 { + _, ok := pluginInstance.(framework.BalancePlugin) + if ok { + klog.V(3).Info("converting Balance plugin: %s", pluginInstance.Name()) + profilePlugins.Balance.Enabled = []string{pluginConfig.Name} + } + return profilePlugins +} + +func checkDeschedule(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins { + _, ok := pluginInstance.(framework.DeschedulePlugin) + if ok { + klog.V(3).Info("converting Deschedule plugin: %s", pluginInstance.Name()) + profilePlugins.Deschedule.Enabled = []string{pluginConfig.Name} + } + return profilePlugins +} diff --git a/pkg/descheduler/strategy_migration.go b/pkg/api/v1alpha1/strategymigration.go similarity index 85% rename from pkg/descheduler/strategy_migration.go rename to pkg/api/v1alpha1/strategymigration.go index 09fafac9d..302b768ce 100644 --- a/pkg/descheduler/strategy_migration.go +++ b/pkg/api/v1alpha1/strategymigration.go @@ -1,5 +1,5 @@ /* -Copyright 2022 The Kubernetes Authors. +Copyright 2023 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. @@ -14,14 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -package descheduler +package v1alpha1 import ( "fmt" "k8s.io/klog/v2" "sigs.k8s.io/descheduler/pkg/api" - "sigs.k8s.io/descheduler/pkg/api/v1alpha1" "sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization" "sigs.k8s.io/descheduler/pkg/framework/plugins/podlifetime" "sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates" @@ -37,8 +36,8 @@ import ( // without any wiring. Keeping the wiring here so the descheduler can still use // the v1alpha1 configuration during the strategy migration to plugins. -var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error){ - "RemovePodsViolatingNodeTaints": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { +var StrategyParamsToPluginArgs = map[string]func(params *StrategyParameters) (*api.PluginConfig, error){ + "RemovePodsViolatingNodeTaints": func(params *StrategyParameters) (*api.PluginConfig, error) { args := &removepodsviolatingnodetaints.RemovePodsViolatingNodeTaintsArgs{ Namespaces: v1alpha1NamespacesToInternal(params.Namespaces), LabelSelector: params.LabelSelector, @@ -54,10 +53,10 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "RemoveFailedPods": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "RemoveFailedPods": func(params *StrategyParameters) (*api.PluginConfig, error) { failedPodsParams := params.FailedPods if failedPodsParams == nil { - failedPodsParams = &v1alpha1.FailedPods{} + failedPodsParams = &FailedPods{} } args := &removefailedpods.RemoveFailedPodsArgs{ Namespaces: v1alpha1NamespacesToInternal(params.Namespaces), @@ -76,7 +75,7 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "RemovePodsViolatingNodeAffinity": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "RemovePodsViolatingNodeAffinity": func(params *StrategyParameters) (*api.PluginConfig, error) { args := &removepodsviolatingnodeaffinity.RemovePodsViolatingNodeAffinityArgs{ Namespaces: v1alpha1NamespacesToInternal(params.Namespaces), LabelSelector: params.LabelSelector, @@ -91,7 +90,7 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "RemovePodsViolatingInterPodAntiAffinity": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "RemovePodsViolatingInterPodAntiAffinity": func(params *StrategyParameters) (*api.PluginConfig, error) { args := &removepodsviolatinginterpodantiaffinity.RemovePodsViolatingInterPodAntiAffinityArgs{ Namespaces: v1alpha1NamespacesToInternal(params.Namespaces), LabelSelector: params.LabelSelector, @@ -105,10 +104,10 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "RemovePodsHavingTooManyRestarts": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "RemovePodsHavingTooManyRestarts": func(params *StrategyParameters) (*api.PluginConfig, error) { tooManyRestartsParams := params.PodsHavingTooManyRestarts if tooManyRestartsParams == nil { - tooManyRestartsParams = &v1alpha1.PodsHavingTooManyRestarts{} + tooManyRestartsParams = &PodsHavingTooManyRestarts{} } args := &removepodshavingtoomanyrestarts.RemovePodsHavingTooManyRestartsArgs{ Namespaces: v1alpha1NamespacesToInternal(params.Namespaces), @@ -125,10 +124,10 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "PodLifeTime": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "PodLifeTime": func(params *StrategyParameters) (*api.PluginConfig, error) { podLifeTimeParams := params.PodLifeTime if podLifeTimeParams == nil { - podLifeTimeParams = &v1alpha1.PodLifeTime{} + podLifeTimeParams = &PodLifeTime{} } var states []string @@ -154,7 +153,7 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "RemoveDuplicates": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "RemoveDuplicates": func(params *StrategyParameters) (*api.PluginConfig, error) { args := &removeduplicates.RemoveDuplicatesArgs{ Namespaces: v1alpha1NamespacesToInternal(params.Namespaces), } @@ -170,7 +169,7 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "RemovePodsViolatingTopologySpreadConstraint": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "RemovePodsViolatingTopologySpreadConstraint": func(params *StrategyParameters) (*api.PluginConfig, error) { args := &removepodsviolatingtopologyspreadconstraint.RemovePodsViolatingTopologySpreadConstraintArgs{ Namespaces: v1alpha1NamespacesToInternal(params.Namespaces), LabelSelector: params.LabelSelector, @@ -185,9 +184,9 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "HighNodeUtilization": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "HighNodeUtilization": func(params *StrategyParameters) (*api.PluginConfig, error) { if params.NodeResourceUtilizationThresholds == nil { - params.NodeResourceUtilizationThresholds = &v1alpha1.NodeResourceUtilizationThresholds{} + params.NodeResourceUtilizationThresholds = &NodeResourceUtilizationThresholds{} } args := &nodeutilization.HighNodeUtilizationArgs{ EvictableNamespaces: v1alpha1NamespacesToInternal(params.Namespaces), @@ -203,9 +202,9 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame Args: args, }, nil }, - "LowNodeUtilization": func(params *v1alpha1.StrategyParameters) (*api.PluginConfig, error) { + "LowNodeUtilization": func(params *StrategyParameters) (*api.PluginConfig, error) { if params.NodeResourceUtilizationThresholds == nil { - params.NodeResourceUtilizationThresholds = &v1alpha1.NodeResourceUtilizationThresholds{} + params.NodeResourceUtilizationThresholds = &NodeResourceUtilizationThresholds{} } args := &nodeutilization.LowNodeUtilizationArgs{ EvictableNamespaces: v1alpha1NamespacesToInternal(params.Namespaces), @@ -226,7 +225,7 @@ var strategyParamsToPluginArgs = map[string]func(params *v1alpha1.StrategyParame }, } -func v1alpha1NamespacesToInternal(namespaces *v1alpha1.Namespaces) *api.Namespaces { +func v1alpha1NamespacesToInternal(namespaces *Namespaces) *api.Namespaces { internal := &api.Namespaces{} if namespaces != nil { if namespaces.Exclude != nil { @@ -241,7 +240,7 @@ func v1alpha1NamespacesToInternal(namespaces *v1alpha1.Namespaces) *api.Namespac return internal } -func v1alpha1ThresholdToInternal(thresholds v1alpha1.ResourceThresholds) api.ResourceThresholds { +func v1alpha1ThresholdToInternal(thresholds ResourceThresholds) api.ResourceThresholds { internal := make(api.ResourceThresholds, len(thresholds)) for k, v := range thresholds { internal[k] = api.Percentage(float64(v)) diff --git a/pkg/descheduler/strategy_migration_test.go b/pkg/api/v1alpha1/strategymigration_test.go similarity index 79% rename from pkg/descheduler/strategy_migration_test.go rename to pkg/api/v1alpha1/strategymigration_test.go index da342c3d2..983168014 100644 --- a/pkg/descheduler/strategy_migration_test.go +++ b/pkg/api/v1alpha1/strategymigration_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package descheduler +package v1alpha1 import ( "fmt" @@ -23,7 +23,6 @@ import ( "github.com/google/go-cmp/cmp" utilpointer "k8s.io/utils/pointer" "sigs.k8s.io/descheduler/pkg/api" - "sigs.k8s.io/descheduler/pkg/api/v1alpha1" "sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization" "sigs.k8s.io/descheduler/pkg/framework/plugins/podlifetime" "sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates" @@ -39,20 +38,20 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingNodeTaints(t *testing.T) { strategyName := "RemovePodsViolatingNodeTaints" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ + params: &StrategyParameters{ ExcludedTaints: []string{ "dedicated=special-user", "reserved", }, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -69,8 +68,8 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingNodeTaints(t *testing.T) { }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - Namespaces: &v1alpha1.Namespaces{ + params: &StrategyParameters{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, Include: []string{"test2"}, }, @@ -84,7 +83,7 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingNodeTaints(t *testing.T) { t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -107,22 +106,22 @@ func TestStrategyParamsToPluginArgsRemoveFailedPods(t *testing.T) { strategyName := "RemoveFailedPods" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ - FailedPods: &v1alpha1.FailedPods{ + params: &StrategyParameters{ + FailedPods: &FailedPods{ MinPodLifetimeSeconds: utilpointer.Uint(3600), ExcludeOwnerKinds: []string{"Job"}, Reasons: []string{"NodeAffinity"}, IncludingInitContainers: true, }, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -142,8 +141,8 @@ func TestStrategyParamsToPluginArgsRemoveFailedPods(t *testing.T) { }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - Namespaces: &v1alpha1.Namespaces{ + params: &StrategyParameters{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, Include: []string{"test2"}, }, @@ -157,7 +156,7 @@ func TestStrategyParamsToPluginArgsRemoveFailedPods(t *testing.T) { t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -180,17 +179,17 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingNodeAffinity(t *testing.T) strategyName := "RemovePodsViolatingNodeAffinity" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ + params: &StrategyParameters{ NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"}, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -207,15 +206,15 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingNodeAffinity(t *testing.T) }, { description: "invalid params, not setting nodeaffinity type", - params: &v1alpha1.StrategyParameters{}, + params: &StrategyParameters{}, err: fmt.Errorf("strategy \"%s\" param validation failed: nodeAffinityType needs to be set", strategyName), result: nil, }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ + params: &StrategyParameters{ NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"}, - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, Include: []string{"test2"}, }, @@ -229,7 +228,7 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingNodeAffinity(t *testing.T) t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -252,16 +251,16 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingInterPodAntiAffinity(t *te strategyName := "RemovePodsViolatingInterPodAntiAffinity" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ + params: &StrategyParameters{ ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -277,8 +276,8 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingInterPodAntiAffinity(t *te }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - Namespaces: &v1alpha1.Namespaces{ + params: &StrategyParameters{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, Include: []string{"test2"}, }, @@ -292,7 +291,7 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingInterPodAntiAffinity(t *te t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -315,20 +314,20 @@ func TestStrategyParamsToPluginArgsRemovePodsHavingTooManyRestarts(t *testing.T) strategyName := "RemovePodsHavingTooManyRestarts" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ - PodsHavingTooManyRestarts: &v1alpha1.PodsHavingTooManyRestarts{ + params: &StrategyParameters{ + PodsHavingTooManyRestarts: &PodsHavingTooManyRestarts{ PodRestartThreshold: 100, IncludingInitContainers: true, }, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -346,8 +345,8 @@ func TestStrategyParamsToPluginArgsRemovePodsHavingTooManyRestarts(t *testing.T) }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - Namespaces: &v1alpha1.Namespaces{ + params: &StrategyParameters{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, Include: []string{"test2"}, }, @@ -357,8 +356,8 @@ func TestStrategyParamsToPluginArgsRemovePodsHavingTooManyRestarts(t *testing.T) }, { description: "invalid params restart threshold", - params: &v1alpha1.StrategyParameters{ - PodsHavingTooManyRestarts: &v1alpha1.PodsHavingTooManyRestarts{ + params: &StrategyParameters{ + PodsHavingTooManyRestarts: &PodsHavingTooManyRestarts{ PodRestartThreshold: 0, }, }, @@ -371,7 +370,7 @@ func TestStrategyParamsToPluginArgsRemovePodsHavingTooManyRestarts(t *testing.T) t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -394,15 +393,15 @@ func TestStrategyParamsToPluginArgsPodLifeTime(t *testing.T) { strategyName := "PodLifeTime" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ - PodLifeTime: &v1alpha1.PodLifeTime{ + params: &StrategyParameters{ + PodLifeTime: &PodLifeTime{ MaxPodLifeTimeSeconds: utilpointer.Uint(86400), States: []string{ "Pending", @@ -410,7 +409,7 @@ func TestStrategyParamsToPluginArgsPodLifeTime(t *testing.T) { }, }, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -431,11 +430,11 @@ func TestStrategyParamsToPluginArgsPodLifeTime(t *testing.T) { }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - PodLifeTime: &v1alpha1.PodLifeTime{ + params: &StrategyParameters{ + PodLifeTime: &PodLifeTime{ MaxPodLifeTimeSeconds: utilpointer.Uint(86400), }, - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, Include: []string{"test2"}, }, @@ -445,8 +444,8 @@ func TestStrategyParamsToPluginArgsPodLifeTime(t *testing.T) { }, { description: "invalid params MaxPodLifeTimeSeconds not set", - params: &v1alpha1.StrategyParameters{ - PodLifeTime: &v1alpha1.PodLifeTime{}, + params: &StrategyParameters{ + PodLifeTime: &PodLifeTime{}, }, err: fmt.Errorf("strategy \"%s\" param validation failed: MaxPodLifeTimeSeconds not set", strategyName), result: nil, @@ -457,7 +456,7 @@ func TestStrategyParamsToPluginArgsPodLifeTime(t *testing.T) { t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -480,19 +479,19 @@ func TestStrategyParamsToPluginArgsRemoveDuplicates(t *testing.T) { strategyName := "RemoveDuplicates" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ - RemoveDuplicates: &v1alpha1.RemoveDuplicates{ + params: &StrategyParameters{ + RemoveDuplicates: &RemoveDuplicates{ ExcludeOwnerKinds: []string{"ReplicaSet"}, }, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -509,11 +508,11 @@ func TestStrategyParamsToPluginArgsRemoveDuplicates(t *testing.T) { }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - PodLifeTime: &v1alpha1.PodLifeTime{ + params: &StrategyParameters{ + PodLifeTime: &PodLifeTime{ MaxPodLifeTimeSeconds: utilpointer.Uint(86400), }, - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, Include: []string{"test2"}, }, @@ -527,7 +526,7 @@ func TestStrategyParamsToPluginArgsRemoveDuplicates(t *testing.T) { t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -550,17 +549,17 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingTopologySpreadConstraint(t strategyName := "RemovePodsViolatingTopologySpreadConstraint" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ + params: &StrategyParameters{ IncludeSoftConstraints: true, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -577,8 +576,8 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingTopologySpreadConstraint(t }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - Namespaces: &v1alpha1.Namespaces{ + params: &StrategyParameters{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, Include: []string{"test2"}, }, @@ -592,7 +591,7 @@ func TestStrategyParamsToPluginArgsRemovePodsViolatingTopologySpreadConstraint(t t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -615,24 +614,24 @@ func TestStrategyParamsToPluginArgsHighNodeUtilization(t *testing.T) { strategyName := "HighNodeUtilization" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ - NodeResourceUtilizationThresholds: &v1alpha1.NodeResourceUtilizationThresholds{ + params: &StrategyParameters{ + NodeResourceUtilizationThresholds: &NodeResourceUtilizationThresholds{ NumberOfNodes: 3, - Thresholds: v1alpha1.ResourceThresholds{ - "cpu": v1alpha1.Percentage(20), - "memory": v1alpha1.Percentage(20), - "pods": v1alpha1.Percentage(20), + Thresholds: ResourceThresholds{ + "cpu": Percentage(20), + "memory": Percentage(20), + "pods": Percentage(20), }, }, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -654,16 +653,16 @@ func TestStrategyParamsToPluginArgsHighNodeUtilization(t *testing.T) { }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - NodeResourceUtilizationThresholds: &v1alpha1.NodeResourceUtilizationThresholds{ + params: &StrategyParameters{ + NodeResourceUtilizationThresholds: &NodeResourceUtilizationThresholds{ NumberOfNodes: 3, - Thresholds: v1alpha1.ResourceThresholds{ - "cpu": v1alpha1.Percentage(20), - "memory": v1alpha1.Percentage(20), - "pods": v1alpha1.Percentage(20), + Thresholds: ResourceThresholds{ + "cpu": Percentage(20), + "memory": Percentage(20), + "pods": Percentage(20), }, }, - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Include: []string{"test2"}, }, }, @@ -672,8 +671,8 @@ func TestStrategyParamsToPluginArgsHighNodeUtilization(t *testing.T) { }, { description: "invalid params nil ResourceThresholds", - params: &v1alpha1.StrategyParameters{ - NodeResourceUtilizationThresholds: &v1alpha1.NodeResourceUtilizationThresholds{ + params: &StrategyParameters{ + NodeResourceUtilizationThresholds: &NodeResourceUtilizationThresholds{ NumberOfNodes: 3, }, }, @@ -682,11 +681,11 @@ func TestStrategyParamsToPluginArgsHighNodeUtilization(t *testing.T) { }, { description: "invalid params out of bounds threshold", - params: &v1alpha1.StrategyParameters{ - NodeResourceUtilizationThresholds: &v1alpha1.NodeResourceUtilizationThresholds{ + params: &StrategyParameters{ + NodeResourceUtilizationThresholds: &NodeResourceUtilizationThresholds{ NumberOfNodes: 3, - Thresholds: v1alpha1.ResourceThresholds{ - "cpu": v1alpha1.Percentage(150), + Thresholds: ResourceThresholds{ + "cpu": Percentage(150), }, }, }, @@ -699,7 +698,7 @@ func TestStrategyParamsToPluginArgsHighNodeUtilization(t *testing.T) { t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { @@ -722,30 +721,30 @@ func TestStrategyParamsToPluginArgsLowNodeUtilization(t *testing.T) { strategyName := "LowNodeUtilization" type testCase struct { description string - params *v1alpha1.StrategyParameters + params *StrategyParameters err error result *api.PluginConfig } testCases := []testCase{ { description: "wire in all valid parameters", - params: &v1alpha1.StrategyParameters{ - NodeResourceUtilizationThresholds: &v1alpha1.NodeResourceUtilizationThresholds{ + params: &StrategyParameters{ + NodeResourceUtilizationThresholds: &NodeResourceUtilizationThresholds{ NumberOfNodes: 3, - Thresholds: v1alpha1.ResourceThresholds{ - "cpu": v1alpha1.Percentage(20), - "memory": v1alpha1.Percentage(20), - "pods": v1alpha1.Percentage(20), + Thresholds: ResourceThresholds{ + "cpu": Percentage(20), + "memory": Percentage(20), + "pods": Percentage(20), }, - TargetThresholds: v1alpha1.ResourceThresholds{ - "cpu": v1alpha1.Percentage(50), - "memory": v1alpha1.Percentage(50), - "pods": v1alpha1.Percentage(50), + TargetThresholds: ResourceThresholds{ + "cpu": Percentage(50), + "memory": Percentage(50), + "pods": Percentage(50), }, UseDeviationThresholds: true, }, ThresholdPriority: utilpointer.Int32(100), - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Exclude: []string{"test1"}, }, }, @@ -773,22 +772,22 @@ func TestStrategyParamsToPluginArgsLowNodeUtilization(t *testing.T) { }, { description: "invalid params namespaces", - params: &v1alpha1.StrategyParameters{ - NodeResourceUtilizationThresholds: &v1alpha1.NodeResourceUtilizationThresholds{ + params: &StrategyParameters{ + NodeResourceUtilizationThresholds: &NodeResourceUtilizationThresholds{ NumberOfNodes: 3, - Thresholds: v1alpha1.ResourceThresholds{ - "cpu": v1alpha1.Percentage(20), - "memory": v1alpha1.Percentage(20), - "pods": v1alpha1.Percentage(20), + Thresholds: ResourceThresholds{ + "cpu": Percentage(20), + "memory": Percentage(20), + "pods": Percentage(20), }, - TargetThresholds: v1alpha1.ResourceThresholds{ - "cpu": v1alpha1.Percentage(50), - "memory": v1alpha1.Percentage(50), - "pods": v1alpha1.Percentage(50), + TargetThresholds: ResourceThresholds{ + "cpu": Percentage(50), + "memory": Percentage(50), + "pods": Percentage(50), }, UseDeviationThresholds: true, }, - Namespaces: &v1alpha1.Namespaces{ + Namespaces: &Namespaces{ Include: []string{"test2"}, }, }, @@ -797,8 +796,8 @@ func TestStrategyParamsToPluginArgsLowNodeUtilization(t *testing.T) { }, { description: "invalid params nil ResourceThresholds", - params: &v1alpha1.StrategyParameters{ - NodeResourceUtilizationThresholds: &v1alpha1.NodeResourceUtilizationThresholds{ + params: &StrategyParameters{ + NodeResourceUtilizationThresholds: &NodeResourceUtilizationThresholds{ NumberOfNodes: 3, }, }, @@ -807,11 +806,11 @@ func TestStrategyParamsToPluginArgsLowNodeUtilization(t *testing.T) { }, { description: "invalid params out of bounds threshold", - params: &v1alpha1.StrategyParameters{ - NodeResourceUtilizationThresholds: &v1alpha1.NodeResourceUtilizationThresholds{ + params: &StrategyParameters{ + NodeResourceUtilizationThresholds: &NodeResourceUtilizationThresholds{ NumberOfNodes: 3, - Thresholds: v1alpha1.ResourceThresholds{ - "cpu": v1alpha1.Percentage(150), + Thresholds: ResourceThresholds{ + "cpu": Percentage(150), }, }, }, @@ -824,7 +823,7 @@ func TestStrategyParamsToPluginArgsLowNodeUtilization(t *testing.T) { t.Run(tc.description, func(t *testing.T) { var result *api.PluginConfig var err error - if pcFnc, exists := strategyParamsToPluginArgs[strategyName]; exists { + if pcFnc, exists := StrategyParamsToPluginArgs[strategyName]; exists { result, err = pcFnc(tc.params) } if err != nil { diff --git a/pkg/api/v1alpha2/conversion.go b/pkg/api/v1alpha2/conversion.go new file mode 100644 index 000000000..36c95e5ca --- /dev/null +++ b/pkg/api/v1alpha2/conversion.go @@ -0,0 +1,136 @@ +/* +Copyright 2023 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 v1alpha2 + +import ( + "fmt" + "sync" + + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + api "sigs.k8s.io/descheduler/pkg/api" + + "sigs.k8s.io/descheduler/pkg/framework/pluginregistry" +) + +var ( + // pluginArgConversionScheme is a scheme with internal and v1alpha2 registered, + // used for defaulting/converting typed PluginConfig Args. + // Access via getPluginArgConversionScheme() + pluginArgConversionScheme *runtime.Scheme + initPluginArgConversionScheme sync.Once + + Scheme = runtime.NewScheme() + Codecs = serializer.NewCodecFactory(Scheme, serializer.EnableStrict) +) + +func GetPluginArgConversionScheme() *runtime.Scheme { + initPluginArgConversionScheme.Do(func() { + // set up the scheme used for plugin arg conversion + pluginArgConversionScheme = runtime.NewScheme() + utilruntime.Must(AddToScheme(pluginArgConversionScheme)) + utilruntime.Must(api.AddToScheme(pluginArgConversionScheme)) + }) + return pluginArgConversionScheme +} + +func Convert_v1alpha2_DeschedulerPolicy_To_api_DeschedulerPolicy(in *DeschedulerPolicy, out *api.DeschedulerPolicy, s conversion.Scope) error { + if err := autoConvert_v1alpha2_DeschedulerPolicy_To_api_DeschedulerPolicy(in, out, s); err != nil { + return err + } + return convertToInternalPluginConfigArgs(out) +} + +// convertToInternalPluginConfigArgs converts PluginConfig#Args into internal +// types using a scheme, after applying defaults. +func convertToInternalPluginConfigArgs(out *api.DeschedulerPolicy) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + prof := &out.Profiles[i] + for j := range prof.PluginConfigs { + args := prof.PluginConfigs[j].Args + if args == nil { + continue + } + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + internalArgs, err := scheme.ConvertToVersion(args, api.SchemeGroupVersion) + if err != nil { + err = nil + internalArgs = args + if err != nil { + return fmt.Errorf("converting .Profiles[%d].PluginConfigs[%d].Args into internal type: %w", i, j, err) + } + } + prof.PluginConfigs[j].Args = internalArgs + } + } + return nil +} + +func Convert_v1alpha2_PluginConfig_To_api_PluginConfig(in *PluginConfig, out *api.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if _, ok := pluginregistry.PluginRegistry[in.Name]; ok { + out.Args = pluginregistry.PluginRegistry[in.Name].PluginArgInstance + if in.Args.Raw != nil { + _, _, err := Codecs.UniversalDecoder().Decode(in.Args.Raw, nil, out.Args) + if err != nil { + return err + } + } else if in.Args.Object != nil { + out.Args = in.Args.Object + } + } else { + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Args, &out.Args, s); err != nil { + return err + } + } + return nil +} + +func Convert_api_DeschedulerPolicy_To_v1alpha2_DeschedulerPolicy(in *api.DeschedulerPolicy, out *DeschedulerPolicy, s conversion.Scope) error { + if err := autoConvert_api_DeschedulerPolicy_To_v1alpha2_DeschedulerPolicy(in, out, s); err != nil { + return err + } + return convertToExternalPluginConfigArgs(out) +} + +// convertToExternalPluginConfigArgs converts PluginConfig#Args into +// external (versioned) types using a scheme. +func convertToExternalPluginConfigArgs(out *DeschedulerPolicy) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + for j := range out.Profiles[i].PluginConfigs { + args := out.Profiles[i].PluginConfigs[j].Args + if args.Object == nil { + continue + } + if _, isUnknown := args.Object.(*runtime.Unknown); isUnknown { + continue + } + externalArgs, err := scheme.ConvertToVersion(args.Object, SchemeGroupVersion) + if err != nil { + return err + } + out.Profiles[i].PluginConfigs[j].Args.Object = externalArgs + } + } + return nil +} diff --git a/pkg/api/v1alpha2/defaults.go b/pkg/api/v1alpha2/defaults.go new file mode 100644 index 000000000..801d530ca --- /dev/null +++ b/pkg/api/v1alpha2/defaults.go @@ -0,0 +1,23 @@ +/* +Copyright 2023 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 v1alpha2 + +import "k8s.io/apimachinery/pkg/runtime" + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} diff --git a/pkg/api/v1alpha2/doc.go b/pkg/api/v1alpha2/doc.go new file mode 100644 index 000000000..2d7dff1ed --- /dev/null +++ b/pkg/api/v1alpha2/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2023 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. +*/ + +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=sigs.k8s.io/descheduler/pkg/api +// +k8s:defaulter-gen=TypeMeta + +// Package v1alpha2 is the v1alpha2 version of the descheduler API +// +groupName=descheduler + +package v1alpha2 // import "sigs.k8s.io/descheduler/pkg/api/v1alpha2" diff --git a/pkg/api/v1alpha2/register.go b/pkg/api/v1alpha2/register.go new file mode 100644 index 000000000..b975e416b --- /dev/null +++ b/pkg/api/v1alpha2/register.go @@ -0,0 +1,61 @@ +/* +Copyright 2023 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 v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + localSchemeBuilder = &SchemeBuilder + AddToScheme = SchemeBuilder.AddToScheme +) + +// GroupName is the group name used in this package +const GroupName = "descheduler" +const GroupVersion = "v1alpha2" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs) +} + +func addKnownTypes(scheme *runtime.Scheme) error { + // TODO this will get cleaned up with the scheme types are fixed + scheme.AddKnownTypes(SchemeGroupVersion, + &DeschedulerPolicy{}, + ) + + return nil +} diff --git a/pkg/api/v1alpha2/sort.go b/pkg/api/v1alpha2/sort.go new file mode 100644 index 000000000..a3f659df3 --- /dev/null +++ b/pkg/api/v1alpha2/sort.go @@ -0,0 +1,26 @@ +/* +Copyright 2023 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 v1alpha2 + +import "sort" + +func SortProfilesByName(profiles []Profile) []Profile { + sort.Slice(profiles, func(i, j int) bool { + return profiles[i].Name < profiles[j].Name + }) + return profiles +} diff --git a/pkg/api/v1alpha2/types.go b/pkg/api/v1alpha2/types.go new file mode 100644 index 000000000..b1b47467f --- /dev/null +++ b/pkg/api/v1alpha2/types.go @@ -0,0 +1,66 @@ +/* +Copyright 2023 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 v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type DeschedulerPolicy struct { + metav1.TypeMeta `json:",inline"` + + // Profiles + Profiles []Profile `json:"profiles,omitempty"` + + // NodeSelector for a set of nodes to operate over + NodeSelector *string `json:"nodeSelector,omitempty"` + + // MaxNoOfPodsToEvictPerNode restricts maximum of pods to be evicted per node. + MaxNoOfPodsToEvictPerNode *uint `json:"maxNoOfPodsToEvictPerNode,omitempty"` + + // MaxNoOfPodsToEvictPerNamespace restricts maximum of pods to be evicted per namespace. + MaxNoOfPodsToEvictPerNamespace *uint `json:"maxNoOfPodsToEvictPerNamespace,omitempty"` +} + +type Profile struct { + Name string `json:"name"` + PluginConfigs []PluginConfig `json:"pluginConfig"` + Plugins Plugins `json:"plugins"` +} + +type Plugins struct { + PreSort PluginSet `json:"presort"` + Sort PluginSet `json:"sort"` + Deschedule PluginSet `json:"deschedule"` + Balance PluginSet `json:"balance"` + Evict PluginSet `json:"evict"` + Filter PluginSet `json:"filter"` + PreEvictionFilter PluginSet `json:"preevictionfilter"` +} + +type PluginConfig struct { + Name string `json:"name"` + Args runtime.RawExtension `json:"args"` +} + +type PluginSet struct { + Enabled []string `json:"enabled"` + Disabled []string `json:"disabled"` +} diff --git a/pkg/api/v1alpha2/zz_generated.conversion.go b/pkg/api/v1alpha2/zz_generated.conversion.go new file mode 100644 index 000000000..0852ba0e3 --- /dev/null +++ b/pkg/api/v1alpha2/zz_generated.conversion.go @@ -0,0 +1,277 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + unsafe "unsafe" + + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + api "sigs.k8s.io/descheduler/pkg/api" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*api.PluginConfig)(nil), (*PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_api_PluginConfig_To_v1alpha2_PluginConfig(a.(*api.PluginConfig), b.(*PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*PluginSet)(nil), (*api.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_PluginSet_To_api_PluginSet(a.(*PluginSet), b.(*api.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*api.PluginSet)(nil), (*PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_api_PluginSet_To_v1alpha2_PluginSet(a.(*api.PluginSet), b.(*PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Plugins)(nil), (*api.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_Plugins_To_api_Plugins(a.(*Plugins), b.(*api.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*api.Plugins)(nil), (*Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_api_Plugins_To_v1alpha2_Plugins(a.(*api.Plugins), b.(*Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Profile)(nil), (*api.Profile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_Profile_To_api_Profile(a.(*Profile), b.(*api.Profile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*api.Profile)(nil), (*Profile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_api_Profile_To_v1alpha2_Profile(a.(*api.Profile), b.(*Profile), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*api.DeschedulerPolicy)(nil), (*DeschedulerPolicy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_api_DeschedulerPolicy_To_v1alpha2_DeschedulerPolicy(a.(*api.DeschedulerPolicy), b.(*DeschedulerPolicy), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*DeschedulerPolicy)(nil), (*api.DeschedulerPolicy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_DeschedulerPolicy_To_api_DeschedulerPolicy(a.(*DeschedulerPolicy), b.(*api.DeschedulerPolicy), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*PluginConfig)(nil), (*api.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_PluginConfig_To_api_PluginConfig(a.(*PluginConfig), b.(*api.PluginConfig), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha2_DeschedulerPolicy_To_api_DeschedulerPolicy(in *DeschedulerPolicy, out *api.DeschedulerPolicy, s conversion.Scope) error { + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]api.Profile, len(*in)) + for i := range *in { + if err := Convert_v1alpha2_Profile_To_api_Profile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.NodeSelector = (*string)(unsafe.Pointer(in.NodeSelector)) + out.MaxNoOfPodsToEvictPerNode = (*uint)(unsafe.Pointer(in.MaxNoOfPodsToEvictPerNode)) + out.MaxNoOfPodsToEvictPerNamespace = (*uint)(unsafe.Pointer(in.MaxNoOfPodsToEvictPerNamespace)) + return nil +} + +func autoConvert_api_DeschedulerPolicy_To_v1alpha2_DeschedulerPolicy(in *api.DeschedulerPolicy, out *DeschedulerPolicy, s conversion.Scope) error { + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]Profile, len(*in)) + for i := range *in { + if err := Convert_api_Profile_To_v1alpha2_Profile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.NodeSelector = (*string)(unsafe.Pointer(in.NodeSelector)) + out.MaxNoOfPodsToEvictPerNode = (*uint)(unsafe.Pointer(in.MaxNoOfPodsToEvictPerNode)) + out.MaxNoOfPodsToEvictPerNamespace = (*uint)(unsafe.Pointer(in.MaxNoOfPodsToEvictPerNamespace)) + return nil +} + +func autoConvert_v1alpha2_PluginConfig_To_api_PluginConfig(in *PluginConfig, out *api.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +func autoConvert_api_PluginConfig_To_v1alpha2_PluginConfig(in *api.PluginConfig, out *PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_api_PluginConfig_To_v1alpha2_PluginConfig is an autogenerated conversion function. +func Convert_api_PluginConfig_To_v1alpha2_PluginConfig(in *api.PluginConfig, out *PluginConfig, s conversion.Scope) error { + return autoConvert_api_PluginConfig_To_v1alpha2_PluginConfig(in, out, s) +} + +func autoConvert_v1alpha2_PluginSet_To_api_PluginSet(in *PluginSet, out *api.PluginSet, s conversion.Scope) error { + out.Enabled = *(*[]string)(unsafe.Pointer(&in.Enabled)) + out.Disabled = *(*[]string)(unsafe.Pointer(&in.Disabled)) + return nil +} + +// Convert_v1alpha2_PluginSet_To_api_PluginSet is an autogenerated conversion function. +func Convert_v1alpha2_PluginSet_To_api_PluginSet(in *PluginSet, out *api.PluginSet, s conversion.Scope) error { + return autoConvert_v1alpha2_PluginSet_To_api_PluginSet(in, out, s) +} + +func autoConvert_api_PluginSet_To_v1alpha2_PluginSet(in *api.PluginSet, out *PluginSet, s conversion.Scope) error { + out.Enabled = *(*[]string)(unsafe.Pointer(&in.Enabled)) + out.Disabled = *(*[]string)(unsafe.Pointer(&in.Disabled)) + return nil +} + +// Convert_api_PluginSet_To_v1alpha2_PluginSet is an autogenerated conversion function. +func Convert_api_PluginSet_To_v1alpha2_PluginSet(in *api.PluginSet, out *PluginSet, s conversion.Scope) error { + return autoConvert_api_PluginSet_To_v1alpha2_PluginSet(in, out, s) +} + +func autoConvert_v1alpha2_Plugins_To_api_Plugins(in *Plugins, out *api.Plugins, s conversion.Scope) error { + if err := Convert_v1alpha2_PluginSet_To_api_PluginSet(&in.PreSort, &out.PreSort, s); err != nil { + return err + } + if err := Convert_v1alpha2_PluginSet_To_api_PluginSet(&in.Sort, &out.Sort, s); err != nil { + return err + } + if err := Convert_v1alpha2_PluginSet_To_api_PluginSet(&in.Deschedule, &out.Deschedule, s); err != nil { + return err + } + if err := Convert_v1alpha2_PluginSet_To_api_PluginSet(&in.Balance, &out.Balance, s); err != nil { + return err + } + if err := Convert_v1alpha2_PluginSet_To_api_PluginSet(&in.Evict, &out.Evict, s); err != nil { + return err + } + if err := Convert_v1alpha2_PluginSet_To_api_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_v1alpha2_PluginSet_To_api_PluginSet(&in.PreEvictionFilter, &out.PreEvictionFilter, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha2_Plugins_To_api_Plugins is an autogenerated conversion function. +func Convert_v1alpha2_Plugins_To_api_Plugins(in *Plugins, out *api.Plugins, s conversion.Scope) error { + return autoConvert_v1alpha2_Plugins_To_api_Plugins(in, out, s) +} + +func autoConvert_api_Plugins_To_v1alpha2_Plugins(in *api.Plugins, out *Plugins, s conversion.Scope) error { + if err := Convert_api_PluginSet_To_v1alpha2_PluginSet(&in.PreSort, &out.PreSort, s); err != nil { + return err + } + if err := Convert_api_PluginSet_To_v1alpha2_PluginSet(&in.Sort, &out.Sort, s); err != nil { + return err + } + if err := Convert_api_PluginSet_To_v1alpha2_PluginSet(&in.Deschedule, &out.Deschedule, s); err != nil { + return err + } + if err := Convert_api_PluginSet_To_v1alpha2_PluginSet(&in.Balance, &out.Balance, s); err != nil { + return err + } + if err := Convert_api_PluginSet_To_v1alpha2_PluginSet(&in.Evict, &out.Evict, s); err != nil { + return err + } + if err := Convert_api_PluginSet_To_v1alpha2_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_api_PluginSet_To_v1alpha2_PluginSet(&in.PreEvictionFilter, &out.PreEvictionFilter, s); err != nil { + return err + } + return nil +} + +// Convert_api_Plugins_To_v1alpha2_Plugins is an autogenerated conversion function. +func Convert_api_Plugins_To_v1alpha2_Plugins(in *api.Plugins, out *Plugins, s conversion.Scope) error { + return autoConvert_api_Plugins_To_v1alpha2_Plugins(in, out, s) +} + +func autoConvert_v1alpha2_Profile_To_api_Profile(in *Profile, out *api.Profile, s conversion.Scope) error { + out.Name = in.Name + if in.PluginConfigs != nil { + in, out := &in.PluginConfigs, &out.PluginConfigs + *out = make([]api.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_v1alpha2_PluginConfig_To_api_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfigs = nil + } + if err := Convert_v1alpha2_Plugins_To_api_Plugins(&in.Plugins, &out.Plugins, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha2_Profile_To_api_Profile is an autogenerated conversion function. +func Convert_v1alpha2_Profile_To_api_Profile(in *Profile, out *api.Profile, s conversion.Scope) error { + return autoConvert_v1alpha2_Profile_To_api_Profile(in, out, s) +} + +func autoConvert_api_Profile_To_v1alpha2_Profile(in *api.Profile, out *Profile, s conversion.Scope) error { + out.Name = in.Name + if in.PluginConfigs != nil { + in, out := &in.PluginConfigs, &out.PluginConfigs + *out = make([]PluginConfig, len(*in)) + for i := range *in { + if err := Convert_api_PluginConfig_To_v1alpha2_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfigs = nil + } + if err := Convert_api_Plugins_To_v1alpha2_Plugins(&in.Plugins, &out.Plugins, s); err != nil { + return err + } + return nil +} + +// Convert_api_Profile_To_v1alpha2_Profile is an autogenerated conversion function. +func Convert_api_Profile_To_v1alpha2_Profile(in *api.Profile, out *Profile, s conversion.Scope) error { + return autoConvert_api_Profile_To_v1alpha2_Profile(in, out, s) +} diff --git a/pkg/api/v1alpha2/zz_generated.deepcopy.go b/pkg/api/v1alpha2/zz_generated.deepcopy.go new file mode 100644 index 000000000..63f375381 --- /dev/null +++ b/pkg/api/v1alpha2/zz_generated.deepcopy.go @@ -0,0 +1,163 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeschedulerPolicy) DeepCopyInto(out *DeschedulerPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]Profile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = new(string) + **out = **in + } + if in.MaxNoOfPodsToEvictPerNode != nil { + in, out := &in.MaxNoOfPodsToEvictPerNode, &out.MaxNoOfPodsToEvictPerNode + *out = new(uint) + **out = **in + } + if in.MaxNoOfPodsToEvictPerNamespace != nil { + in, out := &in.MaxNoOfPodsToEvictPerNamespace, &out.MaxNoOfPodsToEvictPerNamespace + *out = new(uint) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerPolicy. +func (in *DeschedulerPolicy) DeepCopy() *DeschedulerPolicy { + if in == nil { + return nil + } + out := new(DeschedulerPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DeschedulerPolicy) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfig) DeepCopyInto(out *PluginConfig) { + *out = *in + in.Args.DeepCopyInto(&out.Args) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig. +func (in *PluginConfig) DeepCopy() *PluginConfig { + if in == nil { + return nil + } + out := new(PluginConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginSet) DeepCopyInto(out *PluginSet) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet. +func (in *PluginSet) DeepCopy() *PluginSet { + if in == nil { + return nil + } + out := new(PluginSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugins) DeepCopyInto(out *Plugins) { + *out = *in + in.PreSort.DeepCopyInto(&out.PreSort) + in.Sort.DeepCopyInto(&out.Sort) + in.Deschedule.DeepCopyInto(&out.Deschedule) + in.Balance.DeepCopyInto(&out.Balance) + in.Evict.DeepCopyInto(&out.Evict) + in.Filter.DeepCopyInto(&out.Filter) + in.PreEvictionFilter.DeepCopyInto(&out.PreEvictionFilter) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins. +func (in *Plugins) DeepCopy() *Plugins { + if in == nil { + return nil + } + out := new(Plugins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Profile) DeepCopyInto(out *Profile) { + *out = *in + if in.PluginConfigs != nil { + in, out := &in.PluginConfigs, &out.PluginConfigs + *out = make([]PluginConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Plugins.DeepCopyInto(&out.Plugins) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Profile. +func (in *Profile) DeepCopy() *Profile { + if in == nil { + return nil + } + out := new(Profile) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/api/v1alpha2/zz_generated.defaults.go b/pkg/api/v1alpha2/zz_generated.defaults.go new file mode 100644 index 000000000..eb8c39049 --- /dev/null +++ b/pkg/api/v1alpha2/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/pkg/descheduler/descheduler.go b/pkg/descheduler/descheduler.go index 8611e5491..c83ba1f30 100644 --- a/pkg/descheduler/descheduler.go +++ b/pkg/descheduler/descheduler.go @@ -44,8 +44,8 @@ import ( nodeutil "sigs.k8s.io/descheduler/pkg/descheduler/node" podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod" "sigs.k8s.io/descheduler/pkg/framework" + "sigs.k8s.io/descheduler/pkg/framework/pluginregistry" "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" - "sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder" "sigs.k8s.io/descheduler/pkg/utils" ) @@ -59,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, pluginbuilder.PluginRegistry) + deschedulerPolicy, err := LoadPolicyConfig(rs.PolicyConfigFile, rs.Client, pluginregistry.PluginRegistry) if err != nil { return err } @@ -358,7 +358,7 @@ func RunDeschedulerStrategies(ctx context.Context, rs *options.DeschedulerServer klog.ErrorS(fmt.Errorf("unable to get plugin config"), "skipping plugin", "plugin", plugin) continue } - registryPlugin, ok := pluginbuilder.PluginRegistry[plugin] + registryPlugin, ok := pluginregistry.PluginRegistry[plugin] pgFnc := registryPlugin.PluginBuilder if !ok { klog.ErrorS(fmt.Errorf("unable to find plugin in the pluginsMap"), "skipping plugin", "plugin", plugin) @@ -368,14 +368,8 @@ func RunDeschedulerStrategies(ctx context.Context, rs *options.DeschedulerServer klog.ErrorS(err, "unable to initialize a plugin", "pluginName", plugin) } if pg != nil { - switch v := pg.(type) { - case framework.DeschedulePlugin: - enabledDeschedulePlugins = append(enabledDeschedulePlugins, v) - case framework.BalancePlugin: - enabledBalancePlugins = append(enabledBalancePlugins, v) - default: - klog.ErrorS(fmt.Errorf("unknown plugin extension point"), "skipping plugin", "plugin", plugin) - } + // pg can be of any of each type, or both + enabledDeschedulePlugins, enabledBalancePlugins = includeProfilePluginsByType(enabledDeschedulePlugins, enabledBalancePlugins, pg) } } } @@ -416,6 +410,28 @@ func RunDeschedulerStrategies(ctx context.Context, rs *options.DeschedulerServer return nil } +func includeProfilePluginsByType(enabledDeschedulePlugins []framework.DeschedulePlugin, enabledBalancePlugins []framework.BalancePlugin, pg framework.Plugin) ([]framework.DeschedulePlugin, []framework.BalancePlugin) { + enabledDeschedulePlugins = includeDeschedule(enabledDeschedulePlugins, pg) + enabledBalancePlugins = includeBalance(enabledBalancePlugins, pg) + return enabledDeschedulePlugins, enabledBalancePlugins +} + +func includeDeschedule(enabledDeschedulePlugins []framework.DeschedulePlugin, pg framework.Plugin) []framework.DeschedulePlugin { + _, ok := pg.(framework.DeschedulePlugin) + if ok { + enabledDeschedulePlugins = append(enabledDeschedulePlugins, pg.(framework.DeschedulePlugin)) + } + return enabledDeschedulePlugins +} + +func includeBalance(enabledBalancePlugins []framework.BalancePlugin, pg framework.Plugin) []framework.BalancePlugin { + _, ok := pg.(framework.BalancePlugin) + if ok { + enabledBalancePlugins = append(enabledBalancePlugins, pg.(framework.BalancePlugin)) + } + return enabledBalancePlugins +} + func getPluginConfig(pluginName string, pluginConfigs []api.PluginConfig) *api.PluginConfig { for _, pluginConfig := range pluginConfigs { if pluginConfig.Name == pluginName { diff --git a/pkg/descheduler/descheduler_test.go b/pkg/descheduler/descheduler_test.go index c00512f7b..fa7482308 100644 --- a/pkg/descheduler/descheduler_test.go +++ b/pkg/descheduler/descheduler_test.go @@ -15,15 +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/pluginregistry" "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) + pluginregistry.PluginRegistry = pluginregistry.NewRegistry() + pluginregistry.Register(removepodsviolatingnodetaints.PluginName, removepodsviolatingnodetaints.New, &removepodsviolatingnodetaints.RemovePodsViolatingNodeTaintsArgs{}, removepodsviolatingnodetaints.ValidateRemovePodsViolatingNodeTaintsArgs, removepodsviolatingnodetaints.SetDefaults_RemovePodsViolatingNodeTaintsArgs, pluginregistry.PluginRegistry) ctx := context.Background() n1 := test.BuildTestNode("n1", 2000, 3000, 10, nil) n2 := test.BuildTestNode("n2", 2000, 3000, 10, nil) @@ -74,7 +74,7 @@ func TestTaintsUpdated(t *testing.T) { var evictedPods []string client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods)) - internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp, pluginbuilder.PluginRegistry) + internalDeschedulerPolicy, err := v1alpha1.V1alpha1ToInternal(client, dp, pluginregistry.PluginRegistry) if err != nil { t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err) } @@ -89,8 +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) + pluginregistry.PluginRegistry = pluginregistry.NewRegistry() + pluginregistry.Register(removeduplicates.PluginName, removeduplicates.New, &removeduplicates.RemoveDuplicatesArgs{}, removeduplicates.ValidateRemoveDuplicatesArgs, removeduplicates.SetDefaults_RemoveDuplicatesArgs, pluginregistry.PluginRegistry) ctx := context.Background() node1 := test.BuildTestNode("n1", 2000, 3000, 10, nil) node2 := test.BuildTestNode("n2", 2000, 3000, 10, nil) @@ -136,7 +136,7 @@ func TestDuplicate(t *testing.T) { var evictedPods []string client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods)) - internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp, pluginbuilder.PluginRegistry) + internalDeschedulerPolicy, err := v1alpha1.V1alpha1ToInternal(client, dp, pluginregistry.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 8c3a55cab..46beb0ddc 100644 --- a/pkg/descheduler/policyconfig.go +++ b/pkg/descheduler/policyconfig.go @@ -17,7 +17,6 @@ limitations under the License. package descheduler import ( - "context" "fmt" "os" @@ -27,14 +26,13 @@ import ( "sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api/v1alpha1" + "sigs.k8s.io/descheduler/pkg/api/v1alpha2" "sigs.k8s.io/descheduler/pkg/descheduler/scheme" - "sigs.k8s.io/descheduler/pkg/framework" + "sigs.k8s.io/descheduler/pkg/framework/pluginregistry" "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, registry pluginbuilder.Registry) (*api.DeschedulerPolicy, error) { +func LoadPolicyConfig(policyConfigFile string, client clientset.Interface, registry pluginregistry.Registry) (*api.DeschedulerPolicy, error) { if policyConfigFile == "" { klog.V(1).InfoS("Policy config file not specified") return nil, nil @@ -45,171 +43,128 @@ func LoadPolicyConfig(policyConfigFile string, client clientset.Interface, regis return nil, fmt.Errorf("failed to read policy config file %q: %+v", policyConfigFile, err) } + return decode(policyConfigFile, policy, client, registry) +} + +func decode(policyConfigFile string, policy []byte, client clientset.Interface, registry pluginregistry.Registry) (*api.DeschedulerPolicy, error) { versionedPolicy := &v1alpha1.DeschedulerPolicy{} + internalPolicy := &api.DeschedulerPolicy{} + var err error - decoder := scheme.Codecs.UniversalDecoder(v1alpha1.SchemeGroupVersion) + decoder := scheme.Codecs.UniversalDecoder(v1alpha1.SchemeGroupVersion, v1alpha2.SchemeGroupVersion, api.SchemeGroupVersion) if err := runtime.DecodeInto(decoder, policy, versionedPolicy); err != nil { - return nil, fmt.Errorf("failed decoding descheduler's policy config %q: %v", policyConfigFile, err) + // TODO: Right now we are checking this error string because we couldn't make a native + // Convert_v1alpha1_DeschedulerPolicy_To_api_DeschedulerPolicy in conversion.go + // and we are just calling V1alpha1ToInternal directly (since it needs a client as an argument). + // We need to make V1alpha1ToInternal stop needing a client, use a native conversion function + // and just rely in a DecodeInto that would pick up any policy file directly into our internal api. + // An attempt of doing that is in b25a44c51c0fa31a7831b899e73d83abd12a789a. Relevant discussions in following comments: + // https://github.com/kubernetes-sigs/descheduler/pull/1006#discussion_r1062630128 + if err.Error() == "converting (v1alpha2.DeschedulerPolicy) to (v1alpha1.DeschedulerPolicy): unknown conversion" { + klog.V(1).InfoS("Tried reading v1alpha2.DeschedulerPolicy and failed. Trying legacy conversion now.") + } else { + return nil, fmt.Errorf("failed decoding descheduler's policy config %q: %v", policyConfigFile, err) + } + } + if versionedPolicy.APIVersion == "descheduler/v1alpha1" { + // Build profiles + internalPolicy, err = v1alpha1.V1alpha1ToInternal(client, versionedPolicy, registry) + if err != nil { + return nil, fmt.Errorf("failed converting versioned policy to internal policy version: %v", err) + } + } else { + if err := runtime.DecodeInto(decoder, policy, internalPolicy); err != nil { + return nil, fmt.Errorf("failed decoding descheduler's policy config %q: %v", policyConfigFile, err) + } } - // Build profiles - internalPolicy, err := V1alpha1ToInternal(client, versionedPolicy, registry) + err = validateDeschedulerConfiguration(*internalPolicy, registry) if err != nil { - return nil, fmt.Errorf("failed converting versioned policy to internal policy version: %v", err) + return nil, err } + setDefaults(*internalPolicy, registry) + return internalPolicy, nil } -func V1alpha1ToInternal( - client clientset.Interface, - deschedulerPolicy *v1alpha1.DeschedulerPolicy, - registry pluginbuilder.Registry, -) (*api.DeschedulerPolicy, error) { - var evictLocalStoragePods bool - if deschedulerPolicy.EvictLocalStoragePods != nil { - evictLocalStoragePods = *deschedulerPolicy.EvictLocalStoragePods - } - - evictBarePods := false - if deschedulerPolicy.EvictFailedBarePods != nil { - evictBarePods = *deschedulerPolicy.EvictFailedBarePods - if evictBarePods { - klog.V(1).InfoS("Warning: EvictFailedBarePods is set to True. This could cause eviction of pods without ownerReferences.") +func setDefaults(in api.DeschedulerPolicy, registry pluginregistry.Registry) *api.DeschedulerPolicy { + for idx, profile := range in.Profiles { + // If we need to set defaults coming from loadtime in each profile we do it here + in.Profiles[idx] = setDefaultEvictor(profile) + for _, pluginConfig := range profile.PluginConfigs { + setDefaultsPluginConfig(&pluginConfig, registry) } } + return &in +} - evictSystemCriticalPods := false - if deschedulerPolicy.EvictSystemCriticalPods != nil { - evictSystemCriticalPods = *deschedulerPolicy.EvictSystemCriticalPods - if evictSystemCriticalPods { - klog.V(1).InfoS("Warning: EvictSystemCriticalPods is set to True. This could cause eviction of Kubernetes system pods.") +func setDefaultsPluginConfig(pluginConfig *api.PluginConfig, registry pluginregistry.Registry) { + if _, ok := registry[pluginConfig.Name]; ok { + pluginUtilities := registry[pluginConfig.Name] + if pluginUtilities.PluginArgDefaulter != nil { + pluginUtilities.PluginArgDefaulter(pluginConfig.Args) } } +} - ignorePvcPods := false - if deschedulerPolicy.IgnorePVCPods != nil { - ignorePvcPods = *deschedulerPolicy.IgnorePVCPods +func setDefaultEvictor(profile api.Profile) api.Profile { + newPluginConfig := api.PluginConfig{ + Name: defaultevictor.PluginName, + Args: &defaultevictor.DefaultEvictorArgs{ + EvictLocalStoragePods: false, + EvictSystemCriticalPods: false, + IgnorePvcPods: false, + EvictFailedBarePods: false, + }, } + if len(profile.Plugins.Evict.Enabled) == 0 && !hasPluginConfigsWithSameName(newPluginConfig, profile.PluginConfigs) { + profile.Plugins.Evict.Enabled = append(profile.Plugins.Evict.Enabled, defaultevictor.PluginName) + profile.PluginConfigs = append(profile.PluginConfigs, newPluginConfig) + } + return profile +} - var profiles []api.Profile - - // Build profiles - for name, strategy := range deschedulerPolicy.Strategies { - if _, ok := pluginbuilder.PluginRegistry[string(name)]; ok { - if strategy.Enabled { - params := strategy.Params - if params == nil { - params = &v1alpha1.StrategyParameters{} +func validateDeschedulerConfiguration(in api.DeschedulerPolicy, registry pluginregistry.Registry) error { + var errorsInProfiles error + for _, profile := range in.Profiles { + // api.DeschedulerPolicy needs only 1 evictor plugin enabled + if len(profile.Plugins.Evict.Enabled) != 1 { + errTooManyEvictors := fmt.Errorf("profile with invalid number of evictor plugins enabled found. Please enable a single evictor plugin.") + errorsInProfiles = setErrorsInProfiles(errTooManyEvictors, profile.Name, errorsInProfiles) + } + for _, pluginConfig := range profile.PluginConfigs { + if _, ok := registry[pluginConfig.Name]; ok { + pluginUtilities := registry[pluginConfig.Name] + if pluginUtilities.PluginArgValidator != nil { + err := pluginUtilities.PluginArgValidator(pluginConfig.Args) + errorsInProfiles = setErrorsInProfiles(err, profile.Name, errorsInProfiles) } - - nodeFit := false - if name != "PodLifeTime" { - nodeFit = params.NodeFit - } - - // TODO(jchaloup): once all strategies are migrated move this check under - // the default evictor args validation - if params.ThresholdPriority != nil && params.ThresholdPriorityClassName != "" { - klog.ErrorS(fmt.Errorf("priority threshold misconfigured"), "only one of priorityThreshold fields can be set", "pluginName", name) - return nil, fmt.Errorf("priority threshold misconfigured for plugin %v", name) - } - var priorityThreshold *api.PriorityThreshold - if strategy.Params != nil { - priorityThreshold = &api.PriorityThreshold{ - Value: strategy.Params.ThresholdPriority, - Name: strategy.Params.ThresholdPriorityClassName, - } - } - thresholdPriority, err := utils.GetPriorityFromStrategyParams(context.TODO(), client, priorityThreshold) - if err != nil { - klog.ErrorS(err, "Failed to get threshold priority from strategy's params") - return nil, fmt.Errorf("failed to get threshold priority from strategy's params: %v", err) - } - - var pluginConfig *api.PluginConfig - if pcFnc, exists := strategyParamsToPluginArgs[string(name)]; exists { - pluginConfig, err = pcFnc(params) - if err != nil { - klog.ErrorS(err, "skipping strategy", "strategy", name) - return nil, fmt.Errorf("failed to get plugin config for strategy %v: %v", name, err) - } - } else { - klog.ErrorS(fmt.Errorf("unknown strategy name"), "skipping strategy", "strategy", name) - return nil, fmt.Errorf("unknown strategy name: %v", name) - } - - profile := api.Profile{ - Name: fmt.Sprintf("strategy-%v-profile", name), - PluginConfigs: []api.PluginConfig{ - { - Name: defaultevictor.PluginName, - Args: &defaultevictor.DefaultEvictorArgs{ - EvictLocalStoragePods: evictLocalStoragePods, - EvictSystemCriticalPods: evictSystemCriticalPods, - IgnorePvcPods: ignorePvcPods, - EvictFailedBarePods: evictBarePods, - NodeFit: nodeFit, - PriorityThreshold: &api.PriorityThreshold{ - Value: &thresholdPriority, - }, - }, - }, - *pluginConfig, - }, - Plugins: api.Plugins{ - Evict: api.PluginSet{ - Enabled: []string{defaultevictor.PluginName}, - }, - }, - } - - 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 { - klog.ErrorS(fmt.Errorf("unknown strategy name"), "skipping strategy", "strategy", name) - return nil, fmt.Errorf("unknown strategy name: %v", name) } } - - return &api.DeschedulerPolicy{ - Profiles: profiles, - NodeSelector: deschedulerPolicy.NodeSelector, - MaxNoOfPodsToEvictPerNode: deschedulerPolicy.MaxNoOfPodsToEvictPerNode, - 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} + if errorsInProfiles != nil { + return errorsInProfiles } - return profilePlugins + return nil } -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} +func setErrorsInProfiles(err error, profileName string, errorsInProfiles error) error { + if err != nil { + if errorsInProfiles == nil { + errorsInProfiles = fmt.Errorf("in profile %s: %s", profileName, err.Error()) + } else { + errorsInProfiles = fmt.Errorf("%w: %s", errorsInProfiles, fmt.Sprintf("in profile %s: %s", profileName, err.Error())) + } } - return profilePlugins + return errorsInProfiles +} + +func hasPluginConfigsWithSameName(newPluginConfig api.PluginConfig, pluginConfigs []api.PluginConfig) bool { + for _, pluginConfig := range pluginConfigs { + if newPluginConfig.Name == pluginConfig.Name { + return true + } + } + return false } diff --git a/pkg/descheduler/policyconfig_test.go b/pkg/descheduler/policyconfig_test.go index 26922fc05..719541b31 100644 --- a/pkg/descheduler/policyconfig_test.go +++ b/pkg/descheduler/policyconfig_test.go @@ -25,9 +25,10 @@ import ( utilpointer "k8s.io/utils/pointer" "sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api/v1alpha1" + "sigs.k8s.io/descheduler/pkg/framework/pluginregistry" "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" @@ -682,7 +683,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, pluginbuilder.PluginRegistry) + result, err := v1alpha1.V1alpha1ToInternal(client, tc.policy, pluginregistry.PluginRegistry) if err != nil { if err.Error() != tc.err.Error() { t.Errorf("unexpected error: %s", err.Error()) @@ -699,3 +700,302 @@ func TestV1alpha1ToV1alpha2(t *testing.T) { }) } } + +func TestDecodeVersionedPolicy(t *testing.T) { + client := fakeclientset.NewSimpleClientset() + SetupPlugins() + defaultEvictorPluginConfig := api.PluginConfig{ + Name: defaultevictor.PluginName, + Args: &defaultevictor.DefaultEvictorArgs{ + PriorityThreshold: &api.PriorityThreshold{ + Value: utilpointer.Int32(utils.SystemCriticalPriority), + }, + }, + } + defaultEvictorPluginSet := api.PluginSet{ + Enabled: []string{defaultevictor.PluginName}, + } + type testCase struct { + description string + policy []byte + err error + result *api.DeschedulerPolicy + } + testCases := []testCase{ + { + description: "v1alpha1 to internal", + policy: []byte(`apiVersion: "descheduler/v1alpha1" +kind: "DeschedulerPolicy" +strategies: + "PodLifeTime": + enabled: true + params: + podLifeTime: + maxPodLifeTimeSeconds: 5 + namespaces: + include: + - "testleaderelection-a" +`), + result: &api.DeschedulerPolicy{ + Profiles: []api.Profile{ + { + Name: fmt.Sprintf("strategy-%s-profile", podlifetime.PluginName), + PluginConfigs: []api.PluginConfig{ + defaultEvictorPluginConfig, + { + Name: podlifetime.PluginName, + Args: &podlifetime.PodLifeTimeArgs{ + Namespaces: &api.Namespaces{ + Include: []string{"testleaderelection-a"}, + }, + MaxPodLifeTimeSeconds: utilpointer.Uint(5), + }, + }, + }, + Plugins: api.Plugins{ + Evict: defaultEvictorPluginSet, + Deschedule: api.PluginSet{ + Enabled: []string{podlifetime.PluginName}, + }, + }, + }, + }, + }, + }, + { + description: "v1aplha2 to internal", + policy: []byte(`apiVersion: "descheduler/v1alpha2" +kind: "DeschedulerPolicy" +profiles: + - name: ProfileName + pluginConfig: + - name: "DefaultEvictor" + args: + evictSystemCriticalPods: true + evictFailedBarePods: true + evictLocalStoragePods: true + nodeFit: true + - name: "RemovePodsHavingTooManyRestarts" + args: + podRestartThreshold: 100 + includingInitContainers: true + plugins: + filter: + enabled: + - "DefaultEvictor" + evict: + enabled: + - "DefaultEvictor" + deschedule: + enabled: + - "RemovePodsHavingTooManyRestarts" +`), + result: &api.DeschedulerPolicy{ + Profiles: []api.Profile{ + { + Name: "ProfileName", + PluginConfigs: []api.PluginConfig{ + { + Name: defaultevictor.PluginName, + Args: &defaultevictor.DefaultEvictorArgs{ + EvictSystemCriticalPods: true, + EvictFailedBarePods: true, + EvictLocalStoragePods: true, + NodeFit: true, + }, + }, + { + Name: removepodshavingtoomanyrestarts.PluginName, + Args: &removepodshavingtoomanyrestarts.RemovePodsHavingTooManyRestartsArgs{ + PodRestartThreshold: 100, + IncludingInitContainers: true, + }, + }, + }, + Plugins: api.Plugins{ + Evict: api.PluginSet{ + Enabled: []string{defaultevictor.PluginName}, + }, + Filter: api.PluginSet{ + Enabled: []string{defaultevictor.PluginName}, + }, + Deschedule: api.PluginSet{ + Enabled: []string{removepodshavingtoomanyrestarts.PluginName}, + }, + }, + }, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + result, err := decode("filename", tc.policy, client, pluginregistry.PluginRegistry) + if err != nil { + if tc.err == nil { + t.Errorf("unexpected error: %s.", err.Error()) + } else { + t.Errorf("unexpected error: %s. Was expecting %s", err.Error(), tc.err.Error()) + } + } + diff := cmp.Diff(tc.result, result) + if diff != "" && err == nil { + t.Errorf("test '%s' failed. Results are not deep equal. mismatch (-want +got):\n%s", tc.description, diff) + } + }) + } +} + +func TestValidateDeschedulerConfiguration(t *testing.T) { + SetupPlugins() + type testCase struct { + description string + deschedulerPolicy api.DeschedulerPolicy + result error + } + testCases := []testCase{ + { + description: "multiple errors", + deschedulerPolicy: api.DeschedulerPolicy{ + Profiles: []api.Profile{ + { + Name: removefailedpods.PluginName, + Plugins: api.Plugins{ + Deschedule: api.PluginSet{Enabled: []string{removefailedpods.PluginName}}, + }, + PluginConfigs: []api.PluginConfig{ + { + Name: removefailedpods.PluginName, + Args: &removefailedpods.RemoveFailedPodsArgs{ + Namespaces: &api.Namespaces{ + Include: []string{"test1"}, + Exclude: []string{"test1"}, + }, + }, + }, + }, + }, + { + Name: removepodsviolatingtopologyspreadconstraint.PluginName, + Plugins: api.Plugins{ + Deschedule: api.PluginSet{Enabled: []string{removepodsviolatingtopologyspreadconstraint.PluginName}}, + }, + PluginConfigs: []api.PluginConfig{ + { + Name: removepodsviolatingtopologyspreadconstraint.PluginName, + Args: &removepodsviolatingtopologyspreadconstraint.RemovePodsViolatingTopologySpreadConstraintArgs{ + Namespaces: &api.Namespaces{ + Include: []string{"test1"}, + Exclude: []string{"test1"}, + }, + }, + }, + }, + }, + }, + }, + result: fmt.Errorf("in profile RemoveFailedPods: profile with invalid number of evictor plugins enabled found. Please enable a single evictor plugin.: in profile RemoveFailedPods: only one of Include/Exclude namespaces can be set: in profile RemovePodsViolatingTopologySpreadConstraint: profile with invalid number of evictor plugins enabled found. Please enable a single evictor plugin.: in profile RemovePodsViolatingTopologySpreadConstraint: only one of Include/Exclude namespaces can be set"), + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + result := validateDeschedulerConfiguration(tc.deschedulerPolicy, pluginregistry.PluginRegistry) + if result.Error() != tc.result.Error() { + t.Errorf("test '%s' failed. expected \n'%s', got \n'%s'", tc.description, tc.result, result) + } + }) + } +} + +func TestDecodeDefaults(t *testing.T) { + client := fakeclientset.NewSimpleClientset() + SetupPlugins() + type testCase struct { + description string + policy []byte + err error + result *api.DeschedulerPolicy + } + testCases := []testCase{ + { + description: "use empty RemoveFailedPods, check MinPodLifetimeSeconds default", + policy: []byte(`apiVersion: "descheduler/v1alpha2" +kind: "DeschedulerPolicy" +profiles: + - name: ProfileName + pluginConfig: + - name: "DefaultEvictor" + args: + evictSystemCriticalPods: true + evictFailedBarePods: true + evictLocalStoragePods: true + nodeFit: true + - name: "RemoveFailedPods" + plugins: + filter: + enabled: + - "DefaultEvictor" + evict: + enabled: + - "DefaultEvictor" + deschedule: + enabled: + - "RemovePodsHavingTooManyRestarts" +`), + result: &api.DeschedulerPolicy{ + Profiles: []api.Profile{ + { + Name: "ProfileName", + PluginConfigs: []api.PluginConfig{ + { + Name: defaultevictor.PluginName, + Args: &defaultevictor.DefaultEvictorArgs{ + EvictSystemCriticalPods: true, + EvictFailedBarePods: true, + EvictLocalStoragePods: true, + NodeFit: true, + }, + }, + { + Name: removefailedpods.PluginName, + Args: &removefailedpods.RemoveFailedPodsArgs{ + MinPodLifetimeSeconds: utilpointer.Uint(3600), + }, + }, + }, + Plugins: api.Plugins{ + Evict: api.PluginSet{ + Enabled: []string{defaultevictor.PluginName}, + }, + Filter: api.PluginSet{ + Enabled: []string{defaultevictor.PluginName}, + }, + Deschedule: api.PluginSet{ + Enabled: []string{removepodshavingtoomanyrestarts.PluginName}, + }, + }, + }, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + result, err := decode("filename", tc.policy, client, pluginregistry.PluginRegistry) + if err != nil { + if tc.err == nil { + t.Errorf("unexpected error: %s.", err.Error()) + } else { + t.Errorf("unexpected error: %s. Was expecting %s", err.Error(), tc.err.Error()) + } + } + diff := cmp.Diff(tc.result, result) + if diff != "" && err == nil { + t.Errorf("test '%s' failed. Results are not deep equal. mismatch (-want +got):\n%s", tc.description, diff) + } + }) + } +} diff --git a/pkg/descheduler/scheme/scheme.go b/pkg/descheduler/scheme/scheme.go index 2949193c1..1e657abf4 100644 --- a/pkg/descheduler/scheme/scheme.go +++ b/pkg/descheduler/scheme/scheme.go @@ -22,8 +22,19 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" "sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api/v1alpha1" + "sigs.k8s.io/descheduler/pkg/api/v1alpha2" "sigs.k8s.io/descheduler/pkg/apis/componentconfig" componentconfigv1alpha1 "sigs.k8s.io/descheduler/pkg/apis/componentconfig/v1alpha1" + "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" + "sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization" + "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" ) var ( @@ -33,8 +44,23 @@ var ( func init() { utilruntime.Must(api.AddToScheme(Scheme)) - utilruntime.Must(v1alpha1.AddToScheme(Scheme)) + utilruntime.Must(defaultevictor.AddToScheme(Scheme)) + utilruntime.Must(nodeutilization.AddToScheme(Scheme)) + utilruntime.Must(podlifetime.AddToScheme(Scheme)) + utilruntime.Must(removeduplicates.AddToScheme(Scheme)) + utilruntime.Must(removefailedpods.AddToScheme(Scheme)) + utilruntime.Must(removepodshavingtoomanyrestarts.AddToScheme(Scheme)) + utilruntime.Must(removepodsviolatinginterpodantiaffinity.AddToScheme(Scheme)) + utilruntime.Must(removepodsviolatingnodeaffinity.AddToScheme(Scheme)) + utilruntime.Must(removepodsviolatingnodetaints.AddToScheme(Scheme)) + utilruntime.Must(removepodsviolatingtopologyspreadconstraint.AddToScheme(Scheme)) utilruntime.Must(componentconfig.AddToScheme(Scheme)) utilruntime.Must(componentconfigv1alpha1.AddToScheme(Scheme)) + utilruntime.Must(v1alpha1.AddToScheme(Scheme)) + utilruntime.Must(v1alpha2.AddToScheme(Scheme)) + utilruntime.Must(Scheme.SetVersionPriority( + v1alpha2.SchemeGroupVersion, + v1alpha1.SchemeGroupVersion, + )) } diff --git a/pkg/descheduler/setupplugins.go b/pkg/descheduler/setupplugins.go index 35cf01b12..9b2b5ce51 100644 --- a/pkg/descheduler/setupplugins.go +++ b/pkg/descheduler/setupplugins.go @@ -17,9 +17,9 @@ limitations under the License. package descheduler import ( + "sigs.k8s.io/descheduler/pkg/framework/pluginregistry" "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" @@ -31,20 +31,20 @@ import ( ) func SetupPlugins() { - pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry() - RegisterDefaultPlugins(pluginbuilder.PluginRegistry) + pluginregistry.PluginRegistry = pluginregistry.NewRegistry() + RegisterDefaultPlugins(pluginregistry.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) +func RegisterDefaultPlugins(registry pluginregistry.Registry) { + pluginregistry.Register(defaultevictor.PluginName, defaultevictor.New, &defaultevictor.DefaultEvictorArgs{}, defaultevictor.ValidateDefaultEvictorArgs, defaultevictor.SetDefaults_DefaultEvictorArgs, registry) + pluginregistry.Register(nodeutilization.LowNodeUtilizationPluginName, nodeutilization.NewLowNodeUtilization, &nodeutilization.LowNodeUtilizationArgs{}, nodeutilization.ValidateLowNodeUtilizationArgs, nodeutilization.SetDefaults_LowNodeUtilizationArgs, registry) + pluginregistry.Register(nodeutilization.HighNodeUtilizationPluginName, nodeutilization.NewHighNodeUtilization, &nodeutilization.HighNodeUtilizationArgs{}, nodeutilization.ValidateHighNodeUtilizationArgs, nodeutilization.SetDefaults_HighNodeUtilizationArgs, registry) + pluginregistry.Register(podlifetime.PluginName, podlifetime.New, &podlifetime.PodLifeTimeArgs{}, podlifetime.ValidatePodLifeTimeArgs, podlifetime.SetDefaults_PodLifeTimeArgs, registry) + pluginregistry.Register(removeduplicates.PluginName, removeduplicates.New, &removeduplicates.RemoveDuplicatesArgs{}, removeduplicates.ValidateRemoveDuplicatesArgs, removeduplicates.SetDefaults_RemoveDuplicatesArgs, registry) + pluginregistry.Register(removefailedpods.PluginName, removefailedpods.New, &removefailedpods.RemoveFailedPodsArgs{}, removefailedpods.ValidateRemoveFailedPodsArgs, removefailedpods.SetDefaults_RemoveFailedPodsArgs, registry) + pluginregistry.Register(removepodshavingtoomanyrestarts.PluginName, removepodshavingtoomanyrestarts.New, &removepodshavingtoomanyrestarts.RemovePodsHavingTooManyRestartsArgs{}, removepodshavingtoomanyrestarts.ValidateRemovePodsHavingTooManyRestartsArgs, removepodshavingtoomanyrestarts.SetDefaults_RemovePodsHavingTooManyRestartsArgs, registry) + pluginregistry.Register(removepodsviolatinginterpodantiaffinity.PluginName, removepodsviolatinginterpodantiaffinity.New, &removepodsviolatinginterpodantiaffinity.RemovePodsViolatingInterPodAntiAffinityArgs{}, removepodsviolatinginterpodantiaffinity.ValidateRemovePodsViolatingInterPodAntiAffinityArgs, removepodsviolatinginterpodantiaffinity.SetDefaults_RemovePodsViolatingInterPodAntiAffinityArgs, registry) + pluginregistry.Register(removepodsviolatingnodeaffinity.PluginName, removepodsviolatingnodeaffinity.New, &removepodsviolatingnodeaffinity.RemovePodsViolatingNodeAffinityArgs{}, removepodsviolatingnodeaffinity.ValidateRemovePodsViolatingNodeAffinityArgs, removepodsviolatingnodeaffinity.SetDefaults_RemovePodsViolatingNodeAffinityArgs, registry) + pluginregistry.Register(removepodsviolatingnodetaints.PluginName, removepodsviolatingnodetaints.New, &removepodsviolatingnodetaints.RemovePodsViolatingNodeTaintsArgs{}, removepodsviolatingnodetaints.ValidateRemovePodsViolatingNodeTaintsArgs, removepodsviolatingnodetaints.SetDefaults_RemovePodsViolatingNodeTaintsArgs, registry) + pluginregistry.Register(removepodsviolatingtopologyspreadconstraint.PluginName, removepodsviolatingtopologyspreadconstraint.New, &removepodsviolatingtopologyspreadconstraint.RemovePodsViolatingTopologySpreadConstraintArgs{}, removepodsviolatingtopologyspreadconstraint.ValidateRemovePodsViolatingTopologySpreadConstraintArgs, removepodsviolatingtopologyspreadconstraint.SetDefaults_RemovePodsViolatingTopologySpreadConstraintArgs, registry) } diff --git a/pkg/framework/plugins/pluginbuilder/pluginbuilder.go b/pkg/framework/pluginregistry/pluginregistry.go similarity index 62% rename from pkg/framework/plugins/pluginbuilder/pluginbuilder.go rename to pkg/framework/pluginregistry/pluginregistry.go index d7971f462..f5b2dd27a 100644 --- a/pkg/framework/plugins/pluginbuilder/pluginbuilder.go +++ b/pkg/framework/pluginregistry/pluginregistry.go @@ -1,9 +1,12 @@ /* -Copyright 2022 The Kubernetes Authors. +Copyright 2023 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. @@ -11,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package pluginbuilder +package pluginregistry import ( "k8s.io/apimachinery/pkg/runtime" @@ -21,28 +24,37 @@ import ( var PluginRegistry Registry -type PluginBuilderAndArgsInstance struct { +type PluginUtilities struct { PluginBuilder PluginBuilder // Just an example instance of this PluginArg so we can avoid having // to deal with reflect Types - PluginArgInstance runtime.Object + PluginArgInstance runtime.Object + PluginArgValidator PluginArgValidator + PluginArgDefaulter PluginArgDefaulter } type PluginBuilder = func(args runtime.Object, handle framework.Handle) (framework.Plugin, error) -type Registry = map[string]PluginBuilderAndArgsInstance +type ( + PluginArgValidator = func(args runtime.Object) error + PluginArgDefaulter = func(args runtime.Object) +) + +type Registry = map[string]PluginUtilities func NewRegistry() Registry { return Registry{} } -func Register(name string, builderFunc PluginBuilder, exampleArg runtime.Object, registry Registry) { +func Register(name string, builderFunc PluginBuilder, exampleArg runtime.Object, pluginArgValidator PluginArgValidator, pluginArgDefaulter PluginArgDefaulter, registry Registry) { if _, ok := registry[name]; ok { klog.V(10).InfoS("Plugin already registered", "plugin", name) } else { - registry[name] = PluginBuilderAndArgsInstance{ - PluginBuilder: builderFunc, - PluginArgInstance: exampleArg, + registry[name] = PluginUtilities{ + PluginBuilder: builderFunc, + PluginArgInstance: exampleArg, + PluginArgValidator: pluginArgValidator, + PluginArgDefaulter: pluginArgDefaulter, } } } diff --git a/pkg/framework/plugins/defaultevictor/defaults.go b/pkg/framework/plugins/defaultevictor/defaults.go index f71731c45..57838f2c7 100644 --- a/pkg/framework/plugins/defaultevictor/defaults.go +++ b/pkg/framework/plugins/defaultevictor/defaults.go @@ -23,29 +23,30 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_DefaultEvictorArgs // TODO: the final default values would be discussed in community -func SetDefaults_DefaultEvictorArgs(obj *DefaultEvictorArgs) { - if obj.NodeSelector == "" { - obj.NodeSelector = "" +func SetDefaults_DefaultEvictorArgs(obj runtime.Object) { + args := obj.(*DefaultEvictorArgs) + if args.NodeSelector == "" { + args.NodeSelector = "" } - if !obj.EvictLocalStoragePods { - obj.EvictSystemCriticalPods = false + if !args.EvictLocalStoragePods { + args.EvictSystemCriticalPods = false } - if !obj.EvictSystemCriticalPods { - obj.EvictSystemCriticalPods = false + if !args.EvictSystemCriticalPods { + args.EvictSystemCriticalPods = false } - if !obj.IgnorePvcPods { - obj.IgnorePvcPods = false + if !args.IgnorePvcPods { + args.IgnorePvcPods = false } - if !obj.EvictFailedBarePods { - obj.EvictFailedBarePods = false + if !args.EvictFailedBarePods { + args.EvictFailedBarePods = false } - if obj.LabelSelector == nil { - obj.LabelSelector = nil + if args.LabelSelector == nil { + args.LabelSelector = nil } - if obj.PriorityThreshold == nil { - obj.PriorityThreshold = nil + if args.PriorityThreshold == nil { + args.PriorityThreshold = nil } - if !obj.NodeFit { - obj.NodeFit = false + if !args.NodeFit { + args.NodeFit = false } } diff --git a/pkg/framework/plugins/defaultevictor/validation.go b/pkg/framework/plugins/defaultevictor/validation.go new file mode 100644 index 000000000..75ad6fecc --- /dev/null +++ b/pkg/framework/plugins/defaultevictor/validation.go @@ -0,0 +1,30 @@ +/* +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 defaultevictor + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/runtime" +) + +func ValidateDefaultEvictorArgs(obj runtime.Object) error { + args := obj.(*DefaultEvictorArgs) + + if args.PriorityThreshold != nil && len(args.PriorityThreshold.Name) > 0 { + return fmt.Errorf("priority threshold misconfigured, only one of priorityThreshold fields can be set, got %v", args) + } + + return nil +} diff --git a/pkg/framework/plugins/defaultevictor/zz_generated.defaults.go b/pkg/framework/plugins/defaultevictor/zz_generated.defaults.go index 2b83eff3a..f69750785 100644 --- a/pkg/framework/plugins/defaultevictor/zz_generated.defaults.go +++ b/pkg/framework/plugins/defaultevictor/zz_generated.defaults.go @@ -29,10 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&DefaultEvictorArgs{}, func(obj interface{}) { SetObjectDefaults_DefaultEvictorArgs(obj.(*DefaultEvictorArgs)) }) return nil } - -func SetObjectDefaults_DefaultEvictorArgs(in *DefaultEvictorArgs) { - SetDefaults_DefaultEvictorArgs(in) -} diff --git a/pkg/framework/plugins/nodeutilization/defaults.go b/pkg/framework/plugins/nodeutilization/defaults.go index 6621a1863..a1c6dfe0b 100644 --- a/pkg/framework/plugins/nodeutilization/defaults.go +++ b/pkg/framework/plugins/nodeutilization/defaults.go @@ -23,28 +23,30 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_LowNodeUtilizationArgs // TODO: the final default values would be discussed in community -func SetDefaults_LowNodeUtilizationArgs(obj *LowNodeUtilizationArgs) { - if !obj.UseDeviationThresholds { - obj.UseDeviationThresholds = false +func SetDefaults_LowNodeUtilizationArgs(obj runtime.Object) { + args := obj.(*LowNodeUtilizationArgs) + if !args.UseDeviationThresholds { + args.UseDeviationThresholds = false } - if obj.Thresholds == nil { - obj.Thresholds = nil + if args.Thresholds == nil { + args.Thresholds = nil } - if obj.TargetThresholds == nil { - obj.TargetThresholds = nil + if args.TargetThresholds == nil { + args.TargetThresholds = nil } - if obj.NumberOfNodes == 0 { - obj.NumberOfNodes = 0 + if args.NumberOfNodes == 0 { + args.NumberOfNodes = 0 } } // SetDefaults_HighNodeUtilizationArgs // TODO: the final default values would be discussed in community -func SetDefaults_HighNodeUtilizationArgs(obj *HighNodeUtilizationArgs) { - if obj.Thresholds == nil { - obj.Thresholds = nil +func SetDefaults_HighNodeUtilizationArgs(obj runtime.Object) { + args := obj.(*HighNodeUtilizationArgs) + if args.Thresholds == nil { + args.Thresholds = nil } - if obj.NumberOfNodes == 0 { - obj.NumberOfNodes = 0 + if args.NumberOfNodes == 0 { + args.NumberOfNodes = 0 } } diff --git a/pkg/framework/plugins/nodeutilization/validation.go b/pkg/framework/plugins/nodeutilization/validation.go index ab7d450e1..5df502483 100644 --- a/pkg/framework/plugins/nodeutilization/validation.go +++ b/pkg/framework/plugins/nodeutilization/validation.go @@ -16,10 +16,12 @@ package nodeutilization import ( "fmt" + "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/descheduler/pkg/api" ) -func ValidateHighNodeUtilizationArgs(args *HighNodeUtilizationArgs) error { +func ValidateHighNodeUtilizationArgs(obj runtime.Object) error { + args := obj.(*HighNodeUtilizationArgs) // only exclude can be set, or not at all if args.EvictableNamespaces != nil && len(args.EvictableNamespaces.Include) > 0 { return fmt.Errorf("only Exclude namespaces can be set, inclusion is not supported") @@ -32,7 +34,8 @@ func ValidateHighNodeUtilizationArgs(args *HighNodeUtilizationArgs) error { return nil } -func ValidateLowNodeUtilizationArgs(args *LowNodeUtilizationArgs) error { +func ValidateLowNodeUtilizationArgs(obj runtime.Object) error { + args := obj.(*LowNodeUtilizationArgs) // only exclude can be set, or not at all if args.EvictableNamespaces != nil && len(args.EvictableNamespaces.Include) > 0 { return fmt.Errorf("only Exclude namespaces can be set, inclusion is not supported") diff --git a/pkg/framework/plugins/nodeutilization/zz_generated.defaults.go b/pkg/framework/plugins/nodeutilization/zz_generated.defaults.go index 87abab1f4..42bf5d6dd 100644 --- a/pkg/framework/plugins/nodeutilization/zz_generated.defaults.go +++ b/pkg/framework/plugins/nodeutilization/zz_generated.defaults.go @@ -29,15 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&HighNodeUtilizationArgs{}, func(obj interface{}) { SetObjectDefaults_HighNodeUtilizationArgs(obj.(*HighNodeUtilizationArgs)) }) - scheme.AddTypeDefaultingFunc(&LowNodeUtilizationArgs{}, func(obj interface{}) { SetObjectDefaults_LowNodeUtilizationArgs(obj.(*LowNodeUtilizationArgs)) }) return nil } - -func SetObjectDefaults_HighNodeUtilizationArgs(in *HighNodeUtilizationArgs) { - SetDefaults_HighNodeUtilizationArgs(in) -} - -func SetObjectDefaults_LowNodeUtilizationArgs(in *LowNodeUtilizationArgs) { - SetDefaults_LowNodeUtilizationArgs(in) -} diff --git a/pkg/framework/plugins/podlifetime/defaults.go b/pkg/framework/plugins/podlifetime/defaults.go index b4aaa3686..b669e781c 100644 --- a/pkg/framework/plugins/podlifetime/defaults.go +++ b/pkg/framework/plugins/podlifetime/defaults.go @@ -23,17 +23,18 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_PodLifeTimeArgs // TODO: the final default values would be discussed in community -func SetDefaults_PodLifeTimeArgs(obj *PodLifeTimeArgs) { - if obj.Namespaces == nil { - obj.Namespaces = nil +func SetDefaults_PodLifeTimeArgs(obj runtime.Object) { + args := obj.(*PodLifeTimeArgs) + if args.Namespaces == nil { + args.Namespaces = nil } - if obj.LabelSelector == nil { - obj.LabelSelector = nil + if args.LabelSelector == nil { + args.LabelSelector = nil } - if obj.MaxPodLifeTimeSeconds == nil { - obj.MaxPodLifeTimeSeconds = nil + if args.MaxPodLifeTimeSeconds == nil { + args.MaxPodLifeTimeSeconds = nil } - if obj.States == nil { - obj.States = nil + if args.States == nil { + args.States = nil } } diff --git a/pkg/framework/plugins/podlifetime/validation.go b/pkg/framework/plugins/podlifetime/validation.go index c7dd72be2..144120beb 100644 --- a/pkg/framework/plugins/podlifetime/validation.go +++ b/pkg/framework/plugins/podlifetime/validation.go @@ -19,13 +19,16 @@ package podlifetime import ( "fmt" + "k8s.io/apimachinery/pkg/runtime" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" ) // ValidatePodLifeTimeArgs validates PodLifeTime arguments -func ValidatePodLifeTimeArgs(args *PodLifeTimeArgs) error { +func ValidatePodLifeTimeArgs(obj runtime.Object) error { + args := obj.(*PodLifeTimeArgs) if args.MaxPodLifeTimeSeconds == nil { return fmt.Errorf("MaxPodLifeTimeSeconds not set") } diff --git a/pkg/framework/plugins/podlifetime/zz_generated.defaults.go b/pkg/framework/plugins/podlifetime/zz_generated.defaults.go index 74e8e6c5b..d5eeb657c 100644 --- a/pkg/framework/plugins/podlifetime/zz_generated.defaults.go +++ b/pkg/framework/plugins/podlifetime/zz_generated.defaults.go @@ -29,10 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&PodLifeTimeArgs{}, func(obj interface{}) { SetObjectDefaults_PodLifeTimeArgs(obj.(*PodLifeTimeArgs)) }) return nil } - -func SetObjectDefaults_PodLifeTimeArgs(in *PodLifeTimeArgs) { - SetDefaults_PodLifeTimeArgs(in) -} diff --git a/pkg/framework/plugins/removeduplicates/defaults.go b/pkg/framework/plugins/removeduplicates/defaults.go index 7da4f6898..1ed3020e7 100644 --- a/pkg/framework/plugins/removeduplicates/defaults.go +++ b/pkg/framework/plugins/removeduplicates/defaults.go @@ -23,11 +23,12 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_RemoveDuplicatesArgs // TODO: the final default values would be discussed in community -func SetDefaults_RemoveDuplicatesArgs(obj *RemoveDuplicatesArgs) { - if obj.Namespaces == nil { - obj.Namespaces = nil +func SetDefaults_RemoveDuplicatesArgs(obj runtime.Object) { + args := obj.(*RemoveDuplicatesArgs) + if args.Namespaces == nil { + args.Namespaces = nil } - if obj.ExcludeOwnerKinds == nil { - obj.ExcludeOwnerKinds = nil + if args.ExcludeOwnerKinds == nil { + args.ExcludeOwnerKinds = nil } } diff --git a/pkg/framework/plugins/removeduplicates/validation.go b/pkg/framework/plugins/removeduplicates/validation.go index 240bd36e9..a2e359e44 100644 --- a/pkg/framework/plugins/removeduplicates/validation.go +++ b/pkg/framework/plugins/removeduplicates/validation.go @@ -15,9 +15,12 @@ package removeduplicates import ( "fmt" + + "k8s.io/apimachinery/pkg/runtime" ) -func ValidateRemoveDuplicatesArgs(args *RemoveDuplicatesArgs) error { +func ValidateRemoveDuplicatesArgs(obj runtime.Object) error { + args := obj.(*RemoveDuplicatesArgs) // At most one of include/exclude can be set if args.Namespaces != nil && len(args.Namespaces.Include) > 0 && len(args.Namespaces.Exclude) > 0 { return fmt.Errorf("only one of Include/Exclude namespaces can be set") diff --git a/pkg/framework/plugins/removeduplicates/zz_generated.defaults.go b/pkg/framework/plugins/removeduplicates/zz_generated.defaults.go index 097a7e95a..6148aa0c8 100644 --- a/pkg/framework/plugins/removeduplicates/zz_generated.defaults.go +++ b/pkg/framework/plugins/removeduplicates/zz_generated.defaults.go @@ -29,10 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&RemoveDuplicatesArgs{}, func(obj interface{}) { SetObjectDefaults_RemoveDuplicatesArgs(obj.(*RemoveDuplicatesArgs)) }) return nil } - -func SetObjectDefaults_RemoveDuplicatesArgs(in *RemoveDuplicatesArgs) { - SetDefaults_RemoveDuplicatesArgs(in) -} diff --git a/pkg/framework/plugins/removefailedpods/defaults.go b/pkg/framework/plugins/removefailedpods/defaults.go index 52f95e1c6..3fa38d165 100644 --- a/pkg/framework/plugins/removefailedpods/defaults.go +++ b/pkg/framework/plugins/removefailedpods/defaults.go @@ -15,6 +15,7 @@ package removefailedpods import ( "k8s.io/apimachinery/pkg/runtime" + utilpointer "k8s.io/utils/pointer" ) func addDefaultingFuncs(scheme *runtime.Scheme) error { @@ -23,23 +24,24 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_RemoveFailedPodsArgs // TODO: the final default values would be discussed in community -func SetDefaults_RemoveFailedPodsArgs(obj *RemoveFailedPodsArgs) { - if obj.Namespaces == nil { - obj.Namespaces = nil +func SetDefaults_RemoveFailedPodsArgs(obj runtime.Object) { + args := obj.(*RemoveFailedPodsArgs) + if args.Namespaces == nil { + args.Namespaces = nil } - if obj.LabelSelector == nil { - obj.LabelSelector = nil + if args.LabelSelector == nil { + args.LabelSelector = nil } - if obj.ExcludeOwnerKinds == nil { - obj.ExcludeOwnerKinds = nil + if args.ExcludeOwnerKinds == nil { + args.ExcludeOwnerKinds = nil } - if obj.MinPodLifetimeSeconds == nil { - obj.MinPodLifetimeSeconds = nil + if args.MinPodLifetimeSeconds == nil { + args.MinPodLifetimeSeconds = utilpointer.Uint(3600) } - if obj.Reasons == nil { - obj.Reasons = nil + if args.Reasons == nil { + args.Reasons = nil } - if !obj.IncludingInitContainers { - obj.IncludingInitContainers = false + if !args.IncludingInitContainers { + args.IncludingInitContainers = false } } diff --git a/pkg/framework/plugins/removefailedpods/validation.go b/pkg/framework/plugins/removefailedpods/validation.go index 11aa6c7d3..6d04065ba 100644 --- a/pkg/framework/plugins/removefailedpods/validation.go +++ b/pkg/framework/plugins/removefailedpods/validation.go @@ -17,10 +17,12 @@ import ( "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) // ValidateRemoveFailedPodsArgs validates RemoveFailedPods arguments -func ValidateRemoveFailedPodsArgs(args *RemoveFailedPodsArgs) error { +func ValidateRemoveFailedPodsArgs(obj runtime.Object) error { + args := obj.(*RemoveFailedPodsArgs) // At most one of include/exclude can be set if args.Namespaces != nil && len(args.Namespaces.Include) > 0 && len(args.Namespaces.Exclude) > 0 { return fmt.Errorf("only one of Include/Exclude namespaces can be set") diff --git a/pkg/framework/plugins/removefailedpods/zz_generated.defaults.go b/pkg/framework/plugins/removefailedpods/zz_generated.defaults.go index aaa7f1f16..85e9449f4 100644 --- a/pkg/framework/plugins/removefailedpods/zz_generated.defaults.go +++ b/pkg/framework/plugins/removefailedpods/zz_generated.defaults.go @@ -29,10 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&RemoveFailedPodsArgs{}, func(obj interface{}) { SetObjectDefaults_RemoveFailedPodsArgs(obj.(*RemoveFailedPodsArgs)) }) return nil } - -func SetObjectDefaults_RemoveFailedPodsArgs(in *RemoveFailedPodsArgs) { - SetDefaults_RemoveFailedPodsArgs(in) -} diff --git a/pkg/framework/plugins/removepodshavingtoomanyrestarts/defaults.go b/pkg/framework/plugins/removepodshavingtoomanyrestarts/defaults.go index e62af8e72..539f66160 100644 --- a/pkg/framework/plugins/removepodshavingtoomanyrestarts/defaults.go +++ b/pkg/framework/plugins/removepodshavingtoomanyrestarts/defaults.go @@ -23,17 +23,18 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_RemovePodsHavingTooManyRestartsArgs // TODO: the final default values would be discussed in community -func SetDefaults_RemovePodsHavingTooManyRestartsArgs(obj *RemovePodsHavingTooManyRestartsArgs) { - if obj.Namespaces == nil { - obj.Namespaces = nil +func SetDefaults_RemovePodsHavingTooManyRestartsArgs(obj runtime.Object) { + args := obj.(*RemovePodsHavingTooManyRestartsArgs) + if args.Namespaces == nil { + args.Namespaces = nil } - if obj.LabelSelector == nil { - obj.LabelSelector = nil + if args.LabelSelector == nil { + args.LabelSelector = nil } - if obj.PodRestartThreshold == 0 { - obj.PodRestartThreshold = 0 + if args.PodRestartThreshold == 0 { + args.PodRestartThreshold = 0 } - if !obj.IncludingInitContainers { - obj.IncludingInitContainers = false + if !args.IncludingInitContainers { + args.IncludingInitContainers = false } } diff --git a/pkg/framework/plugins/removepodshavingtoomanyrestarts/validation.go b/pkg/framework/plugins/removepodshavingtoomanyrestarts/validation.go index cfb736532..d734f3c74 100644 --- a/pkg/framework/plugins/removepodshavingtoomanyrestarts/validation.go +++ b/pkg/framework/plugins/removepodshavingtoomanyrestarts/validation.go @@ -17,10 +17,12 @@ import ( "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) // ValidateRemovePodsHavingTooManyRestartsArgs validates RemovePodsHavingTooManyRestarts arguments -func ValidateRemovePodsHavingTooManyRestartsArgs(args *RemovePodsHavingTooManyRestartsArgs) error { +func ValidateRemovePodsHavingTooManyRestartsArgs(obj runtime.Object) error { + args := obj.(*RemovePodsHavingTooManyRestartsArgs) // At most one of include/exclude can be set if args.Namespaces != nil && len(args.Namespaces.Include) > 0 && len(args.Namespaces.Exclude) > 0 { return fmt.Errorf("only one of Include/Exclude namespaces can be set") diff --git a/pkg/framework/plugins/removepodshavingtoomanyrestarts/zz_generated.defaults.go b/pkg/framework/plugins/removepodshavingtoomanyrestarts/zz_generated.defaults.go index 09014db69..fb8110bb1 100644 --- a/pkg/framework/plugins/removepodshavingtoomanyrestarts/zz_generated.defaults.go +++ b/pkg/framework/plugins/removepodshavingtoomanyrestarts/zz_generated.defaults.go @@ -29,12 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&RemovePodsHavingTooManyRestartsArgs{}, func(obj interface{}) { - SetObjectDefaults_RemovePodsHavingTooManyRestartsArgs(obj.(*RemovePodsHavingTooManyRestartsArgs)) - }) return nil } - -func SetObjectDefaults_RemovePodsHavingTooManyRestartsArgs(in *RemovePodsHavingTooManyRestartsArgs) { - SetDefaults_RemovePodsHavingTooManyRestartsArgs(in) -} diff --git a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/defaults.go b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/defaults.go index 75a51362f..bfbdb5b82 100644 --- a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/defaults.go +++ b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/defaults.go @@ -23,11 +23,12 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_RemovePodsViolatingInterPodAntiAffinityArgs // TODO: the final default values would be discussed in community -func SetDefaults_RemovePodsViolatingInterPodAntiAffinityArgs(obj *RemovePodsViolatingInterPodAntiAffinityArgs) { - if obj.Namespaces == nil { - obj.Namespaces = nil +func SetDefaults_RemovePodsViolatingInterPodAntiAffinityArgs(obj runtime.Object) { + args := obj.(*RemovePodsViolatingInterPodAntiAffinityArgs) + if args.Namespaces == nil { + args.Namespaces = nil } - if obj.LabelSelector == nil { - obj.LabelSelector = nil + if args.LabelSelector == nil { + args.LabelSelector = nil } } diff --git a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/validation.go b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/validation.go index c20708efd..514cdb8e4 100644 --- a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/validation.go +++ b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/validation.go @@ -17,10 +17,12 @@ import ( "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) // ValidateRemovePodsViolatingInterPodAntiAffinityArgs validates ValidateRemovePodsViolatingInterPodAntiAffinity arguments -func ValidateRemovePodsViolatingInterPodAntiAffinityArgs(args *RemovePodsViolatingInterPodAntiAffinityArgs) error { +func ValidateRemovePodsViolatingInterPodAntiAffinityArgs(obj runtime.Object) error { + args := obj.(*RemovePodsViolatingInterPodAntiAffinityArgs) // At most one of include/exclude can be set if args.Namespaces != nil && len(args.Namespaces.Include) > 0 && len(args.Namespaces.Exclude) > 0 { return fmt.Errorf("only one of Include/Exclude namespaces can be set") diff --git a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/zz_generated.defaults.go b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/zz_generated.defaults.go index 5f8afee0b..b6bdebf76 100644 --- a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/zz_generated.defaults.go +++ b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/zz_generated.defaults.go @@ -29,12 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&RemovePodsViolatingInterPodAntiAffinityArgs{}, func(obj interface{}) { - SetObjectDefaults_RemovePodsViolatingInterPodAntiAffinityArgs(obj.(*RemovePodsViolatingInterPodAntiAffinityArgs)) - }) return nil } - -func SetObjectDefaults_RemovePodsViolatingInterPodAntiAffinityArgs(in *RemovePodsViolatingInterPodAntiAffinityArgs) { - SetDefaults_RemovePodsViolatingInterPodAntiAffinityArgs(in) -} diff --git a/pkg/framework/plugins/removepodsviolatingnodeaffinity/defaults.go b/pkg/framework/plugins/removepodsviolatingnodeaffinity/defaults.go index e8f5cf2cb..1fac940c8 100644 --- a/pkg/framework/plugins/removepodsviolatingnodeaffinity/defaults.go +++ b/pkg/framework/plugins/removepodsviolatingnodeaffinity/defaults.go @@ -23,11 +23,12 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_RemovePodsViolatingNodeAffinityArgs // TODO: the final default values would be discussed in community -func SetDefaults_RemovePodsViolatingNodeAffinityArgs(obj *RemovePodsViolatingNodeAffinityArgs) { - if obj.Namespaces == nil { - obj.Namespaces = nil +func SetDefaults_RemovePodsViolatingNodeAffinityArgs(obj runtime.Object) { + args := obj.(*RemovePodsViolatingNodeAffinityArgs) + if args.Namespaces == nil { + args.Namespaces = nil } - if obj.LabelSelector == nil { - obj.LabelSelector = nil + if args.LabelSelector == nil { + args.LabelSelector = nil } } diff --git a/pkg/framework/plugins/removepodsviolatingnodeaffinity/validation.go b/pkg/framework/plugins/removepodsviolatingnodeaffinity/validation.go index 28130aca3..8c95291eb 100644 --- a/pkg/framework/plugins/removepodsviolatingnodeaffinity/validation.go +++ b/pkg/framework/plugins/removepodsviolatingnodeaffinity/validation.go @@ -20,10 +20,12 @@ import ( "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) // ValidateRemovePodsViolatingNodeAffinityArgs validates RemovePodsViolatingNodeAffinity arguments -func ValidateRemovePodsViolatingNodeAffinityArgs(args *RemovePodsViolatingNodeAffinityArgs) error { +func ValidateRemovePodsViolatingNodeAffinityArgs(obj runtime.Object) error { + args := obj.(*RemovePodsViolatingNodeAffinityArgs) if args == nil || len(args.NodeAffinityType) == 0 { return fmt.Errorf("nodeAffinityType needs to be set") } diff --git a/pkg/framework/plugins/removepodsviolatingnodeaffinity/zz_generated.defaults.go b/pkg/framework/plugins/removepodsviolatingnodeaffinity/zz_generated.defaults.go index b8921fee8..b395c6ee9 100644 --- a/pkg/framework/plugins/removepodsviolatingnodeaffinity/zz_generated.defaults.go +++ b/pkg/framework/plugins/removepodsviolatingnodeaffinity/zz_generated.defaults.go @@ -29,12 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&RemovePodsViolatingNodeAffinityArgs{}, func(obj interface{}) { - SetObjectDefaults_RemovePodsViolatingNodeAffinityArgs(obj.(*RemovePodsViolatingNodeAffinityArgs)) - }) return nil } - -func SetObjectDefaults_RemovePodsViolatingNodeAffinityArgs(in *RemovePodsViolatingNodeAffinityArgs) { - SetDefaults_RemovePodsViolatingNodeAffinityArgs(in) -} diff --git a/pkg/framework/plugins/removepodsviolatingnodetaints/defaults.go b/pkg/framework/plugins/removepodsviolatingnodetaints/defaults.go index 12eebb91b..ca026650b 100644 --- a/pkg/framework/plugins/removepodsviolatingnodetaints/defaults.go +++ b/pkg/framework/plugins/removepodsviolatingnodetaints/defaults.go @@ -23,17 +23,18 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_RemovePodsViolatingNodeTaintsArgs // TODO: the final default values would be discussed in community -func SetDefaults_RemovePodsViolatingNodeTaintsArgs(obj *RemovePodsViolatingNodeTaintsArgs) { - if obj.Namespaces == nil { - obj.Namespaces = nil +func SetDefaults_RemovePodsViolatingNodeTaintsArgs(obj runtime.Object) { + args := obj.(*RemovePodsViolatingNodeTaintsArgs) + if args.Namespaces == nil { + args.Namespaces = nil } - if obj.LabelSelector == nil { - obj.LabelSelector = nil + if args.LabelSelector == nil { + args.LabelSelector = nil } - if !obj.IncludePreferNoSchedule { - obj.IncludePreferNoSchedule = false + if !args.IncludePreferNoSchedule { + args.IncludePreferNoSchedule = false } - if obj.ExcludedTaints == nil { - obj.ExcludedTaints = nil + if args.ExcludedTaints == nil { + args.ExcludedTaints = nil } } diff --git a/pkg/framework/plugins/removepodsviolatingnodetaints/validation.go b/pkg/framework/plugins/removepodsviolatingnodetaints/validation.go index 6bea7543f..c7f6fc6b3 100644 --- a/pkg/framework/plugins/removepodsviolatingnodetaints/validation.go +++ b/pkg/framework/plugins/removepodsviolatingnodetaints/validation.go @@ -20,10 +20,12 @@ import ( "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) // ValidateRemovePodsViolatingNodeTaintsArgs validates RemovePodsViolatingNodeTaints arguments -func ValidateRemovePodsViolatingNodeTaintsArgs(args *RemovePodsViolatingNodeTaintsArgs) error { +func ValidateRemovePodsViolatingNodeTaintsArgs(obj runtime.Object) error { + args := obj.(*RemovePodsViolatingNodeTaintsArgs) // At most one of include/exclude can be set if args.Namespaces != nil && len(args.Namespaces.Include) > 0 && len(args.Namespaces.Exclude) > 0 { return fmt.Errorf("only one of Include/Exclude namespaces can be set") diff --git a/pkg/framework/plugins/removepodsviolatingnodetaints/zz_generated.defaults.go b/pkg/framework/plugins/removepodsviolatingnodetaints/zz_generated.defaults.go index aaaec1a13..f400d5415 100644 --- a/pkg/framework/plugins/removepodsviolatingnodetaints/zz_generated.defaults.go +++ b/pkg/framework/plugins/removepodsviolatingnodetaints/zz_generated.defaults.go @@ -29,12 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&RemovePodsViolatingNodeTaintsArgs{}, func(obj interface{}) { - SetObjectDefaults_RemovePodsViolatingNodeTaintsArgs(obj.(*RemovePodsViolatingNodeTaintsArgs)) - }) return nil } - -func SetObjectDefaults_RemovePodsViolatingNodeTaintsArgs(in *RemovePodsViolatingNodeTaintsArgs) { - SetDefaults_RemovePodsViolatingNodeTaintsArgs(in) -} diff --git a/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/defaults.go b/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/defaults.go index 6d62ee684..ff468c215 100644 --- a/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/defaults.go +++ b/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/defaults.go @@ -23,14 +23,15 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error { // SetDefaults_RemovePodsViolatingTopologySpreadConstraintArgs // TODO: the final default values would be discussed in community -func SetDefaults_RemovePodsViolatingTopologySpreadConstraintArgs(obj *RemovePodsViolatingTopologySpreadConstraintArgs) { - if obj.Namespaces == nil { - obj.Namespaces = nil +func SetDefaults_RemovePodsViolatingTopologySpreadConstraintArgs(obj runtime.Object) { + args := obj.(*RemovePodsViolatingTopologySpreadConstraintArgs) + if args.Namespaces == nil { + args.Namespaces = nil } - if obj.LabelSelector == nil { - obj.LabelSelector = nil + if args.LabelSelector == nil { + args.LabelSelector = nil } - if !obj.IncludeSoftConstraints { - obj.IncludeSoftConstraints = false + if !args.IncludeSoftConstraints { + args.IncludeSoftConstraints = false } } diff --git a/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/validation.go b/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/validation.go index 831e23922..60ebf68ef 100644 --- a/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/validation.go +++ b/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/validation.go @@ -20,10 +20,12 @@ import ( "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) // ValidateRemovePodsViolatingTopologySpreadConstraintArgs validates RemovePodsViolatingTopologySpreadConstraint arguments -func ValidateRemovePodsViolatingTopologySpreadConstraintArgs(args *RemovePodsViolatingTopologySpreadConstraintArgs) error { +func ValidateRemovePodsViolatingTopologySpreadConstraintArgs(obj runtime.Object) error { + args := obj.(*RemovePodsViolatingTopologySpreadConstraintArgs) // At most one of include/exclude can be set if args.Namespaces != nil && len(args.Namespaces.Include) > 0 && len(args.Namespaces.Exclude) > 0 { return fmt.Errorf("only one of Include/Exclude namespaces can be set") diff --git a/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/zz_generated.defaults.go b/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/zz_generated.defaults.go index 8a97e5853..0fbdd9461 100644 --- a/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/zz_generated.defaults.go +++ b/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint/zz_generated.defaults.go @@ -29,12 +29,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&RemovePodsViolatingTopologySpreadConstraintArgs{}, func(obj interface{}) { - SetObjectDefaults_RemovePodsViolatingTopologySpreadConstraintArgs(obj.(*RemovePodsViolatingTopologySpreadConstraintArgs)) - }) return nil } - -func SetObjectDefaults_RemovePodsViolatingTopologySpreadConstraintArgs(in *RemovePodsViolatingTopologySpreadConstraintArgs) { - SetDefaults_RemovePodsViolatingTopologySpreadConstraintArgs(in) -}