Fix queue hint for interpodaffinity when target pod is updated

This commit is contained in:
Bartosz
2025-11-21 14:51:49 +00:00
parent c180d6762d
commit 145adcd522
2 changed files with 49 additions and 34 deletions

View File

@@ -173,6 +173,14 @@ func (pl *InterPodAffinity) isSchedulableAfterPodChange(logger klog.Logger, pod
if err != nil {
return fwk.Queue, err
}
if modifiedPod != nil && originalPod != nil && pod.UID == modifiedPod.UID {
// The only update event we listen on is UpdatePodLabel, so we can assume the labels have changed.
// The pod can become schedulable after update to its labels because e.g. some other pod might have
// anti-affinity on the old labels but not on the new ones.
logger.V(5).Info("the target pod labels have changed and it may be schedulable now",
"pod", klog.KObj(pod))
return fwk.Queue, nil
}
if (modifiedPod != nil && modifiedPod.Spec.NodeName == "") || (originalPod != nil && originalPod.Spec.NodeName == "") {
logger.V(5).Info("the added/updated/deleted pod is unscheduled, so it doesn't make the target pod schedulable",
"pod", klog.KObj(pod), "originalPod", klog.KObj(originalPod), "modifiedPod", klog.KObj(modifiedPod))

View File

@@ -43,90 +43,97 @@ func Test_isSchedulableAfterPodChange(t *testing.T) {
}{
{
name: "add a pod which matches the pod affinity",
pod: st.MakePod().Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("service", "securityscan").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("service", "securityscan").Obj(),
expectedHint: fwk.Queue,
},
{
name: "add an un-scheduled pod",
pod: st.MakePod().Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Label("service", "securityscan").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Label("service", "securityscan").Obj(),
expectedHint: fwk.QueueSkip,
},
{
name: "add a pod which doesn't match the pod affinity",
pod: st.MakePod().Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("aaa", "a").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("aaa", "a").Obj(),
expectedHint: fwk.QueueSkip,
},
{
name: "update a pod from non-match to match pod affinity",
pod: st.MakePod().Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().Node("fake-node").Label("aaa", "a").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("aaa", "a").Obj(),
expectedHint: fwk.Queue,
},
{
name: "the updating pod matches target pod's affinity both before and after label changes",
pod: st.MakePod().Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().Node("fake-node").Label("service", "value2").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("service", "value2").Obj(),
expectedHint: fwk.QueueSkip,
},
{
name: "update an un-scheduled pod",
pod: st.MakePod().Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Label("service", "securityscan").Obj(),
oldPod: st.MakePod().Label("service", "securityscan").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().UID("other").Label("aaa", "a").Obj(),
expectedHint: fwk.QueueSkip,
},
{
name: "update a pod from match to non-match the pod affinity",
pod: st.MakePod().Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("aaa", "a").Obj(),
oldPod: st.MakePod().Node("fake-node").Label("service", "securityscan").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("aaa", "a").Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("service", "securityscan").Obj(),
expectedHint: fwk.QueueSkip,
},
{
name: "update a pod from match to non-match pod's affinity - multiple terms case",
pod: st.MakePod().Name("p").PodAffinityExists("aaa", "hostname", st.PodAffinityWithRequiredReq).
pod: st.MakePod().UID("p").Name("p").PodAffinityExists("aaa", "hostname", st.PodAffinityWithRequiredReq).
PodAffinityExists("bbb", "hostname", st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().Node("fake-node").Label("aaa", "a").Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("aaa", "a").Obj(),
expectedHint: fwk.QueueSkip,
},
{
name: "update a pod from non-match to match pod's affinity - multiple terms case",
pod: st.MakePod().Name("p").PodAffinityExists("aaa", "hostname", st.PodAffinityWithRequiredReq).
pod: st.MakePod().UID("p").Name("p").PodAffinityExists("aaa", "hostname", st.PodAffinityWithRequiredReq).
PodAffinityExists("bbb", "hostname", st.PodAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("aaa", "").Label("bbb", "").Obj(),
oldPod: st.MakePod().Node("fake-node").Label("aaa", "a").Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("aaa", "").Label("bbb", "").Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("aaa", "a").Obj(),
expectedHint: fwk.Queue,
},
{
name: "updated pod is the target pod",
pod: st.MakePod().UID("p").Name("p").Label("foo", "baz").Obj(),
newPod: st.MakePod().UID("p").Name("p").Label("foo", "baz").Obj(),
oldPod: st.MakePod().UID("p").Name("p").Label("foo", "bar").Obj(),
expectedHint: fwk.Queue,
},
{
name: "modify pod label to change it from satisfying pod anti-affinity to not satisfying anti-affinity",
pod: st.MakePod().Name("p").PodAntiAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAntiAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("service", "aaaa").Obj(),
oldPod: st.MakePod().Node("fake-node").Label("service", "securityscan").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAntiAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAntiAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("service", "aaaa").Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("service", "securityscan").Obj(),
expectedHint: fwk.Queue,
},
{
name: "modify pod label to change it from not satisfying pod anti-affinity to satisfying anti-affinity",
pod: st.MakePod().Name("p").PodAntiAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAntiAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().Node("fake-node").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().Node("fake-node").Label("service", "bbb").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAntiAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAntiAffinityWithRequiredReq).Obj(),
newPod: st.MakePod().UID("other").Node("fake-node").Label("service", "securityscan").Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("service", "bbb").Obj(),
expectedHint: fwk.QueueSkip,
},
{
name: "delete a pod which doesn't match pod's anti-affinity",
pod: st.MakePod().Name("p").PodAntiAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAntiAffinityWithRequiredReq).Obj(),
oldPod: st.MakePod().Node("fake-node").Label("aaa", "a").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAntiAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAntiAffinityWithRequiredReq).Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("aaa", "a").Obj(),
expectedHint: fwk.QueueSkip,
},
{
name: "delete a pod which matches pod's anti-affinity",
pod: st.MakePod().Name("p").PodAntiAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAntiAffinityWithRequiredReq).Obj(),
oldPod: st.MakePod().Node("fake-node").Label("service", "securityscan").Obj(),
pod: st.MakePod().UID("p").Name("p").PodAntiAffinityIn("service", "region", []string{"securityscan", "value2"}, st.PodAntiAffinityWithRequiredReq).Obj(),
oldPod: st.MakePod().UID("other").Node("fake-node").Label("service", "securityscan").Obj(),
expectedHint: fwk.Queue,
},
}