Merge remote-tracking branch 'origin/master' into release-1.36

This commit is contained in:
Kubernetes Release Robot
2026-04-15 14:23:55 +00:00
2 changed files with 77 additions and 0 deletions

View File

@@ -1256,6 +1256,10 @@ func (sched *Scheduler) handleSchedulingFailure(ctx context.Context, podFwk fram
logger.Info("Pod has been assigned to node. Abort adding it back to queue.", "pod", klog.KObj(pod), "node", cachedPod.Spec.NodeName)
// We need to call DonePod here because we don't call AddUnschedulableIfNotPresent in this case.
} else {
if cachedPod.UID != podInfo.Pod.UID {
logger.V(2).Info("Pod was recreated while handling scheduling failure. Skip requeueing and status updates.", "pod", klog.KObj(pod), "oldUID", podInfo.Pod.UID, "newUID", cachedPod.UID)
return
}
// As <cachedPod> is from SharedInformer, we need to do a DeepCopy() here.
// ignore this err since apiserver doesn't properly validate affinity terms
// and we can't fix the validation for backwards compatibility.

View File

@@ -1318,6 +1318,79 @@ func TestSchedulerScheduleOne(t *testing.T) {
}
}
func TestHandleSchedulingFailureSkipsRecreatedPod(t *testing.T) {
logger, ctx := ktesting.NewTestContext(t)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
oldPod := st.MakePod().Name("foo").Namespace("ns").UID("old-uid").SchedulerName(testSchedulerName).Obj()
recreatedPod := oldPod.DeepCopy()
recreatedPod.UID = "new-uid"
client := clientsetfake.NewClientset(recreatedPod)
informerFactory := informers.NewSharedInformerFactory(client, 0)
eventBroadcaster := events.NewBroadcaster(&events.EventSinkImpl{Interface: client.EventsV1()})
schedFramework, err := tf.NewFramework(ctx,
[]tf.RegisterPluginFunc{
tf.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
tf.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
},
testSchedulerName,
frameworkruntime.WithClientSet(client),
frameworkruntime.WithEventRecorder(eventBroadcaster.NewRecorder(scheme.Scheme, testSchedulerName)),
frameworkruntime.WithInformerFactory(informerFactory),
)
if err != nil {
t.Fatal(err)
}
ar := metrics.NewMetricsAsyncRecorder(10, time.Second, ctx.Done())
queue := internalqueue.NewSchedulingQueue(nil, informerFactory, internalqueue.WithMetricsRecorder(ar))
sched := &Scheduler{
client: client,
SchedulingQueue: queue,
}
informerFactory.Start(ctx.Done())
informerFactory.WaitForCacheSync(ctx.Done())
queue.Add(ctx, oldPod)
popped, err := queue.Pop(logger)
if err != nil {
t.Fatalf("Pop: %v", err)
}
if got := queue.InFlightPods(); !podListContainsPod(got, oldPod) {
t.Fatalf("expected popped pod to be in-flight before failure handling, got %v", got)
}
nominatingInfo := &fwk.NominatingInfo{NominatingMode: fwk.ModeOverride, NominatedNodeName: "node1"}
sched.handleSchedulingFailure(ctx, schedFramework, popped, fwk.NewStatus(fwk.Unschedulable, "no fit"), nominatingInfo, time.Now())
if err := wait.PollUntilContextTimeout(ctx, time.Millisecond, wait.ForeverTestTimeout, false, func(context.Context) (bool, error) {
return len(queue.InFlightPods()) == 0, nil
}); err != nil {
t.Fatalf("in-flight pod was not cleared: %v", queue.InFlightPods())
}
if got := queue.PodsInBackoffQ(); len(got) != 0 {
t.Fatalf("expected recreated pod to stay out of backoffQ, got %v", got)
}
if got := queue.UnschedulablePods(); len(got) != 0 {
t.Fatalf("expected recreated pod to stay out of unschedulablePods, got %v", got)
}
if got := queue.NominatedPodsForNode("node1"); len(got) != 0 {
t.Fatalf("expected recreated pod to stay out of nominated pods, got %v", got)
}
updatedPod, err := client.CoreV1().Pods(recreatedPod.Namespace).Get(ctx, recreatedPod.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("Get pod: %v", err)
}
if diff := cmp.Diff(recreatedPod.Status, updatedPod.Status); diff != "" {
t.Fatalf("expected recreated pod status to remain unchanged (-want,+got):\n%s", diff)
}
}
type constSigPluginConfig struct {
name string
signature []fwk.SignFragment