From 0c88326df94012b17f2269380b2eb047255cd821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?vlc=E5=88=98=E8=AF=9A?= Date: Mon, 19 Sep 2022 13:45:08 +0800 Subject: [PATCH] PodLifeTime defaulting + moving arguments to its corresponding plugin --- hack/update-generated-conversions.sh | 2 +- hack/update-generated-deep-copies.sh | 2 +- pkg/apis/componentconfig/types_pluginargs.go | 12 --- .../validation/validation_pluginargs.go | 37 +--------- .../validation/validation_pluginargs_test.go | 43 ----------- .../componentconfig/zz_generated.deepcopy.go | 45 ------------ pkg/descheduler/strategy_migration.go | 4 +- .../plugins/podlifetime/pod_lifetime.go | 5 +- .../plugins/podlifetime/pod_lifetime_test.go | 31 ++++---- pkg/framework/plugins/podlifetime/types.go | 32 ++++++++ .../plugins/podlifetime/validation.go | 56 ++++++++++++++ .../plugins/podlifetime/validation_test.go | 64 ++++++++++++++++ .../podlifetime/zz_generated.deepcopy.go | 73 +++++++++++++++++++ 13 files changed, 247 insertions(+), 159 deletions(-) create mode 100644 pkg/framework/plugins/podlifetime/types.go create mode 100644 pkg/framework/plugins/podlifetime/validation.go create mode 100644 pkg/framework/plugins/podlifetime/validation_test.go create mode 100644 pkg/framework/plugins/podlifetime/zz_generated.deepcopy.go diff --git a/hack/update-generated-conversions.sh b/hack/update-generated-conversions.sh index 8d2a7a467..4b723a98a 100755 --- a/hack/update-generated-conversions.sh +++ b/hack/update-generated-conversions.sh @@ -5,5 +5,5 @@ go build -o "${OS_OUTPUT_BINPATH}/conversion-gen" "k8s.io/code-generator/cmd/con ${OS_OUTPUT_BINPATH}/conversion-gen \ --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 diff --git a/hack/update-generated-deep-copies.sh b/hack/update-generated-deep-copies.sh index 49f533152..7c0f60ad4 100755 --- a/hack/update-generated-deep-copies.sh +++ b/hack/update-generated-deep-copies.sh @@ -5,6 +5,6 @@ go build -o "${OS_OUTPUT_BINPATH}/deepcopy-gen" "k8s.io/code-generator/cmd/deepc ${OS_OUTPUT_BINPATH}/deepcopy-gen \ --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 diff --git a/pkg/apis/componentconfig/types_pluginargs.go b/pkg/apis/componentconfig/types_pluginargs.go index 2394c1904..1fcfe4e87 100644 --- a/pkg/apis/componentconfig/types_pluginargs.go +++ b/pkg/apis/componentconfig/types_pluginargs.go @@ -67,18 +67,6 @@ type RemoveDuplicatesArgs struct { // +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. type RemovePodsViolatingTopologySpreadConstraintArgs struct { metav1.TypeMeta diff --git a/pkg/apis/componentconfig/validation/validation_pluginargs.go b/pkg/apis/componentconfig/validation/validation_pluginargs.go index d19a3421c..cf84aeac0 100644 --- a/pkg/apis/componentconfig/validation/validation_pluginargs.go +++ b/pkg/apis/componentconfig/validation/validation_pluginargs.go @@ -19,11 +19,8 @@ package validation import ( "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" + utilerrors "k8s.io/apimachinery/pkg/util/errors" "sigs.k8s.io/descheduler/pkg/api" "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 { return validateNamespaceArgs(args.Namespaces) } @@ -132,20 +114,3 @@ func validatePodRestartThreshold(podRestartThreshold int32) error { } 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 -} diff --git a/pkg/apis/componentconfig/validation/validation_pluginargs_test.go b/pkg/apis/componentconfig/validation/validation_pluginargs_test.go index c0ca2ce02..0bff98dec 100644 --- a/pkg/apis/componentconfig/validation/validation_pluginargs_test.go +++ b/pkg/apis/componentconfig/validation/validation_pluginargs_test.go @@ -19,7 +19,6 @@ package validation import ( "testing" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/descheduler/pkg/api" "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") - } - }) - } -} diff --git a/pkg/apis/componentconfig/zz_generated.deepcopy.go b/pkg/apis/componentconfig/zz_generated.deepcopy.go index 635b98081..458191d47 100644 --- a/pkg/apis/componentconfig/zz_generated.deepcopy.go +++ b/pkg/apis/componentconfig/zz_generated.deepcopy.go @@ -54,51 +54,6 @@ func (in *DeschedulerConfiguration) DeepCopyObject() runtime.Object { 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. func (in *RemoveDuplicatesArgs) DeepCopyInto(out *RemoveDuplicatesArgs) { *out = *in diff --git a/pkg/descheduler/strategy_migration.go b/pkg/descheduler/strategy_migration.go index ae08e46f5..b79e42a01 100644 --- a/pkg/descheduler/strategy_migration.go +++ b/pkg/descheduler/strategy_migration.go @@ -167,13 +167,13 @@ var pluginsMap = map[string]func(ctx context.Context, nodes []*v1.Node, params * states = append(states, podLifeTimeParams.States...) } - args := &componentconfig.PodLifeTimeArgs{ + args := &podlifetime.PodLifeTimeArgs{ Namespaces: params.Namespaces, LabelSelector: params.LabelSelector, MaxPodLifeTimeSeconds: podLifeTimeParams.MaxPodLifeTimeSeconds, 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) return } diff --git a/pkg/framework/plugins/podlifetime/pod_lifetime.go b/pkg/framework/plugins/podlifetime/pod_lifetime.go index 894b09da8..3c1e13ee5 100644 --- a/pkg/framework/plugins/podlifetime/pod_lifetime.go +++ b/pkg/framework/plugins/podlifetime/pod_lifetime.go @@ -25,7 +25,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/klog/v2" - "sigs.k8s.io/descheduler/pkg/apis/componentconfig" "sigs.k8s.io/descheduler/pkg/framework" "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 type PodLifeTime struct { handle framework.Handle - args *componentconfig.PodLifeTimeArgs + args *PodLifeTimeArgs podFilter podutil.FilterFunc } // New builds plugin from its arguments while passing a handle func New(args runtime.Object, handle framework.Handle) (framework.Plugin, error) { - podLifeTimeArgs, ok := args.(*componentconfig.PodLifeTimeArgs) + podLifeTimeArgs, ok := args.(*PodLifeTimeArgs) if !ok { return nil, fmt.Errorf("want args to be of type PodLifeTimeArgs, got %T", args) } diff --git a/pkg/framework/plugins/podlifetime/pod_lifetime_test.go b/pkg/framework/plugins/podlifetime/pod_lifetime_test.go index 63e05549f..9f73f0531 100644 --- a/pkg/framework/plugins/podlifetime/pod_lifetime_test.go +++ b/pkg/framework/plugins/podlifetime/pod_lifetime_test.go @@ -28,7 +28,6 @@ import ( "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/events" - "sigs.k8s.io/descheduler/pkg/apis/componentconfig" "sigs.k8s.io/descheduler/pkg/descheduler/evictions" podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod" "sigs.k8s.io/descheduler/pkg/framework" @@ -143,7 +142,7 @@ func TestPodLifeTime(t *testing.T) { var maxLifeTime uint = 600 testCases := []struct { description string - args *componentconfig.PodLifeTimeArgs + args *PodLifeTimeArgs pods []*v1.Pod nodes []*v1.Node 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.", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, 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.", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, 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.", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, 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.", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, 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.", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, States: []string{"ContainerCreating"}, }, @@ -212,7 +211,7 @@ func TestPodLifeTime(t *testing.T) { }, { description: "Two pods, one with PodInitializing state. 1 should be evicted.", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, States: []string{"PodInitializing"}, }, @@ -235,7 +234,7 @@ func TestPodLifeTime(t *testing.T) { }, { description: "Two old pods with different states. 1 should be evicted.", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, States: []string{"Pending"}, }, @@ -245,7 +244,7 @@ func TestPodLifeTime(t *testing.T) { }, { description: "does not evict pvc pods with ignorePvcPods set to true", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, pods: []*v1.Pod{p11}, @@ -255,7 +254,7 @@ func TestPodLifeTime(t *testing.T) { }, { description: "evicts pvc pods with ignorePvcPods set to false (or unset)", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, pods: []*v1.Pod{p11}, @@ -264,7 +263,7 @@ func TestPodLifeTime(t *testing.T) { }, { description: "No pod to evicted since all pod terminating", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, LabelSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"foo": "bar"}, @@ -276,7 +275,7 @@ func TestPodLifeTime(t *testing.T) { }, { description: "No pod should be evicted since pod terminating", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, LabelSelector: &metav1.LabelSelector{ 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", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, 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", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, 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", - args: &componentconfig.PodLifeTimeArgs{ + args: &PodLifeTimeArgs{ MaxPodLifeTimeSeconds: &maxLifeTime, }, pods: []*v1.Pod{p1, p2, p9}, diff --git a/pkg/framework/plugins/podlifetime/types.go b/pkg/framework/plugins/podlifetime/types.go new file mode 100644 index 000000000..c95d0ea3d --- /dev/null +++ b/pkg/framework/plugins/podlifetime/types.go @@ -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 +} diff --git a/pkg/framework/plugins/podlifetime/validation.go b/pkg/framework/plugins/podlifetime/validation.go new file mode 100644 index 000000000..4ef151764 --- /dev/null +++ b/pkg/framework/plugins/podlifetime/validation.go @@ -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 +} diff --git a/pkg/framework/plugins/podlifetime/validation_test.go b/pkg/framework/plugins/podlifetime/validation_test.go new file mode 100644 index 000000000..4c5b097d1 --- /dev/null +++ b/pkg/framework/plugins/podlifetime/validation_test.go @@ -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") + } + }) + } +} diff --git a/pkg/framework/plugins/podlifetime/zz_generated.deepcopy.go b/pkg/framework/plugins/podlifetime/zz_generated.deepcopy.go new file mode 100644 index 000000000..277c92ba9 --- /dev/null +++ b/pkg/framework/plugins/podlifetime/zz_generated.deepcopy.go @@ -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 +}