1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-28 06:29:29 +01:00

use plugin registry and prepare for conversion (#1003)

* use plugin registry and prepare for conersion

* Register plugins explicitly to a registry

* check interface impl instead of struc var

* setup plugins at top level

* treat plugin type combinations

* pass registry as arg of V1alpha1ToInternal

* move registry yet another level up

* check interface type separately
This commit is contained in:
Lucas Severo Alves
2022-12-01 15:05:54 +01:00
committed by GitHub
parent 6e953b2ff3
commit da8b145980
22 changed files with 234 additions and 196 deletions

View File

@@ -20,6 +20,7 @@ package app
import ( import (
"context" "context"
"io" "io"
"os"
"os/signal" "os/signal"
"syscall" "syscall"
@@ -112,3 +113,8 @@ func NewDeschedulerCommand(out io.Writer) *cobra.Command {
func Run(ctx context.Context, rs *options.DeschedulerServer) error { func Run(ctx context.Context, rs *options.DeschedulerServer) error {
return descheduler.Run(ctx, rs) return descheduler.Run(ctx, rs)
} }
func SetupLogs() {
klog.SetOutput(os.Stdout)
klog.InitFlags(nil)
}

View File

@@ -20,13 +20,13 @@ import (
"os" "os"
"k8s.io/component-base/cli" "k8s.io/component-base/cli"
"k8s.io/klog/v2"
"sigs.k8s.io/descheduler/cmd/descheduler/app" "sigs.k8s.io/descheduler/cmd/descheduler/app"
"sigs.k8s.io/descheduler/pkg/descheduler"
) )
func init() { func init() {
klog.SetOutput(os.Stdout) app.SetupLogs()
klog.InitFlags(nil) descheduler.SetupPlugins()
} }
func main() { func main() {

View File

@@ -45,6 +45,7 @@ import (
podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod" podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod"
"sigs.k8s.io/descheduler/pkg/framework" "sigs.k8s.io/descheduler/pkg/framework"
"sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor"
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
"sigs.k8s.io/descheduler/pkg/utils" "sigs.k8s.io/descheduler/pkg/utils"
) )
@@ -58,7 +59,7 @@ func Run(ctx context.Context, rs *options.DeschedulerServer) error {
rs.Client = rsclient rs.Client = rsclient
rs.EventClient = eventClient rs.EventClient = eventClient
deschedulerPolicy, err := LoadPolicyConfig(rs.PolicyConfigFile, rs.Client) deschedulerPolicy, err := LoadPolicyConfig(rs.PolicyConfigFile, rs.Client, pluginbuilder.PluginRegistry)
if err != nil { if err != nil {
return err return err
} }
@@ -357,11 +358,15 @@ func RunDeschedulerStrategies(ctx context.Context, rs *options.DeschedulerServer
klog.ErrorS(fmt.Errorf("unable to get plugin config"), "skipping plugin", "plugin", plugin) klog.ErrorS(fmt.Errorf("unable to get plugin config"), "skipping plugin", "plugin", plugin)
continue continue
} }
pgFnc, ok := pluginsMap[plugin] registryPlugin, ok := pluginbuilder.PluginRegistry[plugin]
pgFnc := registryPlugin.PluginBuilder
if !ok { if !ok {
klog.ErrorS(fmt.Errorf("unable to find plugin in the pluginsMap"), "skipping plugin", "plugin", plugin) klog.ErrorS(fmt.Errorf("unable to find plugin in the pluginsMap"), "skipping plugin", "plugin", plugin)
} }
pg := pgFnc(pc.Args, handle) pg, err := pgFnc(pc.Args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", plugin)
}
if pg != nil { if pg != nil {
switch v := pg.(type) { switch v := pg.(type) {
case framework.DeschedulePlugin: case framework.DeschedulePlugin:

View File

@@ -15,10 +15,15 @@ import (
"sigs.k8s.io/descheduler/cmd/descheduler/app/options" "sigs.k8s.io/descheduler/cmd/descheduler/app/options"
"sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api"
"sigs.k8s.io/descheduler/pkg/api/v1alpha1" "sigs.k8s.io/descheduler/pkg/api/v1alpha1"
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingnodetaints"
"sigs.k8s.io/descheduler/test" "sigs.k8s.io/descheduler/test"
) )
func TestTaintsUpdated(t *testing.T) { func TestTaintsUpdated(t *testing.T) {
pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry()
pluginbuilder.Register(removepodsviolatingnodetaints.PluginName, removepodsviolatingnodetaints.New, &removepodsviolatingnodetaints.RemovePodsViolatingNodeTaintsArgs{}, pluginbuilder.PluginRegistry)
ctx := context.Background() ctx := context.Background()
n1 := test.BuildTestNode("n1", 2000, 3000, 10, nil) n1 := test.BuildTestNode("n1", 2000, 3000, 10, nil)
n2 := test.BuildTestNode("n2", 2000, 3000, 10, nil) n2 := test.BuildTestNode("n2", 2000, 3000, 10, nil)
@@ -69,7 +74,7 @@ func TestTaintsUpdated(t *testing.T) {
var evictedPods []string var evictedPods []string
client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods)) client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods))
internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp) internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp, pluginbuilder.PluginRegistry)
if err != nil { if err != nil {
t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err) t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err)
} }
@@ -84,6 +89,8 @@ func TestTaintsUpdated(t *testing.T) {
} }
func TestDuplicate(t *testing.T) { func TestDuplicate(t *testing.T) {
pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry()
pluginbuilder.Register(removeduplicates.PluginName, removeduplicates.New, &removeduplicates.RemoveDuplicatesArgs{}, pluginbuilder.PluginRegistry)
ctx := context.Background() ctx := context.Background()
node1 := test.BuildTestNode("n1", 2000, 3000, 10, nil) node1 := test.BuildTestNode("n1", 2000, 3000, 10, nil)
node2 := test.BuildTestNode("n2", 2000, 3000, 10, nil) node2 := test.BuildTestNode("n2", 2000, 3000, 10, nil)
@@ -129,7 +136,7 @@ func TestDuplicate(t *testing.T) {
var evictedPods []string var evictedPods []string
client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods)) client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods))
internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp) internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp, pluginbuilder.PluginRegistry)
if err != nil { if err != nil {
t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err) t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err)
} }

View File

@@ -28,11 +28,13 @@ import (
"sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api"
"sigs.k8s.io/descheduler/pkg/api/v1alpha1" "sigs.k8s.io/descheduler/pkg/api/v1alpha1"
"sigs.k8s.io/descheduler/pkg/descheduler/scheme" "sigs.k8s.io/descheduler/pkg/descheduler/scheme"
"sigs.k8s.io/descheduler/pkg/framework"
"sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor"
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
"sigs.k8s.io/descheduler/pkg/utils" "sigs.k8s.io/descheduler/pkg/utils"
) )
func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api.DeschedulerPolicy, error) { func LoadPolicyConfig(policyConfigFile string, client clientset.Interface, registry pluginbuilder.Registry) (*api.DeschedulerPolicy, error) {
if policyConfigFile == "" { if policyConfigFile == "" {
klog.V(1).InfoS("Policy config file not specified") klog.V(1).InfoS("Policy config file not specified")
return nil, nil return nil, nil
@@ -51,8 +53,7 @@ func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api
} }
// Build profiles // Build profiles
// TODO(jchaloup): replace this with v1alpha1 -> v1alpha2 conversion internalPolicy, err := V1alpha1ToInternal(client, versionedPolicy, registry)
internalPolicy, err := V1alpha1ToInternal(client, versionedPolicy)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed converting versioned policy to internal policy version: %v", err) return nil, fmt.Errorf("failed converting versioned policy to internal policy version: %v", err)
} }
@@ -63,20 +64,8 @@ func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api
func V1alpha1ToInternal( func V1alpha1ToInternal(
client clientset.Interface, client clientset.Interface,
deschedulerPolicy *v1alpha1.DeschedulerPolicy, deschedulerPolicy *v1alpha1.DeschedulerPolicy,
registry pluginbuilder.Registry,
) (*api.DeschedulerPolicy, error) { ) (*api.DeschedulerPolicy, error) {
validStrategyNames := map[v1alpha1.StrategyName]interface{}{
"RemoveDuplicates": nil,
"LowNodeUtilization": nil,
"HighNodeUtilization": nil,
"RemovePodsViolatingInterPodAntiAffinity": nil,
"RemovePodsViolatingNodeAffinity": nil,
"RemovePodsViolatingNodeTaints": nil,
"RemovePodsHavingTooManyRestarts": nil,
"PodLifeTime": nil,
"RemovePodsViolatingTopologySpreadConstraint": nil,
"RemoveFailedPods": nil,
}
var evictLocalStoragePods bool var evictLocalStoragePods bool
if deschedulerPolicy.EvictLocalStoragePods != nil { if deschedulerPolicy.EvictLocalStoragePods != nil {
evictLocalStoragePods = *deschedulerPolicy.EvictLocalStoragePods evictLocalStoragePods = *deschedulerPolicy.EvictLocalStoragePods
@@ -107,7 +96,7 @@ func V1alpha1ToInternal(
// Build profiles // Build profiles
for name, strategy := range deschedulerPolicy.Strategies { for name, strategy := range deschedulerPolicy.Strategies {
if _, ok := validStrategyNames[name]; ok { if _, ok := pluginbuilder.PluginRegistry[string(name)]; ok {
if strategy.Enabled { if strategy.Enabled {
params := strategy.Params params := strategy.Params
if params == nil { if params == nil {
@@ -175,13 +164,16 @@ func V1alpha1ToInternal(
}, },
} }
// Plugins have either of the two extension points pluginArgs := registry[string(name)].PluginArgInstance
switch pluginToExtensionPoint[pluginConfig.Name] { pluginInstance, err := registry[string(name)].PluginBuilder(pluginArgs, &handleImpl{})
case descheduleEP: if err != nil {
profile.Plugins.Deschedule.Enabled = []string{pluginConfig.Name} klog.ErrorS(fmt.Errorf("could not build plugin"), "plugin build error", "plugin", name)
case balanceEP: return nil, fmt.Errorf("could not build plugin: %v", name)
profile.Plugins.Balance.Enabled = []string{pluginConfig.Name}
} }
// pluginInstance can be of any of each type, or both
profilePlugins := profile.Plugins
profile.Plugins = enableProfilePluginsByType(profilePlugins, pluginInstance, pluginConfig)
profiles = append(profiles, profile) profiles = append(profiles, profile)
} }
} else { } else {
@@ -197,3 +189,27 @@ func V1alpha1ToInternal(
MaxNoOfPodsToEvictPerNamespace: deschedulerPolicy.MaxNoOfPodsToEvictPerNamespace, MaxNoOfPodsToEvictPerNamespace: deschedulerPolicy.MaxNoOfPodsToEvictPerNamespace,
}, nil }, nil
} }
func enableProfilePluginsByType(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins {
profilePlugins = checkBalance(profilePlugins, pluginInstance, pluginConfig)
profilePlugins = checkDeschedule(profilePlugins, pluginInstance, pluginConfig)
return profilePlugins
}
func checkBalance(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins {
switch p := pluginInstance.(type) {
case framework.BalancePlugin:
klog.V(3).Info("converting Balance plugin: %s", p.Name())
profilePlugins.Balance.Enabled = []string{pluginConfig.Name}
}
return profilePlugins
}
func checkDeschedule(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins {
switch p := pluginInstance.(type) {
case framework.DeschedulePlugin:
klog.V(3).Info("converting Deschedule plugin: %s", p.Name())
profilePlugins.Deschedule.Enabled = []string{pluginConfig.Name}
}
return profilePlugins
}

View File

@@ -27,6 +27,7 @@ import (
"sigs.k8s.io/descheduler/pkg/api/v1alpha1" "sigs.k8s.io/descheduler/pkg/api/v1alpha1"
"sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor" "sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor"
"sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization" "sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization"
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates" "sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removefailedpods" "sigs.k8s.io/descheduler/pkg/framework/plugins/removefailedpods"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodshavingtoomanyrestarts" "sigs.k8s.io/descheduler/pkg/framework/plugins/removepodshavingtoomanyrestarts"
@@ -38,6 +39,7 @@ import (
) )
func TestV1alpha1ToV1alpha2(t *testing.T) { func TestV1alpha1ToV1alpha2(t *testing.T) {
SetupPlugins()
defaultEvictorPluginConfig := api.PluginConfig{ defaultEvictorPluginConfig := api.PluginConfig{
Name: defaultevictor.PluginName, Name: defaultevictor.PluginName,
Args: &defaultevictor.DefaultEvictorArgs{ Args: &defaultevictor.DefaultEvictorArgs{
@@ -680,7 +682,7 @@ func TestV1alpha1ToV1alpha2(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
client := fakeclientset.NewSimpleClientset() client := fakeclientset.NewSimpleClientset()
result, err := V1alpha1ToInternal(client, tc.policy) result, err := V1alpha1ToInternal(client, tc.policy, pluginbuilder.PluginRegistry)
if err != nil { if err != nil {
if err.Error() != tc.err.Error() { if err.Error() != tc.err.Error() {
t.Errorf("unexpected error: %s", err.Error()) t.Errorf("unexpected error: %s", err.Error())

View File

@@ -0,0 +1,50 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package descheduler
import (
"sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor"
"sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization"
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
"sigs.k8s.io/descheduler/pkg/framework/plugins/podlifetime"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removefailedpods"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodshavingtoomanyrestarts"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingnodeaffinity"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingnodetaints"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingtopologyspreadconstraint"
)
func SetupPlugins() {
pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry()
RegisterDefaultPlugins(pluginbuilder.PluginRegistry)
}
func RegisterDefaultPlugins(registry pluginbuilder.Registry) {
pluginbuilder.Register(defaultevictor.PluginName, defaultevictor.New, &defaultevictor.DefaultEvictorArgs{}, registry)
pluginbuilder.Register(nodeutilization.LowNodeUtilizationPluginName, nodeutilization.NewLowNodeUtilization, &nodeutilization.LowNodeUtilizationArgs{}, registry)
pluginbuilder.Register(nodeutilization.HighNodeUtilizationPluginName, nodeutilization.NewHighNodeUtilization, &nodeutilization.HighNodeUtilizationArgs{}, registry)
pluginbuilder.Register(podlifetime.PluginName, podlifetime.New, &podlifetime.PodLifeTimeArgs{}, registry)
pluginbuilder.Register(removeduplicates.PluginName, removeduplicates.New, &removeduplicates.RemoveDuplicatesArgs{}, registry)
pluginbuilder.Register(removefailedpods.PluginName, removefailedpods.New, &removefailedpods.RemoveFailedPodsArgs{}, registry)
pluginbuilder.Register(removepodshavingtoomanyrestarts.PluginName, removepodshavingtoomanyrestarts.New, &removepodshavingtoomanyrestarts.RemovePodsHavingTooManyRestartsArgs{}, registry)
pluginbuilder.Register(removepodsviolatinginterpodantiaffinity.PluginName, removepodsviolatinginterpodantiaffinity.New, &removepodsviolatinginterpodantiaffinity.RemovePodsViolatingInterPodAntiAffinityArgs{}, registry)
pluginbuilder.Register(removepodsviolatingnodeaffinity.PluginName, removepodsviolatingnodeaffinity.New, &removepodsviolatingnodeaffinity.RemovePodsViolatingNodeAffinityArgs{}, registry)
pluginbuilder.Register(removepodsviolatingnodetaints.PluginName, removepodsviolatingnodetaints.New, &removepodsviolatingnodetaints.RemovePodsViolatingNodeTaintsArgs{}, registry)
pluginbuilder.Register(removepodsviolatingtopologyspreadconstraint.PluginName, removepodsviolatingtopologyspreadconstraint.New, &removepodsviolatingtopologyspreadconstraint.RemovePodsViolatingTopologySpreadConstraintArgs{}, registry)
}

View File

@@ -19,11 +19,9 @@ package descheduler
import ( import (
"fmt" "fmt"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api"
"sigs.k8s.io/descheduler/pkg/api/v1alpha1" "sigs.k8s.io/descheduler/pkg/api/v1alpha1"
"sigs.k8s.io/descheduler/pkg/framework"
"sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization" "sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization"
"sigs.k8s.io/descheduler/pkg/framework/plugins/podlifetime" "sigs.k8s.io/descheduler/pkg/framework/plugins/podlifetime"
"sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates" "sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates"
@@ -250,106 +248,3 @@ func v1alpha1ThresholdToInternal(thresholds v1alpha1.ResourceThresholds) api.Res
} }
return internal return internal
} }
type extensionPoint string
const (
descheduleEP extensionPoint = "deschedule"
balanceEP extensionPoint = "balance"
)
var pluginToExtensionPoint = map[string]extensionPoint{
removepodsviolatingnodetaints.PluginName: descheduleEP,
removefailedpods.PluginName: descheduleEP,
removepodsviolatingnodeaffinity.PluginName: descheduleEP,
removepodsviolatinginterpodantiaffinity.PluginName: descheduleEP,
removepodshavingtoomanyrestarts.PluginName: descheduleEP,
podlifetime.PluginName: descheduleEP,
removeduplicates.PluginName: balanceEP,
removepodsviolatingtopologyspreadconstraint.PluginName: balanceEP,
nodeutilization.HighNodeUtilizationPluginName: balanceEP,
nodeutilization.LowNodeUtilizationPluginName: balanceEP,
}
var pluginsMap = map[string]func(args runtime.Object, handle *handleImpl) framework.Plugin{
removepodsviolatingnodetaints.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := removepodsviolatingnodetaints.New(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingnodetaints.PluginName)
return nil
}
return pg
},
removefailedpods.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := removefailedpods.New(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removefailedpods.PluginName)
return nil
}
return pg
},
removepodsviolatingnodeaffinity.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := removepodsviolatingnodeaffinity.New(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingnodeaffinity.PluginName)
return nil
}
return pg
},
removepodsviolatinginterpodantiaffinity.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := removepodsviolatinginterpodantiaffinity.New(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatinginterpodantiaffinity.PluginName)
return nil
}
return pg
},
removepodshavingtoomanyrestarts.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := removepodshavingtoomanyrestarts.New(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodshavingtoomanyrestarts.PluginName)
return nil
}
return pg
},
podlifetime.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := podlifetime.New(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", podlifetime.PluginName)
return nil
}
return pg
},
removeduplicates.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := removeduplicates.New(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removeduplicates.PluginName)
return nil
}
return pg
},
removepodsviolatingtopologyspreadconstraint.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := removepodsviolatingtopologyspreadconstraint.New(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingtopologyspreadconstraint.PluginName)
return nil
}
return pg
},
nodeutilization.HighNodeUtilizationPluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := nodeutilization.NewHighNodeUtilization(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", nodeutilization.HighNodeUtilizationPluginName)
return nil
}
return pg
},
nodeutilization.LowNodeUtilizationPluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
pg, err := nodeutilization.NewLowNodeUtilization(args, handle)
if err != nil {
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", nodeutilization.LowNodeUtilizationPluginName)
return nil
}
return pg
},
}

View File

@@ -19,6 +19,7 @@ import (
"fmt" "fmt"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/errors"
@@ -129,9 +130,13 @@ func New(args runtime.Object, handle framework.Handle) (framework.Plugin, error)
return nil return nil
}) })
} }
if defaultEvictorArgs.LabelSelector != nil && !defaultEvictorArgs.LabelSelector.Empty() { selector, err := metav1.LabelSelectorAsSelector(defaultEvictorArgs.LabelSelector)
if err != nil {
return nil, fmt.Errorf("could not get selector from label selector")
}
if defaultEvictorArgs.LabelSelector != nil && !selector.Empty() {
ev.constraints = append(ev.constraints, func(pod *v1.Pod) error { ev.constraints = append(ev.constraints, func(pod *v1.Pod) error {
if !defaultEvictorArgs.LabelSelector.Matches(labels.Set(pod.Labels)) { if !selector.Matches(labels.Set(pod.Labels)) {
return fmt.Errorf("pod labels do not match the labelSelector filter in the policy parameter") return fmt.Errorf("pod labels do not match the labelSelector filter in the policy parameter")
} }
return nil return nil

View File

@@ -15,7 +15,6 @@ package defaultevictor
import ( import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"sigs.k8s.io/descheduler/pkg/api" "sigs.k8s.io/descheduler/pkg/api"
) )
@@ -24,14 +23,14 @@ import (
// DefaultEvictorArgs holds arguments used to configure DefaultEvictor plugin. // DefaultEvictorArgs holds arguments used to configure DefaultEvictor plugin.
type DefaultEvictorArgs struct { type DefaultEvictorArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
NodeSelector string NodeSelector string `json:"nodeSelector"`
EvictLocalStoragePods bool EvictLocalStoragePods bool `json:"evictLocalStoragePods"`
EvictSystemCriticalPods bool EvictSystemCriticalPods bool `json:"evictSystemCriticalPods"`
IgnorePvcPods bool IgnorePvcPods bool `json:"ignorePvcPods"`
EvictFailedBarePods bool EvictFailedBarePods bool `json:"evictFailedBarePods"`
LabelSelector labels.Selector LabelSelector *metav1.LabelSelector `json:"labelSelector"`
PriorityThreshold *api.PriorityThreshold PriorityThreshold *api.PriorityThreshold `json:"priorityThreshold"`
NodeFit bool NodeFit bool `json:"nodeFit"`
} }

View File

@@ -22,6 +22,7 @@ limitations under the License.
package defaultevictor package defaultevictor
import ( import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
api "sigs.k8s.io/descheduler/pkg/api" api "sigs.k8s.io/descheduler/pkg/api"
) )
@@ -31,7 +32,9 @@ func (in *DefaultEvictorArgs) DeepCopyInto(out *DefaultEvictorArgs) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
if in.LabelSelector != nil { if in.LabelSelector != nil {
out.LabelSelector = in.LabelSelector.DeepCopySelector() in, out := &in.LabelSelector, &out.LabelSelector
*out = new(v1.LabelSelector)
(*in).DeepCopyInto(*out)
} }
if in.PriorityThreshold != nil { if in.PriorityThreshold != nil {
in, out := &in.PriorityThreshold, &out.PriorityThreshold in, out := &in.PriorityThreshold, &out.PriorityThreshold

View File

@@ -22,28 +22,29 @@ import (
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type LowNodeUtilizationArgs struct { type LowNodeUtilizationArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
UseDeviationThresholds bool `json:"useDeviationThresholds"`
Thresholds api.ResourceThresholds `json:"thresholds"`
TargetThresholds api.ResourceThresholds `json:"targetThresholds"`
NumberOfNodes int `json:"numberOfNodes"`
UseDeviationThresholds bool
Thresholds api.ResourceThresholds
TargetThresholds api.ResourceThresholds
NumberOfNodes int
// Naming this one differently since namespaces are still // Naming this one differently since namespaces are still
// considered while considering resoures used by pods // considered while considering resoures used by pods
// but then filtered out before eviction // but then filtered out before eviction
EvictableNamespaces *api.Namespaces EvictableNamespaces *api.Namespaces `json:"evictableNamespaces"`
} }
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type HighNodeUtilizationArgs struct { type HighNodeUtilizationArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Thresholds api.ResourceThresholds Thresholds api.ResourceThresholds `json:"thresholds"`
NumberOfNodes int NumberOfNodes int `json:"numberOfNodes"`
// Naming this one differently since namespaces are still // Naming this one differently since namespaces are still
// considered while considering resoures used by pods // considered while considering resoures used by pods
// but then filtered out before eviction // but then filtered out before eviction
EvictableNamespaces *api.Namespaces EvictableNamespaces *api.Namespaces `json:"evictableNamespaces"`
} }

View File

@@ -0,0 +1,48 @@
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pluginbuilder
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"sigs.k8s.io/descheduler/pkg/framework"
)
var PluginRegistry Registry
type PluginBuilderAndArgsInstance struct {
PluginBuilder PluginBuilder
// Just an example instance of this PluginArg so we can avoid having
// to deal with reflect Types
PluginArgInstance runtime.Object
}
type PluginBuilder = func(args runtime.Object, handle framework.Handle) (framework.Plugin, error)
type Registry = map[string]PluginBuilderAndArgsInstance
func NewRegistry() Registry {
return Registry{}
}
func Register(name string, builderFunc PluginBuilder, exampleArg runtime.Object, registry Registry) {
if _, ok := registry[name]; ok {
klog.V(10).InfoS("Plugin already registered", "plugin", name)
} else {
registry[name] = PluginBuilderAndArgsInstance{
PluginBuilder: builderFunc,
PluginArgInstance: exampleArg,
}
}
}

View File

@@ -23,10 +23,10 @@ import (
// PodLifeTimeArgs holds arguments used to configure PodLifeTime plugin. // PodLifeTimeArgs holds arguments used to configure PodLifeTime plugin.
type PodLifeTimeArgs struct { type PodLifeTimeArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Namespaces *api.Namespaces Namespaces *api.Namespaces `json:"namespaces"`
LabelSelector *metav1.LabelSelector LabelSelector *metav1.LabelSelector `json:"labelSelector"`
MaxPodLifeTimeSeconds *uint MaxPodLifeTimeSeconds *uint `json:"maxPodLifeTimeSeconds"`
States []string States []string `json:"states"`
} }

View File

@@ -22,8 +22,8 @@ import (
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type RemoveDuplicatesArgs struct { type RemoveDuplicatesArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Namespaces *api.Namespaces Namespaces *api.Namespaces `json:"namespaces"`
ExcludeOwnerKinds []string ExcludeOwnerKinds []string `json:"excludeOwnerKinds"`
} }

View File

@@ -23,12 +23,12 @@ import (
// RemoveFailedPodsArgs holds arguments used to configure RemoveFailedPods plugin. // RemoveFailedPodsArgs holds arguments used to configure RemoveFailedPods plugin.
type RemoveFailedPodsArgs struct { type RemoveFailedPodsArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Namespaces *api.Namespaces Namespaces *api.Namespaces `json:"namespaces"`
LabelSelector *metav1.LabelSelector LabelSelector *metav1.LabelSelector `json:"labelSelector"`
ExcludeOwnerKinds []string ExcludeOwnerKinds []string `json:"excludeOwnerKinds"`
MinPodLifetimeSeconds *uint MinPodLifetimeSeconds *uint `json:"minPodLifetimeSeconds"`
Reasons []string Reasons []string `json:"reasons"`
IncludingInitContainers bool IncludingInitContainers bool `json:"includingInitContainers"`
} }

View File

@@ -23,10 +23,10 @@ import (
// RemovePodsHavingTooManyRestartsArgs holds arguments used to configure RemovePodsHavingTooManyRestarts plugin. // RemovePodsHavingTooManyRestartsArgs holds arguments used to configure RemovePodsHavingTooManyRestarts plugin.
type RemovePodsHavingTooManyRestartsArgs struct { type RemovePodsHavingTooManyRestartsArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Namespaces *api.Namespaces Namespaces *api.Namespaces `json:"namespaces"`
LabelSelector *metav1.LabelSelector LabelSelector *metav1.LabelSelector `json:"labelSelector"`
PodRestartThreshold int32 PodRestartThreshold int32 `json:"podRestartThreshold"`
IncludingInitContainers bool IncludingInitContainers bool `json:"includingInitContainers"`
} }

View File

@@ -26,8 +26,8 @@ import (
// RemovePodsViolatingInterPodAntiAffinity holds arguments used to configure RemovePodsViolatingInterPodAntiAffinity plugin. // RemovePodsViolatingInterPodAntiAffinity holds arguments used to configure RemovePodsViolatingInterPodAntiAffinity plugin.
type RemovePodsViolatingInterPodAntiAffinityArgs struct { type RemovePodsViolatingInterPodAntiAffinityArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Namespaces *api.Namespaces Namespaces *api.Namespaces `json:"namespaces"`
LabelSelector *metav1.LabelSelector LabelSelector *metav1.LabelSelector `json:"labelSelector"`
} }

View File

@@ -26,9 +26,9 @@ import (
// RemovePodsViolatingNodeAffinityArgs holds arguments used to configure RemovePodsViolatingNodeAffinity plugin. // RemovePodsViolatingNodeAffinityArgs holds arguments used to configure RemovePodsViolatingNodeAffinity plugin.
type RemovePodsViolatingNodeAffinityArgs struct { type RemovePodsViolatingNodeAffinityArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Namespaces *api.Namespaces Namespaces *api.Namespaces `json:"namespaces"`
LabelSelector *metav1.LabelSelector LabelSelector *metav1.LabelSelector `json:"labelSelector"`
NodeAffinityType []string NodeAffinityType []string `json:"nodeAffinityType"`
} }

View File

@@ -26,10 +26,10 @@ import (
// RemovePodsViolatingNodeTaintsArgs holds arguments used to configure the RemovePodsViolatingNodeTaints plugin. // RemovePodsViolatingNodeTaintsArgs holds arguments used to configure the RemovePodsViolatingNodeTaints plugin.
type RemovePodsViolatingNodeTaintsArgs struct { type RemovePodsViolatingNodeTaintsArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Namespaces *api.Namespaces Namespaces *api.Namespaces `json:"namespaces"`
LabelSelector *metav1.LabelSelector LabelSelector *metav1.LabelSelector `json:"labelSelector"`
IncludePreferNoSchedule bool IncludePreferNoSchedule bool `json:"includePreferNoSchedule"`
ExcludedTaints []string ExcludedTaints []string `json:"excludedTaints"`
} }

View File

@@ -26,9 +26,9 @@ import (
// RemovePodsViolatingTopologySpreadConstraintArgs holds arguments used to configure RemovePodsViolatingTopologySpreadConstraint plugin. // RemovePodsViolatingTopologySpreadConstraintArgs holds arguments used to configure RemovePodsViolatingTopologySpreadConstraint plugin.
type RemovePodsViolatingTopologySpreadConstraintArgs struct { type RemovePodsViolatingTopologySpreadConstraintArgs struct {
metav1.TypeMeta metav1.TypeMeta `json:",inline"`
Namespaces *api.Namespaces Namespaces *api.Namespaces `json:"namespaces"`
LabelSelector *metav1.LabelSelector LabelSelector *metav1.LabelSelector `json:"labelSelector"`
IncludeSoftConstraints bool IncludeSoftConstraints bool `json:"includeSoftConstraints"`
} }

View File

@@ -38,6 +38,7 @@ import (
) )
func TestLeaderElection(t *testing.T) { func TestLeaderElection(t *testing.T) {
descheduler.SetupPlugins()
ctx := context.Background() ctx := context.Background()
clientSet, _, _, _, stopCh := initializeClient(t) clientSet, _, _, _, stopCh := initializeClient(t)