mirror of
https://github.com/kubernetes-sigs/descheduler.git
synced 2026-01-25 20:59:28 +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:
committed by
GitHub
parent
6e953b2ff3
commit
da8b145980
@@ -20,6 +20,7 @@ package app
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
@@ -112,3 +113,8 @@ func NewDeschedulerCommand(out io.Writer) *cobra.Command {
|
||||
func Run(ctx context.Context, rs *options.DeschedulerServer) error {
|
||||
return descheduler.Run(ctx, rs)
|
||||
}
|
||||
|
||||
func SetupLogs() {
|
||||
klog.SetOutput(os.Stdout)
|
||||
klog.InitFlags(nil)
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ import (
|
||||
"os"
|
||||
|
||||
"k8s.io/component-base/cli"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/descheduler/cmd/descheduler/app"
|
||||
"sigs.k8s.io/descheduler/pkg/descheduler"
|
||||
)
|
||||
|
||||
func init() {
|
||||
klog.SetOutput(os.Stdout)
|
||||
klog.InitFlags(nil)
|
||||
app.SetupLogs()
|
||||
descheduler.SetupPlugins()
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -45,6 +45,7 @@ import (
|
||||
podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod"
|
||||
"sigs.k8s.io/descheduler/pkg/framework"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
|
||||
"sigs.k8s.io/descheduler/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -58,7 +59,7 @@ func Run(ctx context.Context, rs *options.DeschedulerServer) error {
|
||||
rs.Client = rsclient
|
||||
rs.EventClient = eventClient
|
||||
|
||||
deschedulerPolicy, err := LoadPolicyConfig(rs.PolicyConfigFile, rs.Client)
|
||||
deschedulerPolicy, err := LoadPolicyConfig(rs.PolicyConfigFile, rs.Client, pluginbuilder.PluginRegistry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -357,11 +358,15 @@ func RunDeschedulerStrategies(ctx context.Context, rs *options.DeschedulerServer
|
||||
klog.ErrorS(fmt.Errorf("unable to get plugin config"), "skipping plugin", "plugin", plugin)
|
||||
continue
|
||||
}
|
||||
pgFnc, ok := pluginsMap[plugin]
|
||||
registryPlugin, ok := pluginbuilder.PluginRegistry[plugin]
|
||||
pgFnc := registryPlugin.PluginBuilder
|
||||
if !ok {
|
||||
klog.ErrorS(fmt.Errorf("unable to find plugin in the pluginsMap"), "skipping plugin", "plugin", plugin)
|
||||
}
|
||||
pg := pgFnc(pc.Args, handle)
|
||||
pg, err := pgFnc(pc.Args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", plugin)
|
||||
}
|
||||
if pg != nil {
|
||||
switch v := pg.(type) {
|
||||
case framework.DeschedulePlugin:
|
||||
|
||||
@@ -15,10 +15,15 @@ import (
|
||||
"sigs.k8s.io/descheduler/cmd/descheduler/app/options"
|
||||
"sigs.k8s.io/descheduler/pkg/api"
|
||||
"sigs.k8s.io/descheduler/pkg/api/v1alpha1"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodsviolatingnodetaints"
|
||||
"sigs.k8s.io/descheduler/test"
|
||||
)
|
||||
|
||||
func TestTaintsUpdated(t *testing.T) {
|
||||
pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry()
|
||||
pluginbuilder.Register(removepodsviolatingnodetaints.PluginName, removepodsviolatingnodetaints.New, &removepodsviolatingnodetaints.RemovePodsViolatingNodeTaintsArgs{}, pluginbuilder.PluginRegistry)
|
||||
ctx := context.Background()
|
||||
n1 := test.BuildTestNode("n1", 2000, 3000, 10, nil)
|
||||
n2 := test.BuildTestNode("n2", 2000, 3000, 10, nil)
|
||||
@@ -69,7 +74,7 @@ func TestTaintsUpdated(t *testing.T) {
|
||||
var evictedPods []string
|
||||
client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods))
|
||||
|
||||
internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp)
|
||||
internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp, pluginbuilder.PluginRegistry)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err)
|
||||
}
|
||||
@@ -84,6 +89,8 @@ func TestTaintsUpdated(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDuplicate(t *testing.T) {
|
||||
pluginbuilder.PluginRegistry = pluginbuilder.NewRegistry()
|
||||
pluginbuilder.Register(removeduplicates.PluginName, removeduplicates.New, &removeduplicates.RemoveDuplicatesArgs{}, pluginbuilder.PluginRegistry)
|
||||
ctx := context.Background()
|
||||
node1 := test.BuildTestNode("n1", 2000, 3000, 10, nil)
|
||||
node2 := test.BuildTestNode("n2", 2000, 3000, 10, nil)
|
||||
@@ -129,7 +136,7 @@ func TestDuplicate(t *testing.T) {
|
||||
var evictedPods []string
|
||||
client.PrependReactor("create", "pods", podEvictionReactionFuc(&evictedPods))
|
||||
|
||||
internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp)
|
||||
internalDeschedulerPolicy, err := V1alpha1ToInternal(client, dp, pluginbuilder.PluginRegistry)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to convert v1alpha1 to v1alpha2: %v", err)
|
||||
}
|
||||
|
||||
@@ -28,11 +28,13 @@ import (
|
||||
"sigs.k8s.io/descheduler/pkg/api"
|
||||
"sigs.k8s.io/descheduler/pkg/api/v1alpha1"
|
||||
"sigs.k8s.io/descheduler/pkg/descheduler/scheme"
|
||||
"sigs.k8s.io/descheduler/pkg/framework"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
|
||||
"sigs.k8s.io/descheduler/pkg/utils"
|
||||
)
|
||||
|
||||
func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api.DeschedulerPolicy, error) {
|
||||
func LoadPolicyConfig(policyConfigFile string, client clientset.Interface, registry pluginbuilder.Registry) (*api.DeschedulerPolicy, error) {
|
||||
if policyConfigFile == "" {
|
||||
klog.V(1).InfoS("Policy config file not specified")
|
||||
return nil, nil
|
||||
@@ -51,8 +53,7 @@ func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api
|
||||
}
|
||||
|
||||
// Build profiles
|
||||
// TODO(jchaloup): replace this with v1alpha1 -> v1alpha2 conversion
|
||||
internalPolicy, err := V1alpha1ToInternal(client, versionedPolicy)
|
||||
internalPolicy, err := V1alpha1ToInternal(client, versionedPolicy, registry)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed converting versioned policy to internal policy version: %v", err)
|
||||
}
|
||||
@@ -63,20 +64,8 @@ func LoadPolicyConfig(policyConfigFile string, client clientset.Interface) (*api
|
||||
func V1alpha1ToInternal(
|
||||
client clientset.Interface,
|
||||
deschedulerPolicy *v1alpha1.DeschedulerPolicy,
|
||||
registry pluginbuilder.Registry,
|
||||
) (*api.DeschedulerPolicy, error) {
|
||||
validStrategyNames := map[v1alpha1.StrategyName]interface{}{
|
||||
"RemoveDuplicates": nil,
|
||||
"LowNodeUtilization": nil,
|
||||
"HighNodeUtilization": nil,
|
||||
"RemovePodsViolatingInterPodAntiAffinity": nil,
|
||||
"RemovePodsViolatingNodeAffinity": nil,
|
||||
"RemovePodsViolatingNodeTaints": nil,
|
||||
"RemovePodsHavingTooManyRestarts": nil,
|
||||
"PodLifeTime": nil,
|
||||
"RemovePodsViolatingTopologySpreadConstraint": nil,
|
||||
"RemoveFailedPods": nil,
|
||||
}
|
||||
|
||||
var evictLocalStoragePods bool
|
||||
if deschedulerPolicy.EvictLocalStoragePods != nil {
|
||||
evictLocalStoragePods = *deschedulerPolicy.EvictLocalStoragePods
|
||||
@@ -107,7 +96,7 @@ func V1alpha1ToInternal(
|
||||
|
||||
// Build profiles
|
||||
for name, strategy := range deschedulerPolicy.Strategies {
|
||||
if _, ok := validStrategyNames[name]; ok {
|
||||
if _, ok := pluginbuilder.PluginRegistry[string(name)]; ok {
|
||||
if strategy.Enabled {
|
||||
params := strategy.Params
|
||||
if params == nil {
|
||||
@@ -175,13 +164,16 @@ func V1alpha1ToInternal(
|
||||
},
|
||||
}
|
||||
|
||||
// Plugins have either of the two extension points
|
||||
switch pluginToExtensionPoint[pluginConfig.Name] {
|
||||
case descheduleEP:
|
||||
profile.Plugins.Deschedule.Enabled = []string{pluginConfig.Name}
|
||||
case balanceEP:
|
||||
profile.Plugins.Balance.Enabled = []string{pluginConfig.Name}
|
||||
pluginArgs := registry[string(name)].PluginArgInstance
|
||||
pluginInstance, err := registry[string(name)].PluginBuilder(pluginArgs, &handleImpl{})
|
||||
if err != nil {
|
||||
klog.ErrorS(fmt.Errorf("could not build plugin"), "plugin build error", "plugin", name)
|
||||
return nil, fmt.Errorf("could not build plugin: %v", name)
|
||||
}
|
||||
|
||||
// pluginInstance can be of any of each type, or both
|
||||
profilePlugins := profile.Plugins
|
||||
profile.Plugins = enableProfilePluginsByType(profilePlugins, pluginInstance, pluginConfig)
|
||||
profiles = append(profiles, profile)
|
||||
}
|
||||
} else {
|
||||
@@ -197,3 +189,27 @@ func V1alpha1ToInternal(
|
||||
MaxNoOfPodsToEvictPerNamespace: deschedulerPolicy.MaxNoOfPodsToEvictPerNamespace,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func enableProfilePluginsByType(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins {
|
||||
profilePlugins = checkBalance(profilePlugins, pluginInstance, pluginConfig)
|
||||
profilePlugins = checkDeschedule(profilePlugins, pluginInstance, pluginConfig)
|
||||
return profilePlugins
|
||||
}
|
||||
|
||||
func checkBalance(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins {
|
||||
switch p := pluginInstance.(type) {
|
||||
case framework.BalancePlugin:
|
||||
klog.V(3).Info("converting Balance plugin: %s", p.Name())
|
||||
profilePlugins.Balance.Enabled = []string{pluginConfig.Name}
|
||||
}
|
||||
return profilePlugins
|
||||
}
|
||||
|
||||
func checkDeschedule(profilePlugins api.Plugins, pluginInstance framework.Plugin, pluginConfig *api.PluginConfig) api.Plugins {
|
||||
switch p := pluginInstance.(type) {
|
||||
case framework.DeschedulePlugin:
|
||||
klog.V(3).Info("converting Deschedule plugin: %s", p.Name())
|
||||
profilePlugins.Deschedule.Enabled = []string{pluginConfig.Name}
|
||||
}
|
||||
return profilePlugins
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"sigs.k8s.io/descheduler/pkg/api/v1alpha1"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/defaultevictor"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/pluginbuilder"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/removefailedpods"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/removepodshavingtoomanyrestarts"
|
||||
@@ -38,6 +39,7 @@ import (
|
||||
)
|
||||
|
||||
func TestV1alpha1ToV1alpha2(t *testing.T) {
|
||||
SetupPlugins()
|
||||
defaultEvictorPluginConfig := api.PluginConfig{
|
||||
Name: defaultevictor.PluginName,
|
||||
Args: &defaultevictor.DefaultEvictorArgs{
|
||||
@@ -680,7 +682,7 @@ func TestV1alpha1ToV1alpha2(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
client := fakeclientset.NewSimpleClientset()
|
||||
result, err := V1alpha1ToInternal(client, tc.policy)
|
||||
result, err := V1alpha1ToInternal(client, tc.policy, pluginbuilder.PluginRegistry)
|
||||
if err != nil {
|
||||
if err.Error() != tc.err.Error() {
|
||||
t.Errorf("unexpected error: %s", err.Error())
|
||||
|
||||
50
pkg/descheduler/setupplugins.go
Normal file
50
pkg/descheduler/setupplugins.go
Normal 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)
|
||||
}
|
||||
@@ -19,11 +19,9 @@ package descheduler
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/descheduler/pkg/api"
|
||||
"sigs.k8s.io/descheduler/pkg/api/v1alpha1"
|
||||
"sigs.k8s.io/descheduler/pkg/framework"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/nodeutilization"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/podlifetime"
|
||||
"sigs.k8s.io/descheduler/pkg/framework/plugins/removeduplicates"
|
||||
@@ -250,106 +248,3 @@ func v1alpha1ThresholdToInternal(thresholds v1alpha1.ResourceThresholds) api.Res
|
||||
}
|
||||
return internal
|
||||
}
|
||||
|
||||
type extensionPoint string
|
||||
|
||||
const (
|
||||
descheduleEP extensionPoint = "deschedule"
|
||||
balanceEP extensionPoint = "balance"
|
||||
)
|
||||
|
||||
var pluginToExtensionPoint = map[string]extensionPoint{
|
||||
removepodsviolatingnodetaints.PluginName: descheduleEP,
|
||||
removefailedpods.PluginName: descheduleEP,
|
||||
removepodsviolatingnodeaffinity.PluginName: descheduleEP,
|
||||
removepodsviolatinginterpodantiaffinity.PluginName: descheduleEP,
|
||||
removepodshavingtoomanyrestarts.PluginName: descheduleEP,
|
||||
podlifetime.PluginName: descheduleEP,
|
||||
removeduplicates.PluginName: balanceEP,
|
||||
removepodsviolatingtopologyspreadconstraint.PluginName: balanceEP,
|
||||
nodeutilization.HighNodeUtilizationPluginName: balanceEP,
|
||||
nodeutilization.LowNodeUtilizationPluginName: balanceEP,
|
||||
}
|
||||
|
||||
var pluginsMap = map[string]func(args runtime.Object, handle *handleImpl) framework.Plugin{
|
||||
removepodsviolatingnodetaints.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := removepodsviolatingnodetaints.New(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingnodetaints.PluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
removefailedpods.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := removefailedpods.New(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removefailedpods.PluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
removepodsviolatingnodeaffinity.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := removepodsviolatingnodeaffinity.New(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingnodeaffinity.PluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
removepodsviolatinginterpodantiaffinity.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := removepodsviolatinginterpodantiaffinity.New(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatinginterpodantiaffinity.PluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
removepodshavingtoomanyrestarts.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := removepodshavingtoomanyrestarts.New(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodshavingtoomanyrestarts.PluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
podlifetime.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := podlifetime.New(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", podlifetime.PluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
removeduplicates.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := removeduplicates.New(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removeduplicates.PluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
removepodsviolatingtopologyspreadconstraint.PluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := removepodsviolatingtopologyspreadconstraint.New(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", removepodsviolatingtopologyspreadconstraint.PluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
nodeutilization.HighNodeUtilizationPluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := nodeutilization.NewHighNodeUtilization(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", nodeutilization.HighNodeUtilizationPluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
nodeutilization.LowNodeUtilizationPluginName: func(args runtime.Object, handle *handleImpl) framework.Plugin {
|
||||
pg, err := nodeutilization.NewLowNodeUtilization(args, handle)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to initialize a plugin", "pluginName", nodeutilization.LowNodeUtilizationPluginName)
|
||||
return nil
|
||||
}
|
||||
return pg
|
||||
},
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
@@ -129,9 +130,13 @@ func New(args runtime.Object, handle framework.Handle) (framework.Plugin, error)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if defaultEvictorArgs.LabelSelector != nil && !defaultEvictorArgs.LabelSelector.Empty() {
|
||||
selector, err := metav1.LabelSelectorAsSelector(defaultEvictorArgs.LabelSelector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get selector from label selector")
|
||||
}
|
||||
if defaultEvictorArgs.LabelSelector != nil && !selector.Empty() {
|
||||
ev.constraints = append(ev.constraints, func(pod *v1.Pod) error {
|
||||
if !defaultEvictorArgs.LabelSelector.Matches(labels.Set(pod.Labels)) {
|
||||
if !selector.Matches(labels.Set(pod.Labels)) {
|
||||
return fmt.Errorf("pod labels do not match the labelSelector filter in the policy parameter")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -15,7 +15,6 @@ package defaultevictor
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"sigs.k8s.io/descheduler/pkg/api"
|
||||
)
|
||||
|
||||
@@ -24,14 +23,14 @@ import (
|
||||
|
||||
// DefaultEvictorArgs holds arguments used to configure DefaultEvictor plugin.
|
||||
type DefaultEvictorArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
NodeSelector string
|
||||
EvictLocalStoragePods bool
|
||||
EvictSystemCriticalPods bool
|
||||
IgnorePvcPods bool
|
||||
EvictFailedBarePods bool
|
||||
LabelSelector labels.Selector
|
||||
PriorityThreshold *api.PriorityThreshold
|
||||
NodeFit bool
|
||||
NodeSelector string `json:"nodeSelector"`
|
||||
EvictLocalStoragePods bool `json:"evictLocalStoragePods"`
|
||||
EvictSystemCriticalPods bool `json:"evictSystemCriticalPods"`
|
||||
IgnorePvcPods bool `json:"ignorePvcPods"`
|
||||
EvictFailedBarePods bool `json:"evictFailedBarePods"`
|
||||
LabelSelector *metav1.LabelSelector `json:"labelSelector"`
|
||||
PriorityThreshold *api.PriorityThreshold `json:"priorityThreshold"`
|
||||
NodeFit bool `json:"nodeFit"`
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ limitations under the License.
|
||||
package defaultevictor
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
api "sigs.k8s.io/descheduler/pkg/api"
|
||||
)
|
||||
@@ -31,7 +32,9 @@ func (in *DefaultEvictorArgs) DeepCopyInto(out *DefaultEvictorArgs) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.LabelSelector != nil {
|
||||
out.LabelSelector = in.LabelSelector.DeepCopySelector()
|
||||
in, out := &in.LabelSelector, &out.LabelSelector
|
||||
*out = new(v1.LabelSelector)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.PriorityThreshold != nil {
|
||||
in, out := &in.PriorityThreshold, &out.PriorityThreshold
|
||||
|
||||
@@ -22,28 +22,29 @@ import (
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
type LowNodeUtilizationArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
UseDeviationThresholds bool `json:"useDeviationThresholds"`
|
||||
Thresholds api.ResourceThresholds `json:"thresholds"`
|
||||
TargetThresholds api.ResourceThresholds `json:"targetThresholds"`
|
||||
NumberOfNodes int `json:"numberOfNodes"`
|
||||
|
||||
UseDeviationThresholds bool
|
||||
Thresholds api.ResourceThresholds
|
||||
TargetThresholds api.ResourceThresholds
|
||||
NumberOfNodes int
|
||||
// Naming this one differently since namespaces are still
|
||||
// considered while considering resoures used by pods
|
||||
// but then filtered out before eviction
|
||||
EvictableNamespaces *api.Namespaces
|
||||
EvictableNamespaces *api.Namespaces `json:"evictableNamespaces"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
type HighNodeUtilizationArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Thresholds api.ResourceThresholds
|
||||
NumberOfNodes int
|
||||
Thresholds api.ResourceThresholds `json:"thresholds"`
|
||||
NumberOfNodes int `json:"numberOfNodes"`
|
||||
// Naming this one differently since namespaces are still
|
||||
// considered while considering resoures used by pods
|
||||
// but then filtered out before eviction
|
||||
EvictableNamespaces *api.Namespaces
|
||||
EvictableNamespaces *api.Namespaces `json:"evictableNamespaces"`
|
||||
}
|
||||
|
||||
48
pkg/framework/plugins/pluginbuilder/pluginbuilder.go
Normal file
48
pkg/framework/plugins/pluginbuilder/pluginbuilder.go
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
|
||||
// PodLifeTimeArgs holds arguments used to configure PodLifeTime plugin.
|
||||
type PodLifeTimeArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Namespaces *api.Namespaces
|
||||
LabelSelector *metav1.LabelSelector
|
||||
MaxPodLifeTimeSeconds *uint
|
||||
States []string
|
||||
Namespaces *api.Namespaces `json:"namespaces"`
|
||||
LabelSelector *metav1.LabelSelector `json:"labelSelector"`
|
||||
MaxPodLifeTimeSeconds *uint `json:"maxPodLifeTimeSeconds"`
|
||||
States []string `json:"states"`
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
type RemoveDuplicatesArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Namespaces *api.Namespaces
|
||||
ExcludeOwnerKinds []string
|
||||
Namespaces *api.Namespaces `json:"namespaces"`
|
||||
ExcludeOwnerKinds []string `json:"excludeOwnerKinds"`
|
||||
}
|
||||
|
||||
@@ -23,12 +23,12 @@ import (
|
||||
|
||||
// RemoveFailedPodsArgs holds arguments used to configure RemoveFailedPods plugin.
|
||||
type RemoveFailedPodsArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Namespaces *api.Namespaces
|
||||
LabelSelector *metav1.LabelSelector
|
||||
ExcludeOwnerKinds []string
|
||||
MinPodLifetimeSeconds *uint
|
||||
Reasons []string
|
||||
IncludingInitContainers bool
|
||||
Namespaces *api.Namespaces `json:"namespaces"`
|
||||
LabelSelector *metav1.LabelSelector `json:"labelSelector"`
|
||||
ExcludeOwnerKinds []string `json:"excludeOwnerKinds"`
|
||||
MinPodLifetimeSeconds *uint `json:"minPodLifetimeSeconds"`
|
||||
Reasons []string `json:"reasons"`
|
||||
IncludingInitContainers bool `json:"includingInitContainers"`
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
|
||||
// RemovePodsHavingTooManyRestartsArgs holds arguments used to configure RemovePodsHavingTooManyRestarts plugin.
|
||||
type RemovePodsHavingTooManyRestartsArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Namespaces *api.Namespaces
|
||||
LabelSelector *metav1.LabelSelector
|
||||
PodRestartThreshold int32
|
||||
IncludingInitContainers bool
|
||||
Namespaces *api.Namespaces `json:"namespaces"`
|
||||
LabelSelector *metav1.LabelSelector `json:"labelSelector"`
|
||||
PodRestartThreshold int32 `json:"podRestartThreshold"`
|
||||
IncludingInitContainers bool `json:"includingInitContainers"`
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
|
||||
// RemovePodsViolatingInterPodAntiAffinity holds arguments used to configure RemovePodsViolatingInterPodAntiAffinity plugin.
|
||||
type RemovePodsViolatingInterPodAntiAffinityArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Namespaces *api.Namespaces
|
||||
LabelSelector *metav1.LabelSelector
|
||||
Namespaces *api.Namespaces `json:"namespaces"`
|
||||
LabelSelector *metav1.LabelSelector `json:"labelSelector"`
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ import (
|
||||
|
||||
// RemovePodsViolatingNodeAffinityArgs holds arguments used to configure RemovePodsViolatingNodeAffinity plugin.
|
||||
type RemovePodsViolatingNodeAffinityArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Namespaces *api.Namespaces
|
||||
LabelSelector *metav1.LabelSelector
|
||||
NodeAffinityType []string
|
||||
Namespaces *api.Namespaces `json:"namespaces"`
|
||||
LabelSelector *metav1.LabelSelector `json:"labelSelector"`
|
||||
NodeAffinityType []string `json:"nodeAffinityType"`
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ import (
|
||||
|
||||
// RemovePodsViolatingNodeTaintsArgs holds arguments used to configure the RemovePodsViolatingNodeTaints plugin.
|
||||
type RemovePodsViolatingNodeTaintsArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Namespaces *api.Namespaces
|
||||
LabelSelector *metav1.LabelSelector
|
||||
IncludePreferNoSchedule bool
|
||||
ExcludedTaints []string
|
||||
Namespaces *api.Namespaces `json:"namespaces"`
|
||||
LabelSelector *metav1.LabelSelector `json:"labelSelector"`
|
||||
IncludePreferNoSchedule bool `json:"includePreferNoSchedule"`
|
||||
ExcludedTaints []string `json:"excludedTaints"`
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ import (
|
||||
|
||||
// RemovePodsViolatingTopologySpreadConstraintArgs holds arguments used to configure RemovePodsViolatingTopologySpreadConstraint plugin.
|
||||
type RemovePodsViolatingTopologySpreadConstraintArgs struct {
|
||||
metav1.TypeMeta
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
Namespaces *api.Namespaces
|
||||
LabelSelector *metav1.LabelSelector
|
||||
IncludeSoftConstraints bool
|
||||
Namespaces *api.Namespaces `json:"namespaces"`
|
||||
LabelSelector *metav1.LabelSelector `json:"labelSelector"`
|
||||
IncludeSoftConstraints bool `json:"includeSoftConstraints"`
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import (
|
||||
)
|
||||
|
||||
func TestLeaderElection(t *testing.T) {
|
||||
descheduler.SetupPlugins()
|
||||
ctx := context.Background()
|
||||
|
||||
clientSet, _, _, _, stopCh := initializeClient(t)
|
||||
|
||||
Reference in New Issue
Block a user