diff --git a/pkg/controller/daemon/daemon_controller.go b/pkg/controller/daemon/daemon_controller.go index e70fa087d3..9963428bf8 100644 --- a/pkg/controller/daemon/daemon_controller.go +++ b/pkg/controller/daemon/daemon_controller.go @@ -964,10 +964,10 @@ func (dsc *DaemonSetsController) manage(ds *apps.DaemonSet, hash string) error { failedPodsObserved += failedPodsObservedOnNode } - // Remove pods assigned to not existing nodes when daemonset pods are scheduled by default scheduler. + // Remove unscheduled pods assigned to not existing nodes when daemonset pods are scheduled by scheduler. // If node doesn't exist then pods are never scheduled and can't be deleted by PodGCController. if utilfeature.DefaultFeatureGate.Enabled(features.ScheduleDaemonSetPods) { - podsToDelete = append(podsToDelete, getPodsWithoutNode(nodeList, nodeToDaemonPods)...) + podsToDelete = append(podsToDelete, getUnscheduledPodsWithoutNode(nodeList, nodeToDaemonPods)...) } // Label new pods using the hash label value of the current history when creating them @@ -1531,8 +1531,9 @@ func failedPodsBackoffKey(ds *apps.DaemonSet, nodeName string) string { return fmt.Sprintf("%s/%d/%s", ds.UID, ds.Status.ObservedGeneration, nodeName) } -// getPodsWithoutNode returns list of pods assigned to not existing nodes. -func getPodsWithoutNode(runningNodesList []*v1.Node, nodeToDaemonPods map[string][]*v1.Pod) []string { +// getUnscheduledPodsWithoutNode returns list of unscheduled pods assigned to not existing nodes. +// Returned pods can't be deleted by PodGCController so they should be deleted by DaemonSetController. +func getUnscheduledPodsWithoutNode(runningNodesList []*v1.Node, nodeToDaemonPods map[string][]*v1.Pod) []string { var results []string isNodeRunning := make(map[string]bool) for _, node := range runningNodesList { @@ -1541,7 +1542,9 @@ func getPodsWithoutNode(runningNodesList []*v1.Node, nodeToDaemonPods map[string for n, pods := range nodeToDaemonPods { if !isNodeRunning[n] { for _, pod := range pods { - results = append(results, pod.Name) + if len(pod.Spec.NodeName) == 0 { + results = append(results, pod.Name) + } } } } diff --git a/pkg/controller/daemon/daemon_controller_test.go b/pkg/controller/daemon/daemon_controller_test.go index 8eee1b161c..61ff0d1b65 100644 --- a/pkg/controller/daemon/daemon_controller_test.go +++ b/pkg/controller/daemon/daemon_controller_test.go @@ -2447,7 +2447,7 @@ func TestDeleteNoDaemonPod(t *testing.T) { } } -func TestDeletePodForNotExistingNode(t *testing.T) { +func TestDeleteUnscheduledPodForNotExistingNode(t *testing.T) { for _, f := range []bool{true, false} { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ScheduleDaemonSetPods, f)() for _, strategy := range updateStrategies() { @@ -2461,6 +2461,26 @@ func TestDeletePodForNotExistingNode(t *testing.T) { addNodes(manager.nodeStore, 0, 1, nil) addPods(manager.podStore, "node-0", simpleDaemonSetLabel, ds, 1) addPods(manager.podStore, "node-1", simpleDaemonSetLabel, ds, 1) + + podScheduledUsingAffinity := newPod("pod1-node-3", "", simpleDaemonSetLabel, ds) + podScheduledUsingAffinity.Spec.Affinity = &v1.Affinity{ + NodeAffinity: &v1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ + NodeSelectorTerms: []v1.NodeSelectorTerm{ + { + MatchFields: []v1.NodeSelectorRequirement{ + { + Key: schedulerapi.NodeFieldSelectorKeyNodeName, + Operator: v1.NodeSelectorOpIn, + Values: []string{"node-2"}, + }, + }, + }, + }, + }, + }, + } + manager.podStore.Add(podScheduledUsingAffinity) if f { syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 1, 0) } else {