mirror of
https://github.com/kubernetes-sigs/descheduler.git
synced 2026-01-28 14:41:10 +01:00
RemovePodsViolatingNodeAffinity defaulting + moving arguments to its corresponding plugin
This commit is contained in:
@@ -5,5 +5,5 @@ go build -o "${OS_OUTPUT_BINPATH}/conversion-gen" "k8s.io/code-generator/cmd/con
|
|||||||
|
|
||||||
${OS_OUTPUT_BINPATH}/conversion-gen \
|
${OS_OUTPUT_BINPATH}/conversion-gen \
|
||||||
--go-header-file "hack/boilerplate/boilerplate.go.txt" \
|
--go-header-file "hack/boilerplate/boilerplate.go.txt" \
|
||||||
--input-dirs "${PRJ_PREFIX}/pkg/apis/componentconfig/v1alpha1,${PRJ_PREFIX}/pkg/api/v1alpha1,${PRJ_PREFIX}/pkg/framework/plugins/removefailedpods,${PRJ_PREFIX}/pkg/framework/plugins/nodeutilization,${PRJ_PREFIX}/pkg/framework/plugins/podlifetime,${PRJ_PREFIX}/pkg/framework/plugins/removeduplicates,${PRJ_PREFIX}/pkg/framework/plugins/removepodshavingtoomanyrestarts,${PRJ_PREFIX}/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity" \
|
--input-dirs "${PRJ_PREFIX}/pkg/apis/componentconfig/v1alpha1,${PRJ_PREFIX}/pkg/api/v1alpha1,${PRJ_PREFIX}/pkg/framework/plugins/removefailedpods,${PRJ_PREFIX}/pkg/framework/plugins/nodeutilization,${PRJ_PREFIX}/pkg/framework/plugins/podlifetime,${PRJ_PREFIX}/pkg/framework/plugins/removeduplicates,${PRJ_PREFIX}/pkg/framework/plugins/removepodshavingtoomanyrestarts,${PRJ_PREFIX}/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity,${PRJ_PREFIX}/pkg/framework/plugins/removepodsviolatingnodeaffinity" \
|
||||||
--output-file-base zz_generated.conversion
|
--output-file-base zz_generated.conversion
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ go build -o "${OS_OUTPUT_BINPATH}/deepcopy-gen" "k8s.io/code-generator/cmd/deepc
|
|||||||
|
|
||||||
${OS_OUTPUT_BINPATH}/deepcopy-gen \
|
${OS_OUTPUT_BINPATH}/deepcopy-gen \
|
||||||
--go-header-file "hack/boilerplate/boilerplate.go.txt" \
|
--go-header-file "hack/boilerplate/boilerplate.go.txt" \
|
||||||
--input-dirs "${PRJ_PREFIX}/pkg/apis/componentconfig,${PRJ_PREFIX}/pkg/apis/componentconfig/v1alpha1,${PRJ_PREFIX}/pkg/api,${PRJ_PREFIX}/pkg/api/v1alpha1,${PRJ_PREFIX}/pkg/framework/plugins/defaultevictor/,${PRJ_PREFIX}/pkg/framework/plugins/removefailedpods,${PRJ_PREFIX}/pkg/framework/plugins/nodeutilization,${PRJ_PREFIX}/pkg/framework/plugins/podlifetime,${PRJ_PREFIX}/pkg/framework/plugins/removeduplicates,${PRJ_PREFIX}/pkg/framework/plugins/removepodshavingtoomanyrestarts,${PRJ_PREFIX}/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity" \
|
--input-dirs "${PRJ_PREFIX}/pkg/apis/componentconfig,${PRJ_PREFIX}/pkg/apis/componentconfig/v1alpha1,${PRJ_PREFIX}/pkg/api,${PRJ_PREFIX}/pkg/api/v1alpha1,${PRJ_PREFIX}/pkg/framework/plugins/defaultevictor/,${PRJ_PREFIX}/pkg/framework/plugins/removefailedpods,${PRJ_PREFIX}/pkg/framework/plugins/nodeutilization,${PRJ_PREFIX}/pkg/framework/plugins/podlifetime,${PRJ_PREFIX}/pkg/framework/plugins/removeduplicates,${PRJ_PREFIX}/pkg/framework/plugins/removepodshavingtoomanyrestarts,${PRJ_PREFIX}/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity,${PRJ_PREFIX}/pkg/framework/plugins/removepodsviolatingnodeaffinity" \
|
||||||
--output-file-base zz_generated.deepcopy
|
--output-file-base zz_generated.deepcopy
|
||||||
|
|
||||||
|
|||||||
@@ -35,17 +35,6 @@ type RemovePodsViolatingNodeTaintsArgs struct {
|
|||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
// RemovePodsViolatingNodeAffinityArgs holds arguments used to configure RemovePodsViolatingNodeAffinity plugin.
|
|
||||||
type RemovePodsViolatingNodeAffinityArgs struct {
|
|
||||||
metav1.TypeMeta
|
|
||||||
|
|
||||||
Namespaces *api.Namespaces
|
|
||||||
LabelSelector *metav1.LabelSelector
|
|
||||||
NodeAffinityType []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
@@ -40,20 +40,6 @@ func ValidateRemovePodsViolatingNodeTaintsArgs(args *componentconfig.RemovePodsV
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateRemovePodsViolatingNodeAffinityArgs validates RemovePodsViolatingNodeAffinity arguments
|
|
||||||
func ValidateRemovePodsViolatingNodeAffinityArgs(args *componentconfig.RemovePodsViolatingNodeAffinityArgs) error {
|
|
||||||
var err error
|
|
||||||
if args == nil || len(args.NodeAffinityType) == 0 {
|
|
||||||
err = fmt.Errorf("nodeAffinityType needs to be set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorsAggregate(
|
|
||||||
err,
|
|
||||||
validateNamespaceArgs(args.Namespaces),
|
|
||||||
validateLabelSelectorArgs(args.LabelSelector),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateRemovePodsViolatingTopologySpreadConstraintArgs validates RemovePodsViolatingTopologySpreadConstraint arguments
|
// ValidateRemovePodsViolatingTopologySpreadConstraintArgs validates RemovePodsViolatingTopologySpreadConstraint arguments
|
||||||
func ValidateRemovePodsViolatingTopologySpreadConstraintArgs(args *componentconfig.RemovePodsViolatingTopologySpreadConstraintArgs) error {
|
func ValidateRemovePodsViolatingTopologySpreadConstraintArgs(args *componentconfig.RemovePodsViolatingTopologySpreadConstraintArgs) error {
|
||||||
return errorsAggregate(
|
return errorsAggregate(
|
||||||
|
|||||||
@@ -84,44 +84,3 @@ func TestValidateRemovePodsViolatingNodeTaintsArgs(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateRemovePodsViolatingNodeAffinityArgs(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
description string
|
|
||||||
args *componentconfig.RemovePodsViolatingNodeAffinityArgs
|
|
||||||
expectError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
description: "nil NodeAffinityType args, expects errors",
|
|
||||||
args: &componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
|
||||||
NodeAffinityType: nil,
|
|
||||||
},
|
|
||||||
expectError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "empty NodeAffinityType args, expects errors",
|
|
||||||
args: &componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
|
||||||
NodeAffinityType: []string{},
|
|
||||||
},
|
|
||||||
expectError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "valid NodeAffinityType args, no errors",
|
|
||||||
args: &componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
|
||||||
},
|
|
||||||
expectError: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
|
||||||
err := ValidateRemovePodsViolatingNodeAffinityArgs(tc.args)
|
|
||||||
|
|
||||||
hasError := err != nil
|
|
||||||
if tc.expectError != hasError {
|
|
||||||
t.Error("unexpected arg validation behavior")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -54,46 +54,6 @@ func (in *DeschedulerConfiguration) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopyInto(out *RemovePodsViolatingNodeAffinityArgs) {
|
|
||||||
*out = *in
|
|
||||||
out.TypeMeta = in.TypeMeta
|
|
||||||
if in.Namespaces != nil {
|
|
||||||
in, out := &in.Namespaces, &out.Namespaces
|
|
||||||
*out = new(api.Namespaces)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.LabelSelector != nil {
|
|
||||||
in, out := &in.LabelSelector, &out.LabelSelector
|
|
||||||
*out = new(v1.LabelSelector)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
if in.NodeAffinityType != nil {
|
|
||||||
in, out := &in.NodeAffinityType, &out.NodeAffinityType
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemovePodsViolatingNodeAffinityArgs.
|
|
||||||
func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopy() *RemovePodsViolatingNodeAffinityArgs {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(RemovePodsViolatingNodeAffinityArgs)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
|
||||||
func (in *RemovePodsViolatingNodeAffinityArgs) 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.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *RemovePodsViolatingNodeTaintsArgs) DeepCopyInto(out *RemovePodsViolatingNodeTaintsArgs) {
|
func (in *RemovePodsViolatingNodeTaintsArgs) DeepCopyInto(out *RemovePodsViolatingNodeTaintsArgs) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|||||||
@@ -90,12 +90,12 @@ var pluginsMap = map[string]func(ctx context.Context, nodes []*v1.Node, params *
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"RemovePodsViolatingNodeAffinity": func(ctx context.Context, nodes []*v1.Node, params *api.StrategyParameters, handle *handleImpl) {
|
"RemovePodsViolatingNodeAffinity": func(ctx context.Context, nodes []*v1.Node, params *api.StrategyParameters, handle *handleImpl) {
|
||||||
args := &componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args := &removepodsviolatingnodeaffinity.RemovePodsViolatingNodeAffinityArgs{
|
||||||
Namespaces: params.Namespaces,
|
Namespaces: params.Namespaces,
|
||||||
LabelSelector: params.LabelSelector,
|
LabelSelector: params.LabelSelector,
|
||||||
NodeAffinityType: params.NodeAffinityType,
|
NodeAffinityType: params.NodeAffinityType,
|
||||||
}
|
}
|
||||||
if err := validation.ValidateRemovePodsViolatingNodeAffinityArgs(args); err != nil {
|
if err := removepodsviolatingnodeaffinity.ValidateRemovePodsViolatingNodeAffinityArgs(args); err != nil {
|
||||||
klog.V(1).ErrorS(err, "unable to validate plugin arguments", "pluginName", removepodsviolatingnodeaffinity.PluginName)
|
klog.V(1).ErrorS(err, "unable to validate plugin arguments", "pluginName", removepodsviolatingnodeaffinity.PluginName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
"sigs.k8s.io/descheduler/pkg/apis/componentconfig"
|
|
||||||
"sigs.k8s.io/descheduler/pkg/descheduler/evictions"
|
"sigs.k8s.io/descheduler/pkg/descheduler/evictions"
|
||||||
nodeutil "sigs.k8s.io/descheduler/pkg/descheduler/node"
|
nodeutil "sigs.k8s.io/descheduler/pkg/descheduler/node"
|
||||||
podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod"
|
podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod"
|
||||||
@@ -35,7 +34,7 @@ const PluginName = "RemovePodsViolatingNodeAffinity"
|
|||||||
// RemovePodsViolatingNodeAffinity evicts pods on the node which violate node affinity
|
// RemovePodsViolatingNodeAffinity evicts pods on the node which violate node affinity
|
||||||
type RemovePodsViolatingNodeAffinity struct {
|
type RemovePodsViolatingNodeAffinity struct {
|
||||||
handle framework.Handle
|
handle framework.Handle
|
||||||
args *componentconfig.RemovePodsViolatingNodeAffinityArgs
|
args *RemovePodsViolatingNodeAffinityArgs
|
||||||
podFilter podutil.FilterFunc
|
podFilter podutil.FilterFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +42,7 @@ var _ framework.DeschedulePlugin = &RemovePodsViolatingNodeAffinity{}
|
|||||||
|
|
||||||
// New builds plugin from its arguments while passing a handle
|
// New builds plugin from its arguments while passing a handle
|
||||||
func New(args runtime.Object, handle framework.Handle) (framework.Plugin, error) {
|
func New(args runtime.Object, handle framework.Handle) (framework.Plugin, error) {
|
||||||
nodeAffinityArgs, ok := args.(*componentconfig.RemovePodsViolatingNodeAffinityArgs)
|
nodeAffinityArgs, ok := args.(*RemovePodsViolatingNodeAffinityArgs)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("want args to be of type RemovePodsViolatingNodeAffinityArgs, got %T", args)
|
return nil, fmt.Errorf("want args to be of type RemovePodsViolatingNodeAffinityArgs, got %T", args)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import (
|
|||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
"k8s.io/client-go/tools/events"
|
"k8s.io/client-go/tools/events"
|
||||||
"sigs.k8s.io/descheduler/pkg/apis/componentconfig"
|
|
||||||
"sigs.k8s.io/descheduler/pkg/framework"
|
"sigs.k8s.io/descheduler/pkg/framework"
|
||||||
|
|
||||||
"sigs.k8s.io/descheduler/pkg/descheduler/evictions"
|
"sigs.k8s.io/descheduler/pkg/descheduler/evictions"
|
||||||
@@ -96,12 +95,12 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
expectedEvictedPodCount uint
|
expectedEvictedPodCount uint
|
||||||
maxPodsToEvictPerNode *uint
|
maxPodsToEvictPerNode *uint
|
||||||
maxNoOfPodsToEvictPerNamespace *uint
|
maxNoOfPodsToEvictPerNamespace *uint
|
||||||
args componentconfig.RemovePodsViolatingNodeAffinityArgs
|
args RemovePodsViolatingNodeAffinityArgs
|
||||||
nodefit bool
|
nodefit bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
description: "Invalid Affinity type, should not evict any pods",
|
description: "Invalid Affinity type, should not evict any pods",
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingRequiredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingRequiredDuringExecution"},
|
||||||
},
|
},
|
||||||
expectedEvictedPodCount: 0,
|
expectedEvictedPodCount: 0,
|
||||||
@@ -110,7 +109,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Pod is correctly scheduled on node, no eviction expected",
|
description: "Pod is correctly scheduled on node, no eviction expected",
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
},
|
},
|
||||||
expectedEvictedPodCount: 0,
|
expectedEvictedPodCount: 0,
|
||||||
@@ -120,7 +119,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "Pod is scheduled on node without matching labels, another schedulable node available, should be evicted",
|
description: "Pod is scheduled on node without matching labels, another schedulable node available, should be evicted",
|
||||||
expectedEvictedPodCount: 1,
|
expectedEvictedPodCount: 1,
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
},
|
},
|
||||||
pods: addPodsToNode(nodeWithoutLabels, nil),
|
pods: addPodsToNode(nodeWithoutLabels, nil),
|
||||||
@@ -129,7 +128,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxPodsToEvictPerNode set to 1, should not be evicted",
|
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxPodsToEvictPerNode set to 1, should not be evicted",
|
||||||
expectedEvictedPodCount: 1,
|
expectedEvictedPodCount: 1,
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
},
|
},
|
||||||
pods: addPodsToNode(nodeWithoutLabels, nil),
|
pods: addPodsToNode(nodeWithoutLabels, nil),
|
||||||
@@ -139,7 +138,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxPodsToEvictPerNode set to 1, no pod evicted since pod terminting",
|
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxPodsToEvictPerNode set to 1, no pod evicted since pod terminting",
|
||||||
expectedEvictedPodCount: 1,
|
expectedEvictedPodCount: 1,
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
},
|
},
|
||||||
pods: addPodsToNode(nodeWithoutLabels, &metav1.Time{}),
|
pods: addPodsToNode(nodeWithoutLabels, &metav1.Time{}),
|
||||||
@@ -149,7 +148,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxNoOfPodsToEvictPerNamespace set to 1, should not be evicted",
|
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxNoOfPodsToEvictPerNamespace set to 1, should not be evicted",
|
||||||
expectedEvictedPodCount: 1,
|
expectedEvictedPodCount: 1,
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
},
|
},
|
||||||
pods: addPodsToNode(nodeWithoutLabels, nil),
|
pods: addPodsToNode(nodeWithoutLabels, nil),
|
||||||
@@ -159,7 +158,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxNoOfPodsToEvictPerNamespace set to 1, no pod evicted since pod terminting",
|
description: "Pod is scheduled on node without matching labels, another schedulable node available, maxNoOfPodsToEvictPerNamespace set to 1, no pod evicted since pod terminting",
|
||||||
expectedEvictedPodCount: 1,
|
expectedEvictedPodCount: 1,
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
},
|
},
|
||||||
pods: addPodsToNode(nodeWithoutLabels, &metav1.Time{}),
|
pods: addPodsToNode(nodeWithoutLabels, &metav1.Time{}),
|
||||||
@@ -169,7 +168,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "Pod is scheduled on node without matching labels, but no node where pod fits is available, should not evict",
|
description: "Pod is scheduled on node without matching labels, but no node where pod fits is available, should not evict",
|
||||||
expectedEvictedPodCount: 0,
|
expectedEvictedPodCount: 0,
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
},
|
},
|
||||||
pods: addPodsToNode(nodeWithoutLabels, nil),
|
pods: addPodsToNode(nodeWithoutLabels, nil),
|
||||||
@@ -179,7 +178,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "Pod is scheduled on node without matching labels, and node where pod fits is available, should evict",
|
description: "Pod is scheduled on node without matching labels, and node where pod fits is available, should evict",
|
||||||
expectedEvictedPodCount: 0,
|
expectedEvictedPodCount: 0,
|
||||||
args: componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
args: RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
},
|
},
|
||||||
pods: addPodsToNode(nodeWithoutLabels, nil),
|
pods: addPodsToNode(nodeWithoutLabels, nil),
|
||||||
@@ -257,7 +256,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugin, err := New(
|
plugin, err := New(
|
||||||
&componentconfig.RemovePodsViolatingNodeAffinityArgs{
|
&RemovePodsViolatingNodeAffinityArgs{
|
||||||
NodeAffinityType: tc.args.NodeAffinityType,
|
NodeAffinityType: tc.args.NodeAffinityType,
|
||||||
},
|
},
|
||||||
handle,
|
handle,
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
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 removepodsviolatingnodeaffinity
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"sigs.k8s.io/descheduler/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// RemovePodsViolatingNodeAffinityArgs holds arguments used to configure RemovePodsViolatingNodeAffinity plugin.
|
||||||
|
type RemovePodsViolatingNodeAffinityArgs struct {
|
||||||
|
metav1.TypeMeta
|
||||||
|
|
||||||
|
Namespaces *api.Namespaces
|
||||||
|
LabelSelector *metav1.LabelSelector
|
||||||
|
NodeAffinityType []string
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
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 removepodsviolatingnodeaffinity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateRemovePodsViolatingNodeAffinityArgs validates RemovePodsViolatingNodeAffinity arguments
|
||||||
|
func ValidateRemovePodsViolatingNodeAffinityArgs(args *RemovePodsViolatingNodeAffinityArgs) error {
|
||||||
|
if args == nil || len(args.NodeAffinityType) == 0 {
|
||||||
|
return fmt.Errorf("nodeAffinityType needs to be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// At most one of include/exclude can be set
|
||||||
|
if args.Namespaces != nil && len(args.Namespaces.Include) > 0 && len(args.Namespaces.Exclude) > 0 {
|
||||||
|
return fmt.Errorf("only one of Include/Exclude namespaces can be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.LabelSelector != nil {
|
||||||
|
if _, err := metav1.LabelSelectorAsSelector(args.LabelSelector); err != nil {
|
||||||
|
return fmt.Errorf("failed to get label selectors from strategy's params: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
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 removepodsviolatingnodeaffinity
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestValidateRemovePodsViolatingNodeAffinityArgs(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
args *RemovePodsViolatingNodeAffinityArgs
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "nil NodeAffinityType args, expects errors",
|
||||||
|
args: &RemovePodsViolatingNodeAffinityArgs{
|
||||||
|
NodeAffinityType: nil,
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "empty NodeAffinityType args, expects errors",
|
||||||
|
args: &RemovePodsViolatingNodeAffinityArgs{
|
||||||
|
NodeAffinityType: []string{},
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "valid NodeAffinityType args, no errors",
|
||||||
|
args: &RemovePodsViolatingNodeAffinityArgs{
|
||||||
|
NodeAffinityType: []string{"requiredDuringSchedulingIgnoredDuringExecution"},
|
||||||
|
},
|
||||||
|
expectError: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
err := ValidateRemovePodsViolatingNodeAffinityArgs(tc.args)
|
||||||
|
|
||||||
|
hasError := err != nil
|
||||||
|
if tc.expectError != hasError {
|
||||||
|
t.Error("unexpected arg validation behavior")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
//go:build !ignore_autogenerated
|
||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package removepodsviolatingnodeaffinity
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
api "sigs.k8s.io/descheduler/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopyInto(out *RemovePodsViolatingNodeAffinityArgs) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
if in.Namespaces != nil {
|
||||||
|
in, out := &in.Namespaces, &out.Namespaces
|
||||||
|
*out = new(api.Namespaces)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.LabelSelector != nil {
|
||||||
|
in, out := &in.LabelSelector, &out.LabelSelector
|
||||||
|
*out = new(v1.LabelSelector)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.NodeAffinityType != nil {
|
||||||
|
in, out := &in.NodeAffinityType, &out.NodeAffinityType
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemovePodsViolatingNodeAffinityArgs.
|
||||||
|
func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopy() *RemovePodsViolatingNodeAffinityArgs {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RemovePodsViolatingNodeAffinityArgs)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user