1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-26 13:29:11 +01:00
Files
descheduler/pkg/framework/fake/plugin/fake.go
Jan Chaloupka 3510aba01d Detect individual extension points from plugin types
- Populate extension points automatically from plugin types
- Make a list of enabled extension points based on a profile
  configuration
- Populate filter and pre-eviction filter handles from their
  corresponding extension points
2023-04-03 17:04:31 +02:00

411 lines
11 KiB
Go

/*
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 plugin
import (
"context"
"fmt"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/descheduler/pkg/framework/pluginregistry"
frameworktypes "sigs.k8s.io/descheduler/pkg/framework/types"
)
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// FakePluginArgs holds arguments used to configure FakePlugin plugin.
type FakePluginArgs struct {
metav1.TypeMeta `json:",inline"`
}
func ValidateFakePluginArgs(obj runtime.Object) error {
return nil
}
func SetDefaults_FakePluginArgs(obj runtime.Object) {}
var (
_ frameworktypes.EvictorPlugin = &FakePlugin{}
_ frameworktypes.DeschedulePlugin = &FakePlugin{}
_ frameworktypes.BalancePlugin = &FakePlugin{}
_ frameworktypes.EvictorPlugin = &FakeFilterPlugin{}
_ frameworktypes.DeschedulePlugin = &FakeDeschedulePlugin{}
_ frameworktypes.BalancePlugin = &FakeBalancePlugin{}
)
// FakePlugin is a configurable plugin used for testing
type FakePlugin struct {
PluginName string
// ReactionChain is the list of reactors that will be attempted for every
// request in the order they are tried.
ReactionChain []Reactor
args runtime.Object
handle frameworktypes.Handle
}
func NewPluginFncFromFake(fp *FakePlugin) pluginregistry.PluginBuilder {
return func(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plugin, error) {
fakePluginArgs, ok := args.(*FakePluginArgs)
if !ok {
return nil, fmt.Errorf("want args to be of type FakePluginArgs, got %T", args)
}
fp.handle = handle
fp.args = fakePluginArgs
return fp, nil
}
}
// New builds plugin from its arguments while passing a handle
func New(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plugin, error) {
fakePluginArgs, ok := args.(*FakePluginArgs)
if !ok {
return nil, fmt.Errorf("want args to be of type FakePluginArgs, got %T", args)
}
ev := &FakePlugin{}
ev.handle = handle
ev.args = fakePluginArgs
return ev, nil
}
func (c *FakePlugin) AddReactor(extensionPoint string, reaction ReactionFunc) {
c.ReactionChain = append(c.ReactionChain, &SimpleReactor{ExtensionPoint: extensionPoint, Reaction: reaction})
}
// Name retrieves the plugin name
func (d *FakePlugin) Name() string {
return d.PluginName
}
func (d *FakePlugin) PreEvictionFilter(pod *v1.Pod) bool {
return true
}
func (d *FakePlugin) Filter(pod *v1.Pod) bool {
return true
}
func (d *FakePlugin) handleAction(action Action) *frameworktypes.Status {
actionCopy := action.DeepCopy()
for _, reactor := range d.ReactionChain {
if !reactor.Handles(actionCopy) {
continue
}
handled, _, err := reactor.React(actionCopy)
if !handled {
continue
}
return &frameworktypes.Status{
Err: err,
}
}
return &frameworktypes.Status{
Err: fmt.Errorf("unhandled %q action", action.GetExtensionPoint()),
}
}
func (d *FakePlugin) Deschedule(ctx context.Context, nodes []*v1.Node) *frameworktypes.Status {
return d.handleAction(&DescheduleActionImpl{
ActionImpl: ActionImpl{
handle: d.handle,
extensionPoint: string(frameworktypes.DescheduleExtensionPoint),
},
nodes: nodes,
})
}
func (d *FakePlugin) Balance(ctx context.Context, nodes []*v1.Node) *frameworktypes.Status {
return d.handleAction(&BalanceActionImpl{
ActionImpl: ActionImpl{
handle: d.handle,
extensionPoint: string(frameworktypes.BalanceExtensionPoint),
},
nodes: nodes,
})
}
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// FakeDeschedulePluginArgs holds arguments used to configure FakeDeschedulePlugin plugin.
type FakeDeschedulePluginArgs struct {
metav1.TypeMeta `json:",inline"`
}
// FakeDeschedulePlugin is a configurable plugin used for testing
type FakeDeschedulePlugin struct {
PluginName string
// ReactionChain is the list of reactors that will be attempted for every
// request in the order they are tried.
ReactionChain []Reactor
args runtime.Object
handle frameworktypes.Handle
}
func NewFakeDeschedulePluginFncFromFake(fp *FakeDeschedulePlugin) pluginregistry.PluginBuilder {
return func(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plugin, error) {
fakePluginArgs, ok := args.(*FakeDeschedulePluginArgs)
if !ok {
return nil, fmt.Errorf("want args to be of type FakeDeschedulePluginArgs, got %T", args)
}
fp.handle = handle
fp.args = fakePluginArgs
return fp, nil
}
}
// New builds plugin from its arguments while passing a handle
func NewFakeDeschedule(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plugin, error) {
fakePluginArgs, ok := args.(*FakeDeschedulePluginArgs)
if !ok {
return nil, fmt.Errorf("want args to be of type FakePluginArgs, got %T", args)
}
ev := &FakeDeschedulePlugin{}
ev.handle = handle
ev.args = fakePluginArgs
return ev, nil
}
func (c *FakeDeschedulePlugin) AddReactor(extensionPoint string, reaction ReactionFunc) {
c.ReactionChain = append(c.ReactionChain, &SimpleReactor{ExtensionPoint: extensionPoint, Reaction: reaction})
}
// Name retrieves the plugin name
func (d *FakeDeschedulePlugin) Name() string {
return d.PluginName
}
func (d *FakeDeschedulePlugin) Deschedule(ctx context.Context, nodes []*v1.Node) *frameworktypes.Status {
return d.handleAction(&DescheduleActionImpl{
ActionImpl: ActionImpl{
handle: d.handle,
extensionPoint: string(frameworktypes.DescheduleExtensionPoint),
},
nodes: nodes,
})
}
func (d *FakeDeschedulePlugin) handleAction(action Action) *frameworktypes.Status {
actionCopy := action.DeepCopy()
for _, reactor := range d.ReactionChain {
if !reactor.Handles(actionCopy) {
continue
}
handled, _, err := reactor.React(actionCopy)
if !handled {
continue
}
return &frameworktypes.Status{
Err: err,
}
}
return &frameworktypes.Status{
Err: fmt.Errorf("unhandled %q action", action.GetExtensionPoint()),
}
}
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// FakeBalancePluginArgs holds arguments used to configure FakeBalancePlugin plugin.
type FakeBalancePluginArgs struct {
metav1.TypeMeta `json:",inline"`
}
// FakeBalancePlugin is a configurable plugin used for testing
type FakeBalancePlugin struct {
PluginName string
// ReactionChain is the list of reactors that will be attempted for every
// request in the order they are tried.
ReactionChain []Reactor
args runtime.Object
handle frameworktypes.Handle
}
func NewFakeBalancePluginFncFromFake(fp *FakeBalancePlugin) pluginregistry.PluginBuilder {
return func(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plugin, error) {
fakePluginArgs, ok := args.(*FakeBalancePluginArgs)
if !ok {
return nil, fmt.Errorf("want args to be of type FakeBalancePluginArgs, got %T", args)
}
fp.handle = handle
fp.args = fakePluginArgs
return fp, nil
}
}
// New builds plugin from its arguments while passing a handle
func NewFakeBalance(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plugin, error) {
fakePluginArgs, ok := args.(*FakeBalancePluginArgs)
if !ok {
return nil, fmt.Errorf("want args to be of type FakePluginArgs, got %T", args)
}
ev := &FakeBalancePlugin{}
ev.handle = handle
ev.args = fakePluginArgs
return ev, nil
}
func (c *FakeBalancePlugin) AddReactor(extensionPoint string, reaction ReactionFunc) {
c.ReactionChain = append(c.ReactionChain, &SimpleReactor{ExtensionPoint: extensionPoint, Reaction: reaction})
}
// Name retrieves the plugin name
func (d *FakeBalancePlugin) Name() string {
return d.PluginName
}
func (d *FakeBalancePlugin) Balance(ctx context.Context, nodes []*v1.Node) *frameworktypes.Status {
return d.handleAction(&BalanceActionImpl{
ActionImpl: ActionImpl{
handle: d.handle,
extensionPoint: string(frameworktypes.BalanceExtensionPoint),
},
nodes: nodes,
})
}
func (d *FakeBalancePlugin) handleAction(action Action) *frameworktypes.Status {
actionCopy := action.DeepCopy()
for _, reactor := range d.ReactionChain {
if !reactor.Handles(actionCopy) {
continue
}
handled, _, err := reactor.React(actionCopy)
if !handled {
continue
}
return &frameworktypes.Status{
Err: err,
}
}
return &frameworktypes.Status{
Err: fmt.Errorf("unhandled %q action", action.GetExtensionPoint()),
}
}
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// FakeFilterPluginArgs holds arguments used to configure FakeFilterPlugin plugin.
type FakeFilterPluginArgs struct {
metav1.TypeMeta `json:",inline"`
}
// FakeFilterPlugin is a configurable plugin used for testing
type FakeFilterPlugin struct {
PluginName string
// ReactionChain is the list of reactors that will be attempted for every
// request in the order they are tried.
ReactionChain []Reactor
args runtime.Object
handle frameworktypes.Handle
}
func NewFakeFilterPluginFncFromFake(fp *FakeFilterPlugin) pluginregistry.PluginBuilder {
return func(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plugin, error) {
fakePluginArgs, ok := args.(*FakeFilterPluginArgs)
if !ok {
return nil, fmt.Errorf("want args to be of type FakeFilterPluginArgs, got %T", args)
}
fp.handle = handle
fp.args = fakePluginArgs
return fp, nil
}
}
// New builds plugin from its arguments while passing a handle
func NewFakeFilter(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plugin, error) {
fakePluginArgs, ok := args.(*FakeFilterPluginArgs)
if !ok {
return nil, fmt.Errorf("want args to be of type FakePluginArgs, got %T", args)
}
ev := &FakeFilterPlugin{}
ev.handle = handle
ev.args = fakePluginArgs
return ev, nil
}
func (c *FakeFilterPlugin) AddReactor(extensionPoint string, reaction ReactionFunc) {
c.ReactionChain = append(c.ReactionChain, &SimpleReactor{ExtensionPoint: extensionPoint, Reaction: reaction})
}
// Name retrieves the plugin name
func (d *FakeFilterPlugin) Name() string {
return d.PluginName
}
func (d *FakeFilterPlugin) Filter(pod *v1.Pod) bool {
return d.handleBoolAction(&FilterActionImpl{
ActionImpl: ActionImpl{
handle: d.handle,
extensionPoint: string(frameworktypes.FilterExtensionPoint),
},
})
}
func (d *FakeFilterPlugin) PreEvictionFilter(pod *v1.Pod) bool {
return d.handleBoolAction(&PreEvictionFilterActionImpl{
ActionImpl: ActionImpl{
handle: d.handle,
extensionPoint: string(frameworktypes.PreEvictionFilterExtensionPoint),
},
})
}
func (d *FakeFilterPlugin) handleBoolAction(action Action) bool {
actionCopy := action.DeepCopy()
for _, reactor := range d.ReactionChain {
if !reactor.Handles(actionCopy) {
continue
}
handled, filter, _ := reactor.React(actionCopy)
if !handled {
continue
}
return filter
}
panic(fmt.Errorf("unhandled %q action", action.GetExtensionPoint()))
}