mirror of
https://github.com/kubernetes-sigs/descheduler.git
synced 2026-01-26 05:14:13 +01:00
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
This commit is contained in:
@@ -42,6 +42,9 @@ 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
|
||||
@@ -84,6 +87,10 @@ func New(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plug
|
||||
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
|
||||
@@ -103,7 +110,7 @@ func (d *FakePlugin) handleAction(action Action) *frameworktypes.Status {
|
||||
if !reactor.Handles(actionCopy) {
|
||||
continue
|
||||
}
|
||||
handled, err := reactor.React(actionCopy)
|
||||
handled, _, err := reactor.React(actionCopy)
|
||||
if !handled {
|
||||
continue
|
||||
}
|
||||
@@ -136,3 +143,268 @@ func (d *FakePlugin) Balance(ctx context.Context, nodes []*v1.Node) *frameworkty
|
||||
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()))
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ type Action interface {
|
||||
DeepCopy() Action
|
||||
}
|
||||
|
||||
type ReactionFunc func(action Action) (handled, filter bool, err error)
|
||||
|
||||
// Reactor is an interface to allow the composition of reaction functions.
|
||||
type Reactor interface {
|
||||
// Handles indicates whether or not this Reactor deals with a given
|
||||
@@ -31,7 +33,8 @@ type Reactor interface {
|
||||
Handles(action Action) bool
|
||||
// React handles the action. It may choose to
|
||||
// delegate by indicated handled=false.
|
||||
React(action Action) (handled bool, err error)
|
||||
// filter is used to store results of filter based actions
|
||||
React(action Action) (handled, filter bool, err error)
|
||||
}
|
||||
|
||||
// SimpleReactor is a Reactor. Each reaction function is attached to a given extensionPoint. "*" in either field matches everything for that value.
|
||||
@@ -44,12 +47,10 @@ func (r *SimpleReactor) Handles(action Action) bool {
|
||||
return r.ExtensionPoint == "*" || r.ExtensionPoint == action.GetExtensionPoint()
|
||||
}
|
||||
|
||||
func (r *SimpleReactor) React(action Action) (bool, error) {
|
||||
func (r *SimpleReactor) React(action Action) (bool, bool, error) {
|
||||
return r.Reaction(action)
|
||||
}
|
||||
|
||||
type ReactionFunc func(action Action) (handled bool, err error)
|
||||
|
||||
type DescheduleAction interface {
|
||||
Action
|
||||
CanDeschedule() bool
|
||||
@@ -62,6 +63,16 @@ type BalanceAction interface {
|
||||
Nodes() []*v1.Node
|
||||
}
|
||||
|
||||
type FilterAction interface {
|
||||
Action
|
||||
CanFilter() bool
|
||||
}
|
||||
|
||||
type PreEvictionFilterAction interface {
|
||||
Action
|
||||
CanPreEvictionFilter() bool
|
||||
}
|
||||
|
||||
type ActionImpl struct {
|
||||
handle frameworktypes.Handle
|
||||
extensionPoint string
|
||||
@@ -130,6 +141,30 @@ func (a BalanceActionImpl) DeepCopy() Action {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *FakePlugin) AddReactor(extensionPoint string, reaction ReactionFunc) {
|
||||
c.ReactionChain = append(c.ReactionChain, &SimpleReactor{ExtensionPoint: extensionPoint, Reaction: reaction})
|
||||
type FilterActionImpl struct {
|
||||
ActionImpl
|
||||
}
|
||||
|
||||
func (d FilterActionImpl) CanFilter() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a FilterActionImpl) DeepCopy() Action {
|
||||
return FilterActionImpl{
|
||||
ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
|
||||
}
|
||||
}
|
||||
|
||||
type PreEvictionFilterActionImpl struct {
|
||||
ActionImpl
|
||||
}
|
||||
|
||||
func (d PreEvictionFilterActionImpl) CanPreEvictionFilter() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a PreEvictionFilterActionImpl) DeepCopy() Action {
|
||||
return PreEvictionFilterActionImpl{
|
||||
ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,81 @@ 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 *FakeBalancePluginArgs) DeepCopyInto(out *FakeBalancePluginArgs) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeBalancePluginArgs.
|
||||
func (in *FakeBalancePluginArgs) DeepCopy() *FakeBalancePluginArgs {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FakeBalancePluginArgs)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *FakeBalancePluginArgs) 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 *FakeDeschedulePluginArgs) DeepCopyInto(out *FakeDeschedulePluginArgs) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeDeschedulePluginArgs.
|
||||
func (in *FakeDeschedulePluginArgs) DeepCopy() *FakeDeschedulePluginArgs {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FakeDeschedulePluginArgs)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *FakeDeschedulePluginArgs) 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 *FakeFilterPluginArgs) DeepCopyInto(out *FakeFilterPluginArgs) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeFilterPluginArgs.
|
||||
func (in *FakeFilterPluginArgs) DeepCopy() *FakeFilterPluginArgs {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(FakeFilterPluginArgs)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *FakeFilterPluginArgs) 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 *FakePluginArgs) DeepCopyInto(out *FakePluginArgs) {
|
||||
*out = *in
|
||||
|
||||
Reference in New Issue
Block a user