diff --git a/pkg/apis/componentconfig/types.go b/pkg/apis/componentconfig/types.go index b837178650..c2fbffde09 100644 --- a/pkg/apis/componentconfig/types.go +++ b/pkg/apis/componentconfig/types.go @@ -57,6 +57,9 @@ type DeschedulerConfiguration struct { // IgnorePVCPods sets whether PVC pods should be allowed to be evicted IgnorePVCPods bool + // IgnorePodsWithResourceClaims sets whether pods using resource claims should be allowed to be evicted + IgnorePodsWithResourceClaims bool + // Tracing specifies the options for tracing. Tracing TracingConfiguration diff --git a/pkg/apis/componentconfig/v1alpha1/types.go b/pkg/apis/componentconfig/v1alpha1/types.go index 26a66e7779..dce80ecf5f 100644 --- a/pkg/apis/componentconfig/v1alpha1/types.go +++ b/pkg/apis/componentconfig/v1alpha1/types.go @@ -57,6 +57,9 @@ type DeschedulerConfiguration struct { // IgnorePVCPods sets whether PVC pods should be allowed to be evicted IgnorePVCPods bool `json:"ignorePvcPods,omitempty"` + // IgnorePodsWithResourceClaims sets whether pods using resource claims should be allowed to be evicted + IgnorePodsWithResourceClaims bool `json:"ignorePodsWithResourceClaims"` + // Tracing is used to setup the required OTEL tracing configuration Tracing TracingConfiguration `json:"tracing,omitempty"` diff --git a/pkg/apis/componentconfig/v1alpha1/zz_generated.conversion.go b/pkg/apis/componentconfig/v1alpha1/zz_generated.conversion.go index bf5ab44220..cb52946f35 100644 --- a/pkg/apis/componentconfig/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/componentconfig/v1alpha1/zz_generated.conversion.go @@ -69,6 +69,7 @@ func autoConvert_v1alpha1_DeschedulerConfiguration_To_componentconfig_Deschedule out.EvictLocalStoragePods = in.EvictLocalStoragePods out.EvictDaemonSetPods = in.EvictDaemonSetPods out.IgnorePVCPods = in.IgnorePVCPods + out.IgnorePodsWithResourceClaims = in.IgnorePodsWithResourceClaims if err := Convert_v1alpha1_TracingConfiguration_To_componentconfig_TracingConfiguration(&in.Tracing, &out.Tracing, s); err != nil { return err } @@ -92,6 +93,7 @@ func autoConvert_componentconfig_DeschedulerConfiguration_To_v1alpha1_Deschedule out.EvictLocalStoragePods = in.EvictLocalStoragePods out.EvictDaemonSetPods = in.EvictDaemonSetPods out.IgnorePVCPods = in.IgnorePVCPods + out.IgnorePodsWithResourceClaims = in.IgnorePodsWithResourceClaims if err := Convert_componentconfig_TracingConfiguration_To_v1alpha1_TracingConfiguration(&in.Tracing, &out.Tracing, s); err != nil { return err } diff --git a/pkg/descheduler/policyconfig.go b/pkg/descheduler/policyconfig.go index 393b66d24f..a17ce97f06 100644 --- a/pkg/descheduler/policyconfig.go +++ b/pkg/descheduler/policyconfig.go @@ -101,11 +101,12 @@ func setDefaultEvictor(profile api.DeschedulerProfile, client clientset.Interfac newPluginConfig := api.PluginConfig{ Name: defaultevictor.PluginName, Args: &defaultevictor.DefaultEvictorArgs{ - EvictLocalStoragePods: false, - EvictSystemCriticalPods: false, - IgnorePvcPods: false, - EvictFailedBarePods: false, - IgnorePodsWithoutPDB: false, + EvictLocalStoragePods: false, + EvictSystemCriticalPods: false, + IgnorePvcPods: false, + EvictFailedBarePods: false, + IgnorePodsWithoutPDB: false, + IgnorePodsWithResourceClaims: false, }, } diff --git a/pkg/framework/plugins/defaultevictor/defaultevictor.go b/pkg/framework/plugins/defaultevictor/defaultevictor.go index f23bf13a12..0e7e147aee 100644 --- a/pkg/framework/plugins/defaultevictor/defaultevictor.go +++ b/pkg/framework/plugins/defaultevictor/defaultevictor.go @@ -209,6 +209,15 @@ func New(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plug }) } + if defaultEvictorArgs.IgnorePodsWithResourceClaims { + ev.constraints = append(ev.constraints, func(pod *v1.Pod) error { + if utils.IsPodWithResourceClaims(pod) { + return fmt.Errorf("pod has a ResourceClaim and descheduler is configured to ignore ResourceClaim pods") + } + return nil + }) + } + return ev, nil } diff --git a/pkg/framework/plugins/defaultevictor/defaultevictor_test.go b/pkg/framework/plugins/defaultevictor/defaultevictor_test.go index 3656340a1f..363e2e10d4 100644 --- a/pkg/framework/plugins/defaultevictor/defaultevictor_test.go +++ b/pkg/framework/plugins/defaultevictor/defaultevictor_test.go @@ -28,6 +28,7 @@ import ( "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" + "k8s.io/utils/ptr" "sigs.k8s.io/descheduler/pkg/api" podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod" frameworkfake "sigs.k8s.io/descheduler/pkg/framework/fake" @@ -37,20 +38,21 @@ import ( ) type testCase struct { - description string - pods []*v1.Pod - nodes []*v1.Node - pdbs []*policyv1.PodDisruptionBudget - evictFailedBarePods bool - evictLocalStoragePods bool - evictSystemCriticalPods bool - ignorePvcPods bool - priorityThreshold *int32 - nodeFit bool - minReplicas uint - minPodAge *metav1.Duration - result bool - ignorePodsWithoutPDB bool + description string + pods []*v1.Pod + nodes []*v1.Node + pdbs []*policyv1.PodDisruptionBudget + evictFailedBarePods bool + evictLocalStoragePods bool + evictSystemCriticalPods bool + ignorePvcPods bool + priorityThreshold *int32 + nodeFit bool + minReplicas uint + minPodAge *metav1.Duration + result bool + ignorePodsWithoutPDB bool + ignorePodsWithResourceClaims bool } func TestDefaultEvictorPreEvictionFilter(t *testing.T) { @@ -778,8 +780,8 @@ func TestDefaultEvictorFilter(t *testing.T) { pod.Spec.Volumes = []v1.Volume{ { Name: "pvc", VolumeSource: v1.VolumeSource{ - PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: "foo"}, - }, + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: "foo"}, + }, }, } }), @@ -794,14 +796,44 @@ func TestDefaultEvictorFilter(t *testing.T) { pod.Spec.Volumes = []v1.Volume{ { Name: "pvc", VolumeSource: v1.VolumeSource{ - PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: "foo"}, - }, + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: "foo"}, + }, }, } }), }, ignorePvcPods: false, result: true, + }, { + description: "ignorePodsWithResourceClaims is not set, pod with ResourceClaims, evicts", + pods: []*v1.Pod{ + test.BuildTestPod("p15", 400, 0, n1.Name, func(pod *v1.Pod) { + pod.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList() + pod.Spec.ResourceClaims = []v1.PodResourceClaim{ + { + Name: "test-name", + ResourceClaimName: ptr.To("test-resourceclaim"), + }, + } + }), + }, + ignorePodsWithResourceClaims: false, + result: true, + }, { + description: "ignorePodsWithResourceClaims is set, pod with ResourceClaims, evicts", + pods: []*v1.Pod{ + test.BuildTestPod("p15", 400, 0, n1.Name, func(pod *v1.Pod) { + pod.ObjectMeta.OwnerReferences = test.GetNormalPodOwnerRefList() + pod.Spec.ResourceClaims = []v1.PodResourceClaim{ + { + Name: "test-name", + ResourceClaimName: ptr.To("test-resourceclaim"), + }, + } + }), + }, + ignorePodsWithResourceClaims: true, + result: false, }, } @@ -900,10 +932,11 @@ func initializePlugin(ctx context.Context, test testCase) (frameworktypes.Plugin PriorityThreshold: &api.PriorityThreshold{ Value: test.priorityThreshold, }, - NodeFit: test.nodeFit, - MinReplicas: test.minReplicas, - MinPodAge: test.minPodAge, - IgnorePodsWithoutPDB: test.ignorePodsWithoutPDB, + NodeFit: test.nodeFit, + MinReplicas: test.minReplicas, + MinPodAge: test.minPodAge, + IgnorePodsWithoutPDB: test.ignorePodsWithoutPDB, + IgnorePodsWithResourceClaims: test.ignorePodsWithResourceClaims, } evictorPlugin, err := New( diff --git a/pkg/framework/plugins/defaultevictor/defaults.go b/pkg/framework/plugins/defaultevictor/defaults.go index 463ddd5185..d5405ecc8f 100644 --- a/pkg/framework/plugins/defaultevictor/defaults.go +++ b/pkg/framework/plugins/defaultevictor/defaults.go @@ -52,4 +52,10 @@ func SetDefaults_DefaultEvictorArgs(obj runtime.Object) { if !args.NodeFit { args.NodeFit = false } + if !args.IgnorePodsWithoutPDB { + args.IgnorePodsWithoutPDB = false + } + if !args.IgnorePodsWithResourceClaims { + args.IgnorePodsWithResourceClaims = false + } } diff --git a/pkg/framework/plugins/defaultevictor/defaults_test.go b/pkg/framework/plugins/defaultevictor/defaults_test.go index 2a76e778c9..3293f9e0ef 100644 --- a/pkg/framework/plugins/defaultevictor/defaults_test.go +++ b/pkg/framework/plugins/defaultevictor/defaults_test.go @@ -33,47 +33,50 @@ func TestSetDefaults_DefaultEvictorArgs(t *testing.T) { name: "DefaultEvictorArgs empty", in: &DefaultEvictorArgs{}, want: &DefaultEvictorArgs{ - NodeSelector: "", - EvictLocalStoragePods: false, - EvictDaemonSetPods: false, - EvictSystemCriticalPods: false, - IgnorePvcPods: false, - EvictFailedBarePods: false, - LabelSelector: nil, - PriorityThreshold: nil, - NodeFit: false, - IgnorePodsWithoutPDB: false, + NodeSelector: "", + EvictLocalStoragePods: false, + EvictDaemonSetPods: false, + EvictSystemCriticalPods: false, + IgnorePvcPods: false, + EvictFailedBarePods: false, + LabelSelector: nil, + PriorityThreshold: nil, + NodeFit: false, + IgnorePodsWithoutPDB: false, + IgnorePodsWithResourceClaims: false, }, }, { name: "DefaultEvictorArgs with value", in: &DefaultEvictorArgs{ - NodeSelector: "NodeSelector", - EvictLocalStoragePods: true, - EvictDaemonSetPods: true, - EvictSystemCriticalPods: true, - IgnorePvcPods: true, - EvictFailedBarePods: true, - LabelSelector: nil, + NodeSelector: "NodeSelector", + EvictLocalStoragePods: true, + EvictDaemonSetPods: true, + EvictSystemCriticalPods: true, + IgnorePvcPods: true, + EvictFailedBarePods: true, + LabelSelector: nil, + NodeFit: true, + IgnorePodsWithoutPDB: true, + IgnorePodsWithResourceClaims: true, PriorityThreshold: &api.PriorityThreshold{ Value: utilptr.To[int32](800), }, - NodeFit: true, - IgnorePodsWithoutPDB: true, }, want: &DefaultEvictorArgs{ - NodeSelector: "NodeSelector", - EvictLocalStoragePods: true, - EvictDaemonSetPods: true, - EvictSystemCriticalPods: true, - IgnorePvcPods: true, - EvictFailedBarePods: true, - LabelSelector: nil, + NodeSelector: "NodeSelector", + EvictLocalStoragePods: true, + EvictDaemonSetPods: true, + EvictSystemCriticalPods: true, + IgnorePvcPods: true, + EvictFailedBarePods: true, + LabelSelector: nil, + NodeFit: true, + IgnorePodsWithoutPDB: true, + IgnorePodsWithResourceClaims: true, PriorityThreshold: &api.PriorityThreshold{ Value: utilptr.To[int32](800), }, - NodeFit: true, - IgnorePodsWithoutPDB: true, }, }, } diff --git a/pkg/framework/plugins/defaultevictor/types.go b/pkg/framework/plugins/defaultevictor/types.go index 3a39cbc911..3e3d61c5d5 100644 --- a/pkg/framework/plugins/defaultevictor/types.go +++ b/pkg/framework/plugins/defaultevictor/types.go @@ -25,16 +25,17 @@ import ( type DefaultEvictorArgs struct { metav1.TypeMeta `json:",inline"` - NodeSelector string `json:"nodeSelector,omitempty"` - EvictLocalStoragePods bool `json:"evictLocalStoragePods,omitempty"` - EvictDaemonSetPods bool `json:"evictDaemonSetPods,omitempty"` - EvictSystemCriticalPods bool `json:"evictSystemCriticalPods,omitempty"` - IgnorePvcPods bool `json:"ignorePvcPods,omitempty"` - EvictFailedBarePods bool `json:"evictFailedBarePods,omitempty"` - LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"` - PriorityThreshold *api.PriorityThreshold `json:"priorityThreshold,omitempty"` - NodeFit bool `json:"nodeFit,omitempty"` - MinReplicas uint `json:"minReplicas,omitempty"` - MinPodAge *metav1.Duration `json:"minPodAge,omitempty"` - IgnorePodsWithoutPDB bool `json:"ignorePodsWithoutPDB,omitempty"` + NodeSelector string `json:"nodeSelector,omitempty"` + EvictLocalStoragePods bool `json:"evictLocalStoragePods,omitempty"` + EvictDaemonSetPods bool `json:"evictDaemonSetPods,omitempty"` + EvictSystemCriticalPods bool `json:"evictSystemCriticalPods,omitempty"` + IgnorePvcPods bool `json:"ignorePvcPods,omitempty"` + EvictFailedBarePods bool `json:"evictFailedBarePods,omitempty"` + LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"` + PriorityThreshold *api.PriorityThreshold `json:"priorityThreshold,omitempty"` + NodeFit bool `json:"nodeFit,omitempty"` + MinReplicas uint `json:"minReplicas,omitempty"` + MinPodAge *metav1.Duration `json:"minPodAge,omitempty"` + IgnorePodsWithoutPDB bool `json:"ignorePodsWithoutPDB,omitempty"` + IgnorePodsWithResourceClaims bool `json:"ignorePodsWithResourceClaims,omitempty"` } diff --git a/pkg/utils/pod.go b/pkg/utils/pod.go index 3b015317e4..e3148e65cc 100644 --- a/pkg/utils/pod.go +++ b/pkg/utils/pod.go @@ -120,6 +120,11 @@ func IsPodWithPVC(pod *v1.Pod) bool { return false } +// IsPodWithResourceClaims returns true if the pod has resource claims. +func IsPodWithResourceClaims(pod *v1.Pod) bool { + return len(pod.Spec.ResourceClaims) != 0 +} + // IsPodCoveredByPDB returns true if the pod is covered by at least one PodDisruptionBudget. func IsPodCoveredByPDB(pod *v1.Pod, lister policyv1.PodDisruptionBudgetLister) (bool, error) { // We can't use the GetPodPodDisruptionBudgets expansion method here because it treats no pdb as an error,