Skip to content

Commit 2837c59

Browse files
authored
Merge pull request #7820 from norbertcyran/add-taints-to-original-node
Ensure added taints are present on the node in the snapshot
2 parents 61b5645 + aa479c9 commit 2837c59

File tree

4 files changed

+135
-7
lines changed

4 files changed

+135
-7
lines changed

cluster-autoscaler/core/scaledown/actuation/actuator_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,9 @@ func runStartDeletionTest(t *testing.T, tc startDeletionTestCase, force bool) {
13021302
// Verify ScaleDownNodes looks as expected.
13031303
ignoreSdNodeOrder := cmpopts.SortSlices(func(a, b *status.ScaleDownNode) bool { return a.Node.Name < b.Node.Name })
13041304
cmpNg := cmp.Comparer(func(a, b *testprovider.TestNodeGroup) bool { return a.Id() == b.Id() })
1305-
statusCmpOpts := cmp.Options{ignoreSdNodeOrder, cmpNg, cmpopts.EquateEmpty()}
1305+
// Deletion taint may be lifted by goroutine, ignore taints to avoid race condition
1306+
ignoreTaints := cmpopts.IgnoreFields(apiv1.NodeSpec{}, "Taints")
1307+
statusCmpOpts := cmp.Options{ignoreSdNodeOrder, cmpNg, cmpopts.EquateEmpty(), ignoreTaints}
13061308
if diff := cmp.Diff(wantScaleDownNodes, gotScaleDownNodes, statusCmpOpts); diff != "" {
13071309
t.Errorf("StartDeletion scaled down nodes diff (-want +got):\n%s", diff)
13081310
}

cluster-autoscaler/core/static_autoscaler_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ func TestStaticAutoscalerRunOnce(t *testing.T) {
504504
// Remove unregistered nodes.
505505
readyNodeLister.SetNodes([]*apiv1.Node{n1, n2})
506506
allNodeLister.SetNodes([]*apiv1.Node{n1, n2})
507-
allPodListerMock.On("List").Return([]*apiv1.Pod{p1, p2}, nil).Once()
507+
allPodListerMock.On("List").Return([]*apiv1.Pod{p1}, nil).Once()
508508
daemonSetListerMock.On("List", labels.Everything()).Return([]*appsv1.DaemonSet{}, nil).Once()
509509
onScaleDownMock.On("ScaleDown", "ng2", "n3").Return(nil).Once()
510510
podDisruptionBudgetListerMock.On("List").Return([]*policyv1.PodDisruptionBudget{}, nil).Once()
@@ -536,11 +536,6 @@ func TestStaticAutoscalerRunOnceWithScaleDownDelayPerNG(t *testing.T) {
536536
onScaleDownMock := &onScaleDownMock{}
537537
deleteFinished := make(chan bool, 1)
538538

539-
n1 := BuildTestNode("n1", 1000, 1000)
540-
SetNodeReadyState(n1, true, time.Now())
541-
n2 := BuildTestNode("n2", 1000, 1000)
542-
SetNodeReadyState(n2, true, time.Now())
543-
544539
tn := BuildTestNode("tn", 1000, 1000)
545540
tni := framework.NewTestNodeInfo(tn)
546541

@@ -710,6 +705,11 @@ func TestStaticAutoscalerRunOnceWithScaleDownDelayPerNG(t *testing.T) {
710705

711706
tc.beforeTest(processors)
712707

708+
n1 := BuildTestNode("n1", 1000, 1000)
709+
SetNodeReadyState(n1, true, time.Now())
710+
n2 := BuildTestNode("n2", 1000, 1000)
711+
SetNodeReadyState(n2, true, time.Now())
712+
713713
provider.AddNode("ng1", n1)
714714
provider.AddNode("ng2", n2)
715715
ng1.SetTargetSize(1)

cluster-autoscaler/utils/taints/taints.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ func AddTaints(node *apiv1.Node, client kube_client.Interface, taints []apiv1.Ta
215215
return err
216216
}
217217
klog.V(1).Infof("Successfully added %v on node %v", strings.Join(taintKeys(taints), ","), node.Name)
218+
node.Spec.Taints = append([]apiv1.Taint{}, freshNode.Spec.Taints...)
218219
return nil
219220
}
220221
}
@@ -350,6 +351,7 @@ func CleanTaints(node *apiv1.Node, client kube_client.Interface, taintKeys []str
350351
return false, err
351352
}
352353
klog.V(1).Infof("Successfully released %v on node %v", strings.Join(taintKeys, ","), node.Name)
354+
node.Spec.Taints = append([]apiv1.Taint{}, freshNode.Spec.Taints...)
353355
return true, nil
354356
}
355357
}

cluster-autoscaler/utils/taints/taints_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,3 +723,127 @@ func TestCountNodeTaints(t *testing.T) {
723723
got := CountNodeTaints([]*apiv1.Node{node, node2}, taintConfig)
724724
assert.Equal(t, want, got)
725725
}
726+
727+
func TestAddTaints(t *testing.T) {
728+
testCases := []struct {
729+
name string
730+
existingTaints []string
731+
newTaints []string
732+
wantTaints []string
733+
}{
734+
{
735+
name: "no existing taints",
736+
newTaints: []string{"t1", "t2"},
737+
wantTaints: []string{"t1", "t2"},
738+
},
739+
{
740+
name: "existing taints - no overlap",
741+
existingTaints: []string{"t1"},
742+
newTaints: []string{"t2", "t3"},
743+
wantTaints: []string{"t1", "t2", "t3"},
744+
},
745+
{
746+
name: "existing taints - duplicates",
747+
existingTaints: []string{"t1"},
748+
newTaints: []string{"t1", "t2"},
749+
wantTaints: []string{"t1", "t2"},
750+
},
751+
}
752+
for _, tc := range testCases {
753+
t.Run(tc.name, func(t *testing.T) {
754+
n := BuildTestNode("node", 1000, 1000)
755+
existingTaints := make([]apiv1.Taint, len(tc.existingTaints))
756+
for i, t := range tc.existingTaints {
757+
existingTaints[i] = apiv1.Taint{
758+
Key: t,
759+
Effect: apiv1.TaintEffectNoSchedule,
760+
}
761+
}
762+
n.Spec.Taints = append([]apiv1.Taint{}, existingTaints...)
763+
fakeClient := buildFakeClient(t, n)
764+
newTaints := make([]apiv1.Taint, len(tc.newTaints))
765+
for i, t := range tc.newTaints {
766+
newTaints[i] = apiv1.Taint{
767+
Key: t,
768+
Effect: apiv1.TaintEffectNoSchedule,
769+
}
770+
}
771+
err := AddTaints(n, fakeClient, newTaints, false)
772+
assert.NoError(t, err)
773+
apiNode := getNode(t, fakeClient, "node")
774+
for _, want := range tc.wantTaints {
775+
assert.True(t, HasTaint(n, want))
776+
assert.True(t, HasTaint(apiNode, want))
777+
}
778+
})
779+
}
780+
}
781+
782+
func TestCleanTaints(t *testing.T) {
783+
testCases := []struct {
784+
name string
785+
existingTaints []string
786+
taintsToRemove []string
787+
wantTaints []string
788+
wantModified bool
789+
}{
790+
{
791+
name: "no existing taints",
792+
taintsToRemove: []string{"t1", "t2"},
793+
wantTaints: []string{},
794+
wantModified: false,
795+
},
796+
{
797+
name: "existing taints - no overlap",
798+
existingTaints: []string{"t1"},
799+
taintsToRemove: []string{"t2", "t3"},
800+
wantTaints: []string{"t1"},
801+
wantModified: false,
802+
},
803+
{
804+
name: "existing taints - remove one",
805+
existingTaints: []string{"t1", "t2"},
806+
taintsToRemove: []string{"t1"},
807+
wantTaints: []string{"t2"},
808+
wantModified: true,
809+
},
810+
{
811+
name: "existing taints - remove all",
812+
existingTaints: []string{"t1", "t2"},
813+
taintsToRemove: []string{"t1", "t2"},
814+
wantTaints: []string{},
815+
wantModified: true,
816+
},
817+
}
818+
819+
for _, tc := range testCases {
820+
t.Run(tc.name, func(t *testing.T) {
821+
n := BuildTestNode("node", 1000, 1000)
822+
existingTaints := make([]apiv1.Taint, len(tc.existingTaints))
823+
for i, taintKey := range tc.existingTaints {
824+
existingTaints[i] = apiv1.Taint{
825+
Key: taintKey,
826+
Effect: apiv1.TaintEffectNoSchedule,
827+
}
828+
}
829+
n.Spec.Taints = append([]apiv1.Taint{}, existingTaints...)
830+
fakeClient := buildFakeClient(t, n)
831+
832+
modified, err := CleanTaints(n, fakeClient, tc.taintsToRemove, false)
833+
assert.NoError(t, err)
834+
assert.Equal(t, tc.wantModified, modified)
835+
836+
apiNode := getNode(t, fakeClient, "node")
837+
838+
for _, want := range tc.wantTaints {
839+
assert.True(t, HasTaint(apiNode, want))
840+
assert.True(t, HasTaint(n, want))
841+
}
842+
843+
for _, removed := range tc.taintsToRemove {
844+
assert.False(t, HasTaint(apiNode, removed))
845+
assert.False(t, HasTaint(n, removed), "Taint %s should have been removed from local node object", removed)
846+
}
847+
})
848+
}
849+
}

0 commit comments

Comments
 (0)