mirror of
https://github.com/kubernetes-sigs/descheduler.git
synced 2026-01-28 06:29:29 +01:00
PodLifeTime 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" \
|
--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" \
|
||||||
--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" \
|
--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" \
|
||||||
--output-file-base zz_generated.deepcopy
|
--output-file-base zz_generated.deepcopy
|
||||||
|
|
||||||
|
|||||||
@@ -67,18 +67,6 @@ type RemoveDuplicatesArgs struct {
|
|||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
// PodLifeTimeArgs holds arguments used to configure PodLifeTime plugin.
|
|
||||||
type PodLifeTimeArgs struct {
|
|
||||||
metav1.TypeMeta
|
|
||||||
|
|
||||||
Namespaces *api.Namespaces
|
|
||||||
LabelSelector *metav1.LabelSelector
|
|
||||||
MaxPodLifeTimeSeconds *uint
|
|
||||||
States []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
|
||||||
|
|||||||
@@ -19,11 +19,8 @@ package validation
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"sigs.k8s.io/descheduler/pkg/api"
|
"sigs.k8s.io/descheduler/pkg/api"
|
||||||
"sigs.k8s.io/descheduler/pkg/apis/componentconfig"
|
"sigs.k8s.io/descheduler/pkg/apis/componentconfig"
|
||||||
)
|
)
|
||||||
@@ -66,21 +63,6 @@ func ValidateRemovePodsViolatingNodeAffinityArgs(args *componentconfig.RemovePod
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidatePodLifeTimeArgs validates PodLifeTime arguments
|
|
||||||
func ValidatePodLifeTimeArgs(args *componentconfig.PodLifeTimeArgs) error {
|
|
||||||
var err error
|
|
||||||
if args.MaxPodLifeTimeSeconds == nil {
|
|
||||||
err = fmt.Errorf("MaxPodLifeTimeSeconds not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorsAggregate(
|
|
||||||
err,
|
|
||||||
validateNamespaceArgs(args.Namespaces),
|
|
||||||
validateLabelSelectorArgs(args.LabelSelector),
|
|
||||||
validatePodLifeTimeStates(args.States),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidateRemoveDuplicatesArgs(args *componentconfig.RemoveDuplicatesArgs) error {
|
func ValidateRemoveDuplicatesArgs(args *componentconfig.RemoveDuplicatesArgs) error {
|
||||||
return validateNamespaceArgs(args.Namespaces)
|
return validateNamespaceArgs(args.Namespaces)
|
||||||
}
|
}
|
||||||
@@ -132,20 +114,3 @@ func validatePodRestartThreshold(podRestartThreshold int32) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatePodLifeTimeStates(states []string) error {
|
|
||||||
podLifeTimeAllowedStates := sets.NewString(
|
|
||||||
string(v1.PodRunning),
|
|
||||||
string(v1.PodPending),
|
|
||||||
|
|
||||||
// Container state reasons: https://github.com/kubernetes/kubernetes/blob/release-1.24/pkg/kubelet/kubelet_pods.go#L76-L79
|
|
||||||
"PodInitializing",
|
|
||||||
"ContainerCreating",
|
|
||||||
)
|
|
||||||
|
|
||||||
if !podLifeTimeAllowedStates.HasAll(states...) {
|
|
||||||
return fmt.Errorf("states must be one of %v", podLifeTimeAllowedStates.List())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package validation
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/descheduler/pkg/api"
|
"sigs.k8s.io/descheduler/pkg/api"
|
||||||
"sigs.k8s.io/descheduler/pkg/apis/componentconfig"
|
"sigs.k8s.io/descheduler/pkg/apis/componentconfig"
|
||||||
@@ -126,45 +125,3 @@ func TestValidateRemovePodsViolatingNodeAffinityArgs(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateRemovePodLifeTimeArgs(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
description string
|
|
||||||
args *componentconfig.PodLifeTimeArgs
|
|
||||||
expectError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
description: "valid arg, no errors",
|
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
|
||||||
MaxPodLifeTimeSeconds: func(i uint) *uint { return &i }(1),
|
|
||||||
States: []string{string(v1.PodRunning)},
|
|
||||||
},
|
|
||||||
expectError: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "nil MaxPodLifeTimeSeconds arg, expects errors",
|
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
|
||||||
MaxPodLifeTimeSeconds: nil,
|
|
||||||
},
|
|
||||||
expectError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "invalid pod state arg, expects errors",
|
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
|
||||||
States: []string{string(v1.NodeRunning)},
|
|
||||||
},
|
|
||||||
expectError: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
|
||||||
err := ValidatePodLifeTimeArgs(tc.args)
|
|
||||||
|
|
||||||
hasError := err != nil
|
|
||||||
if tc.expectError != hasError {
|
|
||||||
t.Error("unexpected arg validation behavior")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -54,51 +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 *PodLifeTimeArgs) DeepCopyInto(out *PodLifeTimeArgs) {
|
|
||||||
*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.MaxPodLifeTimeSeconds != nil {
|
|
||||||
in, out := &in.MaxPodLifeTimeSeconds, &out.MaxPodLifeTimeSeconds
|
|
||||||
*out = new(uint)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
if in.States != nil {
|
|
||||||
in, out := &in.States, &out.States
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodLifeTimeArgs.
|
|
||||||
func (in *PodLifeTimeArgs) DeepCopy() *PodLifeTimeArgs {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(PodLifeTimeArgs)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
|
||||||
func (in *PodLifeTimeArgs) 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 *RemoveDuplicatesArgs) DeepCopyInto(out *RemoveDuplicatesArgs) {
|
func (in *RemoveDuplicatesArgs) DeepCopyInto(out *RemoveDuplicatesArgs) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|||||||
@@ -167,13 +167,13 @@ var pluginsMap = map[string]func(ctx context.Context, nodes []*v1.Node, params *
|
|||||||
states = append(states, podLifeTimeParams.States...)
|
states = append(states, podLifeTimeParams.States...)
|
||||||
}
|
}
|
||||||
|
|
||||||
args := &componentconfig.PodLifeTimeArgs{
|
args := &podlifetime.PodLifeTimeArgs{
|
||||||
Namespaces: params.Namespaces,
|
Namespaces: params.Namespaces,
|
||||||
LabelSelector: params.LabelSelector,
|
LabelSelector: params.LabelSelector,
|
||||||
MaxPodLifeTimeSeconds: podLifeTimeParams.MaxPodLifeTimeSeconds,
|
MaxPodLifeTimeSeconds: podLifeTimeParams.MaxPodLifeTimeSeconds,
|
||||||
States: states,
|
States: states,
|
||||||
}
|
}
|
||||||
if err := validation.ValidatePodLifeTimeArgs(args); err != nil {
|
if err := podlifetime.ValidatePodLifeTimeArgs(args); err != nil {
|
||||||
klog.V(1).ErrorS(err, "unable to validate plugin arguments", "pluginName", podlifetime.PluginName)
|
klog.V(1).ErrorS(err, "unable to validate plugin arguments", "pluginName", podlifetime.PluginName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
"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"
|
||||||
@@ -39,13 +38,13 @@ var _ framework.DeschedulePlugin = &PodLifeTime{}
|
|||||||
// PodLifeTime evicts pods on the node that violate the max pod lifetime threshold
|
// PodLifeTime evicts pods on the node that violate the max pod lifetime threshold
|
||||||
type PodLifeTime struct {
|
type PodLifeTime struct {
|
||||||
handle framework.Handle
|
handle framework.Handle
|
||||||
args *componentconfig.PodLifeTimeArgs
|
args *PodLifeTimeArgs
|
||||||
podFilter podutil.FilterFunc
|
podFilter podutil.FilterFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
podLifeTimeArgs, ok := args.(*componentconfig.PodLifeTimeArgs)
|
podLifeTimeArgs, ok := args.(*PodLifeTimeArgs)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("want args to be of type PodLifeTimeArgs, got %T", args)
|
return nil, fmt.Errorf("want args to be of type PodLifeTimeArgs, got %T", args)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,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/descheduler/evictions"
|
"sigs.k8s.io/descheduler/pkg/descheduler/evictions"
|
||||||
podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod"
|
podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod"
|
||||||
"sigs.k8s.io/descheduler/pkg/framework"
|
"sigs.k8s.io/descheduler/pkg/framework"
|
||||||
@@ -143,7 +142,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
var maxLifeTime uint = 600
|
var maxLifeTime uint = 600
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
args *componentconfig.PodLifeTimeArgs
|
args *PodLifeTimeArgs
|
||||||
pods []*v1.Pod
|
pods []*v1.Pod
|
||||||
nodes []*v1.Node
|
nodes []*v1.Node
|
||||||
expectedEvictedPodCount uint
|
expectedEvictedPodCount uint
|
||||||
@@ -153,7 +152,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
description: "Two pods in the `dev` Namespace, 1 is new and 1 very is old. 1 should be evicted.",
|
description: "Two pods in the `dev` Namespace, 1 is new and 1 very is old. 1 should be evicted.",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p1, p2},
|
pods: []*v1.Pod{p1, p2},
|
||||||
@@ -162,7 +161,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Two pods in the `dev` Namespace, 2 are new and 0 are old. 0 should be evicted.",
|
description: "Two pods in the `dev` Namespace, 2 are new and 0 are old. 0 should be evicted.",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p3, p4},
|
pods: []*v1.Pod{p3, p4},
|
||||||
@@ -171,7 +170,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Two pods in the `dev` Namespace, 1 created 605 seconds ago. 1 should be evicted.",
|
description: "Two pods in the `dev` Namespace, 1 created 605 seconds ago. 1 should be evicted.",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p5, p6},
|
pods: []*v1.Pod{p5, p6},
|
||||||
@@ -180,7 +179,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Two pods in the `dev` Namespace, 1 created 595 seconds ago. 0 should be evicted.",
|
description: "Two pods in the `dev` Namespace, 1 created 595 seconds ago. 0 should be evicted.",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p7, p8},
|
pods: []*v1.Pod{p7, p8},
|
||||||
@@ -189,7 +188,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Two pods, one with ContainerCreating state. 1 should be evicted.",
|
description: "Two pods, one with ContainerCreating state. 1 should be evicted.",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
States: []string{"ContainerCreating"},
|
States: []string{"ContainerCreating"},
|
||||||
},
|
},
|
||||||
@@ -212,7 +211,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Two pods, one with PodInitializing state. 1 should be evicted.",
|
description: "Two pods, one with PodInitializing state. 1 should be evicted.",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
States: []string{"PodInitializing"},
|
States: []string{"PodInitializing"},
|
||||||
},
|
},
|
||||||
@@ -235,7 +234,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Two old pods with different states. 1 should be evicted.",
|
description: "Two old pods with different states. 1 should be evicted.",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
States: []string{"Pending"},
|
States: []string{"Pending"},
|
||||||
},
|
},
|
||||||
@@ -245,7 +244,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "does not evict pvc pods with ignorePvcPods set to true",
|
description: "does not evict pvc pods with ignorePvcPods set to true",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p11},
|
pods: []*v1.Pod{p11},
|
||||||
@@ -255,7 +254,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "evicts pvc pods with ignorePvcPods set to false (or unset)",
|
description: "evicts pvc pods with ignorePvcPods set to false (or unset)",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p11},
|
pods: []*v1.Pod{p11},
|
||||||
@@ -264,7 +263,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "No pod to evicted since all pod terminating",
|
description: "No pod to evicted since all pod terminating",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
LabelSelector: &metav1.LabelSelector{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
MatchLabels: map[string]string{"foo": "bar"},
|
MatchLabels: map[string]string{"foo": "bar"},
|
||||||
@@ -276,7 +275,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "No pod should be evicted since pod terminating",
|
description: "No pod should be evicted since pod terminating",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
LabelSelector: &metav1.LabelSelector{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
MatchLabels: map[string]string{"foo": "bar"},
|
MatchLabels: map[string]string{"foo": "bar"},
|
||||||
@@ -288,7 +287,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "2 Oldest pods should be evicted when maxPodsToEvictPerNode and maxPodsToEvictPerNamespace are not set",
|
description: "2 Oldest pods should be evicted when maxPodsToEvictPerNode and maxPodsToEvictPerNamespace are not set",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p1, p2, p9},
|
pods: []*v1.Pod{p1, p2, p9},
|
||||||
@@ -299,7 +298,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "1 Oldest pod should be evicted when maxPodsToEvictPerNamespace is set to 1",
|
description: "1 Oldest pod should be evicted when maxPodsToEvictPerNamespace is set to 1",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p1, p2, p9},
|
pods: []*v1.Pod{p1, p2, p9},
|
||||||
@@ -309,7 +308,7 @@ func TestPodLifeTime(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "1 Oldest pod should be evicted when maxPodsToEvictPerNode is set to 1",
|
description: "1 Oldest pod should be evicted when maxPodsToEvictPerNode is set to 1",
|
||||||
args: &componentconfig.PodLifeTimeArgs{
|
args: &PodLifeTimeArgs{
|
||||||
MaxPodLifeTimeSeconds: &maxLifeTime,
|
MaxPodLifeTimeSeconds: &maxLifeTime,
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{p1, p2, p9},
|
pods: []*v1.Pod{p1, p2, p9},
|
||||||
|
|||||||
32
pkg/framework/plugins/podlifetime/types.go
Normal file
32
pkg/framework/plugins/podlifetime/types.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
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 podlifetime
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// PodLifeTimeArgs holds arguments used to configure PodLifeTime plugin.
|
||||||
|
type PodLifeTimeArgs struct {
|
||||||
|
metav1.TypeMeta
|
||||||
|
|
||||||
|
Namespaces *api.Namespaces
|
||||||
|
LabelSelector *metav1.LabelSelector
|
||||||
|
MaxPodLifeTimeSeconds *uint
|
||||||
|
States []string
|
||||||
|
}
|
||||||
56
pkg/framework/plugins/podlifetime/validation.go
Normal file
56
pkg/framework/plugins/podlifetime/validation.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
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 podlifetime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidatePodLifeTimeArgs validates PodLifeTime arguments
|
||||||
|
func ValidatePodLifeTimeArgs(args *PodLifeTimeArgs) error {
|
||||||
|
if args.MaxPodLifeTimeSeconds == nil {
|
||||||
|
return fmt.Errorf("MaxPodLifeTimeSeconds not 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
podLifeTimeAllowedStates := sets.NewString(
|
||||||
|
string(v1.PodRunning),
|
||||||
|
string(v1.PodPending),
|
||||||
|
|
||||||
|
// Container state reasons: https://github.com/kubernetes/kubernetes/blob/release-1.24/pkg/kubelet/kubelet_pods.go#L76-L79
|
||||||
|
"PodInitializing",
|
||||||
|
"ContainerCreating",
|
||||||
|
)
|
||||||
|
|
||||||
|
if !podLifeTimeAllowedStates.HasAll(args.States...) {
|
||||||
|
return fmt.Errorf("states must be one of %v", podLifeTimeAllowedStates.List())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
64
pkg/framework/plugins/podlifetime/validation_test.go
Normal file
64
pkg/framework/plugins/podlifetime/validation_test.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
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 podlifetime
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateRemovePodLifeTimeArgs(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
args *PodLifeTimeArgs
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "valid arg, no errors",
|
||||||
|
args: &PodLifeTimeArgs{
|
||||||
|
MaxPodLifeTimeSeconds: func(i uint) *uint { return &i }(1),
|
||||||
|
States: []string{string(v1.PodRunning)},
|
||||||
|
},
|
||||||
|
expectError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "nil MaxPodLifeTimeSeconds arg, expects errors",
|
||||||
|
args: &PodLifeTimeArgs{
|
||||||
|
MaxPodLifeTimeSeconds: nil,
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "invalid pod state arg, expects errors",
|
||||||
|
args: &PodLifeTimeArgs{
|
||||||
|
States: []string{string(v1.NodeRunning)},
|
||||||
|
},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
err := ValidatePodLifeTimeArgs(tc.args)
|
||||||
|
|
||||||
|
hasError := err != nil
|
||||||
|
if tc.expectError != hasError {
|
||||||
|
t.Error("unexpected arg validation behavior")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
73
pkg/framework/plugins/podlifetime/zz_generated.deepcopy.go
Normal file
73
pkg/framework/plugins/podlifetime/zz_generated.deepcopy.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
//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 podlifetime
|
||||||
|
|
||||||
|
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 *PodLifeTimeArgs) DeepCopyInto(out *PodLifeTimeArgs) {
|
||||||
|
*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.MaxPodLifeTimeSeconds != nil {
|
||||||
|
in, out := &in.MaxPodLifeTimeSeconds, &out.MaxPodLifeTimeSeconds
|
||||||
|
*out = new(uint)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.States != nil {
|
||||||
|
in, out := &in.States, &out.States
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodLifeTimeArgs.
|
||||||
|
func (in *PodLifeTimeArgs) DeepCopy() *PodLifeTimeArgs {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(PodLifeTimeArgs)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *PodLifeTimeArgs) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user