Change:
Some Pods in Kubernetes scheduler's internal cache don't have condition in their status. We store scheduled pods information into cache as assumedPod before binding Pod. And, just after binding Pod, we receive event for scheduled Pods from eventhandler and will be used to add Pod to cache. But, as described above, we've store scheduled pods information. So, basically, scheduler doesn't update pod in cache here: But, event contains changes not only of but also of . So, we should update cache to keep up-to-date when we receive event for scheduled Pods from eventhandler. Otherwise, won't updated until new changes for that Pod are made. Kubernetes scheduler's internal cache always keeps Pod's up-to-date. some Node. a Pod. is scheduled by scheduler. in Pods in Kubernetes scheduler's internal cache (by adding debug log or cache) I think kubelet will update Pods status after they run containers, so you need to do (4) before kubelet does so. (Or doesn't use kubelet like e2e tests) /assign Let me double-check this. (The above explanation includes my expectations, so may not be entirely correct.) v1.23.4 But, I guess this bug exists on latest master as well. <details</details<details</details<details</details<details</details<details</details
This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the label and provide further guidance. The label can be by org members by writing in a comment. <detailsInstructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/sig scheduling
The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules: After 90d of inactivity, is applied After 30d of inactivity since was applied, is applied After 30d of inactivity since was applied, the issue is closed You can: Mark this issue or PR as fresh with Mark this issue or PR as rotten with Close this issue or PR with Offer to help out with [Issue Triage][1] Please send feedback to sig-contributor-experience at . /lifecycle stale [1]:
/remove-lifecycle stale
Does this lead to unschedulable pods or is this just for debugging purposes?
We uses condition in a custom plugin. Mostly No in the real cluster. Only for a very short time (from the scheduler schedules a Pod to kubelet next updates a pod) our plugin does not behave as expected and may make some pods unschedulable. But, when it comes to e2e testing, this bug can be troublesome. In our e2e testing, we don't run kubelet, and no one updates Pods after the scheduler scheduled them Then, all scheduled Pods in the scheduler cache have non-updated condition and it results in unexpected results from our plugin.

Discussion:
currState, ok := cache.podStates[key] switch { case ok && cache.assumedPods.Has(key): <ins> // When assuming, we've already added the Pod to cache, // Just update here to make sure the Pod's status is up-to-date. if err = cache.updatePod(currState.pod, pod); err != nil { klog.ErrorS(err, "Error occurred while updating pod") } </ins> if currState.pod.Spec.NodeName != pod.Spec.NodeName { // The pod was added to a different node than it was assumed to. klog.InfoS("Pod was added to a different node than it was assumed", "podKey", key, "pod", klog.KObj(pod), "assumedNode", klog.KRef("", pod.Spec.NodeName), "currentNode", klog.KRef("", currState.pod.Spec.NodeName)) <del> if err = cache.updatePod(currState.pod, pod); err != nil { klog.ErrorS(err, "Error occurred while updating pod") } } else { delete(cache.assumedPods, key) cache.podStates[key].deadline = nil cache.podStates[key].pod = pod </del> <ins> return nil </ins> } case !ok: // Pod was expired. We should add it back.

} } <ins> // TestAddPodAlwaysUpdatePodInfoInNodeInfo tests that AddPod method always updates PodInfo in NodeInfo, // even when the Pod is assumed one. func TestAddPodAlwaysUpdatesPodInfoInNodeInfo(t *testing.T) { ttl := 10 * time.Second now := time.Now() p1 := makeBasePod(t, "node1", "test-1", "100m", "500", "", []v1.ContainerPort{{HostPort: 80}}) p2 := p1.DeepCopy() p2.Status.Conditions = append(p1.Status.Conditions, v1.PodCondition{ Type:   v1.PodScheduled, Status: v1.ConditionTrue, }) tests := []struct { podsToAssume         []*v1.Pod podsToAddAfterAssume []*v1.Pod nodeInfo             map[string]*framework.NodeInfo }{ { podsToAssume:         []*v1.Pod{p1}, podsToAddAfterAssume: []*v1.Pod{p2}, nodeInfo: map[string]*framework.NodeInfo{ "node1": newNodeInfo( &framework.Resource{ MilliCPU: 100, Memory:   500, }, &framework.Resource{ MilliCPU: 100, Memory:   500, }, []*v1.Pod{p2}, newHostPortInfoBuilder().add("TCP", "0.0.0.0", 80).build(), make(map[string]*framework.ImageStateSummary), ), }, }, } for i, tt := range tests { t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) { cache := newCache(ttl, time.Second, nil) for _, podToAssume := range tt.podsToAssume { if err := assumeAndFinishBinding(cache, podToAssume, now); err != nil { t.Fatalf("assumePod failed: %v", err) } } for _, podToAdd := range tt.podsToAddAfterAssume { if err := cache.AddPod(podToAdd); err != nil { t.Fatalf("AddPod failed: %v", err) } } for nodeName, expected := range tt.nodeInfo { n := cache.nodes[nodeName] if err := deepEqualWithoutGeneration(n, expected); err != nil { t.Errorf("node %q: %v", nodeName, err) } } }) } } </ins> // TestAddPodWillReplaceAssumed tests that a pod being Add()ed will replace any assumed pod. func TestAddPodWillReplaceAssumed(t *testing.T) { now := time.Now()