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

Descheduling profile with PoC fake plugin (#1093)

* Descheduling profile

* Fake plugin + profile unit testing

* Rename Profile config type into DeschedulerProfile

To avoid resamblance with profileImpl

* First run deschedule, then balance extension points
This commit is contained in:
Jan Chaloupka
2023-03-23 17:14:33 +01:00
committed by GitHub
parent 0872b214ff
commit bcc6c8eb2a
18 changed files with 1088 additions and 301 deletions

View File

@@ -0,0 +1,138 @@
/*
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"
"sigs.k8s.io/descheduler/pkg/framework/pluginregistry"
)
// +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 (
_ framework.EvictorPlugin = &FakePlugin{}
_ framework.DeschedulePlugin = &FakePlugin{}
_ framework.BalancePlugin = &FakePlugin{}
)
// 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 framework.Handle
}
func NewPluginFncFromFake(fp *FakePlugin) pluginregistry.PluginBuilder {
return func(args runtime.Object, handle framework.Handle) (framework.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 framework.Handle) (framework.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
}
// 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) *framework.Status {
actionCopy := action.DeepCopy()
for _, reactor := range d.ReactionChain {
if !reactor.Handles(actionCopy) {
continue
}
handled, err := reactor.React(actionCopy)
if !handled {
continue
}
return &framework.Status{
Err: err,
}
}
return &framework.Status{
Err: fmt.Errorf("unhandled %q action", action.GetExtensionPoint()),
}
}
func (d *FakePlugin) Deschedule(ctx context.Context, nodes []*v1.Node) *framework.Status {
return d.handleAction(&DescheduleActionImpl{
ActionImpl: ActionImpl{
handle: d.handle,
extensionPoint: string(framework.DescheduleExtensionPoint),
},
nodes: nodes,
})
}
func (d *FakePlugin) Balance(ctx context.Context, nodes []*v1.Node) *framework.Status {
return d.handleAction(&BalanceActionImpl{
ActionImpl: ActionImpl{
handle: d.handle,
extensionPoint: string(framework.BalanceExtensionPoint),
},
nodes: nodes,
})
}

View File

@@ -0,0 +1,135 @@
/*
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 (
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/descheduler/pkg/framework"
)
type Action interface {
Handle() framework.Handle
GetExtensionPoint() string
DeepCopy() Action
}
// 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
// action.
Handles(action Action) bool
// React handles the action. It may choose to
// delegate by indicated handled=false.
React(action Action) (handled bool, err error)
}
// SimpleReactor is a Reactor. Each reaction function is attached to a given extensionPoint. "*" in either field matches everything for that value.
type SimpleReactor struct {
ExtensionPoint string
Reaction ReactionFunc
}
func (r *SimpleReactor) Handles(action Action) bool {
return r.ExtensionPoint == "*" || r.ExtensionPoint == action.GetExtensionPoint()
}
func (r *SimpleReactor) React(action Action) (bool, error) {
return r.Reaction(action)
}
type ReactionFunc func(action Action) (handled bool, err error)
type DescheduleAction interface {
Action
CanDeschedule() bool
Nodes() []*v1.Node
}
type BalanceAction interface {
Action
CanBalance() bool
Nodes() []*v1.Node
}
type ActionImpl struct {
handle framework.Handle
extensionPoint string
}
func (a ActionImpl) Handle() framework.Handle {
return a.handle
}
func (a ActionImpl) GetExtensionPoint() string {
return a.extensionPoint
}
func (a ActionImpl) DeepCopy() Action {
// The handle is expected to be accessed only throuh interface methods
// Thus, no deep copy needed.
ret := a
return ret
}
type DescheduleActionImpl struct {
ActionImpl
nodes []*v1.Node
}
func (d DescheduleActionImpl) CanDeschedule() bool {
return true
}
func (d DescheduleActionImpl) Nodes() []*v1.Node {
return d.nodes
}
func (a DescheduleActionImpl) DeepCopy() Action {
nodesCopy := []*v1.Node{}
for _, node := range a.nodes {
nodesCopy = append(nodesCopy, node.DeepCopy())
}
return DescheduleActionImpl{
ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
nodes: nodesCopy,
}
}
type BalanceActionImpl struct {
ActionImpl
nodes []*v1.Node
}
func (d BalanceActionImpl) CanBalance() bool {
return true
}
func (d BalanceActionImpl) Nodes() []*v1.Node {
return d.nodes
}
func (a BalanceActionImpl) DeepCopy() Action {
nodesCopy := []*v1.Node{}
for _, node := range a.nodes {
nodesCopy = append(nodesCopy, node.DeepCopy())
}
return BalanceActionImpl{
ActionImpl: a.ActionImpl.DeepCopy().(ActionImpl),
nodes: nodesCopy,
}
}
func (c *FakePlugin) AddReactor(extensionPoint string, reaction ReactionFunc) {
c.ReactionChain = append(c.ReactionChain, &SimpleReactor{ExtensionPoint: extensionPoint, Reaction: reaction})
}

View File

@@ -0,0 +1,51 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package plugin
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 *FakePluginArgs) DeepCopyInto(out *FakePluginArgs) {
*out = *in
out.TypeMeta = in.TypeMeta
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakePluginArgs.
func (in *FakePluginArgs) DeepCopy() *FakePluginArgs {
if in == nil {
return nil
}
out := new(FakePluginArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *FakePluginArgs) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}