1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-26 05:14:13 +01:00

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
This commit is contained in:
Lucas Severo Alves
2023-01-17 17:10:34 +01:00
committed by GitHub
parent 861c6325f3
commit 137f3b20dc
50 changed files with 1867 additions and 492 deletions

17
pkg/api/conversion.go Normal file
View File

@@ -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

View File

@@ -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
}

View File

@@ -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))

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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)
}

24
pkg/api/v1alpha2/doc.go Normal file
View File

@@ -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"

View File

@@ -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
}

26
pkg/api/v1alpha2/sort.go Normal file
View File

@@ -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
}

66
pkg/api/v1alpha2/types.go Normal file
View File

@@ -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"`
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}
})
}
}

View File

@@ -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,
))
}

View File

@@ -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)
}

View File

@@ -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,
}
}
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")
}

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")
}

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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")

View File

@@ -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)
}