Skip to content

Commit 5248bef

Browse files
authored
Merge pull request kubernetes#91750 from Huang-Wei/clear-nnn
Fix an issue that a Pod's nominatedNodeName cannot be cleared upon node deletion
2 parents de1a277 + 369a900 commit 5248bef

File tree

4 files changed

+93
-8
lines changed

4 files changed

+93
-8
lines changed

pkg/scheduler/scheduler.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -375,13 +375,10 @@ func updatePod(client clientset.Interface, pod *v1.Pod, condition *v1.PodConditi
375375
podCopy := pod.DeepCopy()
376376
// NominatedNodeName is updated only if we are trying to set it, and the value is
377377
// different from the existing one.
378-
if !podutil.UpdatePodCondition(&podCopy.Status, condition) &&
379-
(len(nominatedNode) == 0 || pod.Status.NominatedNodeName == nominatedNode) {
378+
if !podutil.UpdatePodCondition(&podCopy.Status, condition) && pod.Status.NominatedNodeName == nominatedNode {
380379
return nil
381380
}
382-
if nominatedNode != "" {
383-
podCopy.Status.NominatedNodeName = nominatedNode
384-
}
381+
podCopy.Status.NominatedNodeName = nominatedNode
385382
return patchPod(client, pod, podCopy)
386383
}
387384

pkg/scheduler/scheduler_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ func TestUpdatePod(t *testing.T) {
13341334
expectedPatchDataPattern: `{"status":{"\$setElementOrder/conditions":\[{"type":"currentType"}],"conditions":\[{"lastProbeTime":"2020-05-13T01:01:01Z","message":"newMessage","reason":"newReason","type":"currentType"}]}}`,
13351335
},
13361336
{
1337-
name: "Should not make patch request if pod condition already exists and is identical and nominated node name is not set",
1337+
name: "Should make patch request if pod condition already exists and is identical but nominated node name is different",
13381338
currentPodConditions: []v1.PodCondition{
13391339
{
13401340
Type: "currentType",
@@ -1354,7 +1354,7 @@ func TestUpdatePod(t *testing.T) {
13541354
Message: "currentMessage",
13551355
},
13561356
currentNominatedNodeName: "node1",
1357-
expectedPatchRequests: 0,
1357+
expectedPatchRequests: 1,
13581358
},
13591359
{
13601360
name: "Should make patch request if pod condition already exists and is identical but nominated node name is set and different",

test/integration/scheduler/preemption_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
v1 "k8s.io/api/core/v1"
2828
policy "k8s.io/api/policy/v1beta1"
29+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2930
"k8s.io/apimachinery/pkg/api/resource"
3031
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3132
"k8s.io/apimachinery/pkg/runtime"
@@ -1023,6 +1024,93 @@ func TestNominatedNodeCleanUp(t *testing.T) {
10231024
}
10241025
}
10251026

1027+
func TestNominatedNodeCleanUpUponNodeDeletion(t *testing.T) {
1028+
// Initialize scheduler.
1029+
testCtx := initTest(t, "preemption")
1030+
defer testutils.CleanupTest(t, testCtx)
1031+
1032+
cs := testCtx.ClientSet
1033+
defer cleanupPodsInNamespace(cs, t, testCtx.NS.Name)
1034+
1035+
// Create a node with some resources and a label.
1036+
nodeRes := &v1.ResourceList{
1037+
v1.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI),
1038+
v1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
1039+
v1.ResourceMemory: *resource.NewQuantity(100, resource.DecimalSI),
1040+
}
1041+
nodeNames := []string{"node1", "node2"}
1042+
for _, nodeName := range nodeNames {
1043+
_, err := createNode(testCtx.ClientSet, nodeName, nodeRes)
1044+
if err != nil {
1045+
t.Fatalf("Error creating nodes: %v", err)
1046+
}
1047+
}
1048+
1049+
// Fill the cluster with one high-priority and one low-priority Pod.
1050+
highPriPod, err := createPausePod(cs, mkPriorityPodWithGrace(testCtx, "high-pod", highPriority, 60))
1051+
if err != nil {
1052+
t.Fatalf("Error creating high-priority pod: %v", err)
1053+
}
1054+
// Make sure the pod is scheduled.
1055+
if err := testutils.WaitForPodToSchedule(cs, highPriPod); err != nil {
1056+
t.Fatalf("Pod %v/%v didn't get scheduled: %v", highPriPod.Namespace, highPriPod.Name, err)
1057+
}
1058+
1059+
lowPriPod, err := createPausePod(cs, mkPriorityPodWithGrace(testCtx, "low-pod", lowPriority, 60))
1060+
if err != nil {
1061+
t.Fatalf("Error creating low-priority pod: %v", err)
1062+
}
1063+
// Make sure the pod is scheduled.
1064+
if err := testutils.WaitForPodToSchedule(cs, lowPriPod); err != nil {
1065+
t.Fatalf("Pod %v/%v didn't get scheduled: %v", lowPriPod.Namespace, lowPriPod.Name, err)
1066+
}
1067+
1068+
// Create a medium-priority Pod.
1069+
medPriPod, err := createPausePod(cs, mkPriorityPodWithGrace(testCtx, "med-pod", mediumPriority, 60))
1070+
if err != nil {
1071+
t.Fatalf("Error creating med-priority pod: %v", err)
1072+
}
1073+
// Check its nominatedNodeName field is set properly.
1074+
if err := waitForNominatedNodeName(cs, medPriPod); err != nil {
1075+
t.Fatalf("NominatedNodeName was not set for pod %v/%v: %v", medPriPod.Namespace, medPriPod.Name, err)
1076+
}
1077+
1078+
// Get the live version of low and med pods.
1079+
lowPriPod, _ = getPod(cs, lowPriPod.Name, lowPriPod.Namespace)
1080+
medPriPod, _ = getPod(cs, medPriPod.Name, medPriPod.Namespace)
1081+
1082+
want, got := lowPriPod.Spec.NodeName, medPriPod.Status.NominatedNodeName
1083+
if want != got {
1084+
t.Fatalf("Expect med-priority's nominatedNodeName to be %v, but got %v.", want, got)
1085+
}
1086+
1087+
// Delete the node where med-priority pod is nominated to.
1088+
cs.CoreV1().Nodes().Delete(context.TODO(), got, metav1.DeleteOptions{})
1089+
if err := wait.Poll(200*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
1090+
_, err := cs.CoreV1().Nodes().Get(context.TODO(), got, metav1.GetOptions{})
1091+
if apierrors.IsNotFound(err) {
1092+
return true, nil
1093+
}
1094+
return false, err
1095+
}); err != nil {
1096+
t.Fatalf("Node %v cannot be deleted: %v.", got, err)
1097+
}
1098+
1099+
// Finally verify if med-priority pod's nominatedNodeName gets cleared.
1100+
if err := wait.Poll(200*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
1101+
pod, err := cs.CoreV1().Pods(medPriPod.Namespace).Get(context.TODO(), medPriPod.Name, metav1.GetOptions{})
1102+
if err != nil {
1103+
t.Errorf("Error getting the medium priority pod info: %v", err)
1104+
}
1105+
if len(pod.Status.NominatedNodeName) == 0 {
1106+
return true, nil
1107+
}
1108+
return false, err
1109+
}); err != nil {
1110+
t.Errorf("The nominated node name of the medium priority pod was not cleared: %v", err)
1111+
}
1112+
}
1113+
10261114
func mkMinAvailablePDB(name, namespace string, uid types.UID, minAvailable int, matchLabels map[string]string) *policy.PodDisruptionBudget {
10271115
intMinAvailable := intstr.FromInt(minAvailable)
10281116
return &policy.PodDisruptionBudget{

test/integration/scheduler/util.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ func noPodsInNamespace(c clientset.Interface, podNamespace string) wait.Conditio
483483
// cleanupPodsInNamespace deletes the pods in the given namespace and waits for them to
484484
// be actually deleted.
485485
func cleanupPodsInNamespace(cs clientset.Interface, t *testing.T, ns string) {
486-
if err := cs.CoreV1().Pods(ns).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{}); err != nil {
486+
if err := cs.CoreV1().Pods(ns).DeleteCollection(context.TODO(), *metav1.NewDeleteOptions(0), metav1.ListOptions{}); err != nil {
487487
t.Errorf("error while listing pod in namespace %v: %v", ns, err)
488488
return
489489
}

0 commit comments

Comments
 (0)