@@ -26,10 +26,13 @@ import (
2626 . "github.com/onsi/gomega"
2727 corev1 "k8s.io/api/core/v1"
2828 "k8s.io/utils/ptr"
29+ "sigs.k8s.io/controller-runtime/pkg/client"
2930
31+ clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
3032 "sigs.k8s.io/cluster-api/test/framework"
3133 "sigs.k8s.io/cluster-api/test/framework/clusterctl"
3234 "sigs.k8s.io/cluster-api/util"
35+ "sigs.k8s.io/cluster-api/util/patch"
3336)
3437
3538// MachineDeploymentRolloutSpecInput is the input for MachineDeploymentRolloutSpec.
@@ -135,6 +138,138 @@ func MachineDeploymentRolloutSpec(ctx context.Context, inputGetter func() Machin
135138 Namespace : clusterResources .Cluster .Namespace ,
136139 })
137140
141+ preExistingAlwaysTaint := clusterv1.MachineTaint {
142+ Key : "pre-existing-always-taint" ,
143+ Value : ptr .To ("always-value" ),
144+ Effect : corev1 .TaintEffectPreferNoSchedule ,
145+ Propagation : clusterv1 .TaintPropagationAlways ,
146+ }
147+
148+ preExistingOnInitializationTaint := clusterv1.MachineTaint {
149+ Key : "pre-existing-on-initialization-taint" ,
150+ Value : ptr .To ("on-initialization-value" ),
151+ Effect : corev1 .TaintEffectPreferNoSchedule ,
152+ Propagation : clusterv1 .TaintPropagationOnInitialization ,
153+ }
154+ addingAlwaysTaint := clusterv1.MachineTaint {
155+ Key : "added-always-taint" ,
156+ Value : ptr .To ("added-always-value" ),
157+ Effect : corev1 .TaintEffectPreferNoSchedule ,
158+ Propagation : clusterv1 .TaintPropagationAlways ,
159+ }
160+
161+ addingOnInitializationTaint := clusterv1.MachineTaint {
162+ Key : "added-on-initialization-taint" ,
163+ Value : ptr .To ("added-on-initialization-value" ),
164+ Effect : corev1 .TaintEffectPreferNoSchedule ,
165+ Propagation : clusterv1 .TaintPropagationOnInitialization ,
166+ }
167+
168+ wantMachineTaints := []clusterv1.MachineTaint {
169+ preExistingAlwaysTaint ,
170+ preExistingOnInitializationTaint ,
171+ }
172+ wantNodeTaints := toCoreV1Taints (
173+ preExistingAlwaysTaint ,
174+ preExistingOnInitializationTaint ,
175+ )
176+
177+ Byf ("Verify MachineDeployment Machines and Nodes have the correct taints" )
178+ wlClient := input .BootstrapClusterProxy .GetWorkloadCluster (ctx , clusterResources .Cluster .Namespace , clusterResources .Cluster .Name ).GetClient ()
179+ verifyMachineAndNodeTaints (ctx , verifyMachineAndNodeTaintsInput {
180+ BootstrapClusterClient : input .BootstrapClusterProxy .GetClient (),
181+ WorkloadClusterClient : wlClient ,
182+ ClusterName : clusterResources .Cluster .Name ,
183+ MachineDeployments : clusterResources .MachineDeployments ,
184+ MachineTaints : wantMachineTaints ,
185+ NodeTaints : wantNodeTaints ,
186+ })
187+
188+ Byf ("Verify in-place propagation by adding new taints to the MachineDeployment" )
189+ wantMachineTaints = []clusterv1.MachineTaint {
190+ preExistingAlwaysTaint ,
191+ preExistingOnInitializationTaint ,
192+ addingAlwaysTaint ,
193+ addingOnInitializationTaint ,
194+ }
195+ wantNodeTaints = toCoreV1Taints (
196+ preExistingAlwaysTaint ,
197+ preExistingOnInitializationTaint ,
198+ addingAlwaysTaint ,
199+ )
200+ for _ , md := range clusterResources .MachineDeployments {
201+ patchHelper , err := patch .NewHelper (md , input .BootstrapClusterProxy .GetClient ())
202+ Expect (err ).ToNot (HaveOccurred ())
203+ md .Spec .Template .Spec .Taints = wantMachineTaints
204+ Expect (patchHelper .Patch (ctx , md )).To (Succeed ())
205+ }
206+
207+ verifyMachineAndNodeTaints (ctx , verifyMachineAndNodeTaintsInput {
208+ BootstrapClusterClient : input .BootstrapClusterProxy .GetClient (),
209+ WorkloadClusterClient : wlClient ,
210+ ClusterName : clusterResources .Cluster .Name ,
211+ MachineDeployments : clusterResources .MachineDeployments ,
212+ MachineTaints : wantMachineTaints ,
213+ NodeTaints : wantNodeTaints ,
214+ })
215+
216+ Byf ("Verify in-place propagation when removing an Always taint from the nodes" )
217+ nodes := corev1.NodeList {}
218+ Expect (wlClient .List (ctx , & nodes )).To (Succeed ())
219+ // Remove the initial taints from the nodes.
220+ for _ , node := range nodes .Items {
221+ patchHelper , err := patch .NewHelper (& node , wlClient )
222+ Expect (err ).ToNot (HaveOccurred ())
223+ newTaints := []corev1.Taint {}
224+ for _ , taint := range node .Spec .Taints {
225+ if taint .Key == preExistingAlwaysTaint .Key {
226+ continue
227+ }
228+ if taint .Key == preExistingOnInitializationTaint .Key {
229+ continue
230+ }
231+ newTaints = append (newTaints , taint )
232+ }
233+ node .Spec .Taints = newTaints
234+ Expect (patchHelper .Patch (ctx , & node )).To (Succeed ())
235+ }
236+
237+ wantNodeTaints = toCoreV1Taints (
238+ preExistingAlwaysTaint ,
239+ addingAlwaysTaint ,
240+ )
241+
242+ verifyMachineAndNodeTaints (ctx , verifyMachineAndNodeTaintsInput {
243+ BootstrapClusterClient : input .BootstrapClusterProxy .GetClient (),
244+ WorkloadClusterClient : wlClient ,
245+ ClusterName : clusterResources .Cluster .Name ,
246+ MachineDeployments : clusterResources .MachineDeployments ,
247+ MachineTaints : wantMachineTaints ,
248+ NodeTaints : wantNodeTaints ,
249+ })
250+
251+ Byf ("Verify in-place propagation by removing taints from the MachineDeployment" )
252+ wantMachineTaints = []clusterv1.MachineTaint {
253+ preExistingOnInitializationTaint ,
254+ addingOnInitializationTaint ,
255+ }
256+ wantNodeTaints = toCoreV1Taints ()
257+ for _ , md := range clusterResources .MachineDeployments {
258+ patchHelper , err := patch .NewHelper (md , input .BootstrapClusterProxy .GetClient ())
259+ Expect (err ).ToNot (HaveOccurred ())
260+ md .Spec .Template .Spec .Taints = wantMachineTaints
261+ Expect (patchHelper .Patch (ctx , md )).To (Succeed ())
262+ }
263+
264+ verifyMachineAndNodeTaints (ctx , verifyMachineAndNodeTaintsInput {
265+ BootstrapClusterClient : input .BootstrapClusterProxy .GetClient (),
266+ WorkloadClusterClient : wlClient ,
267+ ClusterName : clusterResources .Cluster .Name ,
268+ MachineDeployments : clusterResources .MachineDeployments ,
269+ MachineTaints : wantMachineTaints ,
270+ NodeTaints : wantNodeTaints ,
271+ })
272+
138273 By ("PASSED!" )
139274 })
140275
@@ -143,3 +278,52 @@ func MachineDeploymentRolloutSpec(ctx context.Context, inputGetter func() Machin
143278 framework .DumpSpecResourcesAndCleanup (ctx , specName , input .BootstrapClusterProxy , input .ClusterctlConfigPath , input .ArtifactFolder , namespace , cancelWatches , clusterResources .Cluster , input .E2EConfig .GetIntervals , input .SkipCleanup )
144279 })
145280}
281+
282+ type verifyMachineAndNodeTaintsInput struct {
283+ BootstrapClusterClient client.Client
284+ WorkloadClusterClient client.Client
285+ ClusterName string
286+ MachineDeployments []* clusterv1.MachineDeployment
287+ MachineTaints []clusterv1.MachineTaint
288+ NodeTaints []corev1.Taint
289+ }
290+
291+ func verifyMachineAndNodeTaints (ctx context.Context , input verifyMachineAndNodeTaintsInput ) {
292+ Expect (ctx ).NotTo (BeNil (), "ctx is required for verifyMachineAndNodeTaints" )
293+ Expect (input .BootstrapClusterClient ).ToNot (BeNil (), "Invalid argument. input.BootstrapClusterClient can't be nil when calling verifyMachineAndNodeTaints" )
294+ Expect (input .WorkloadClusterClient ).ToNot (BeNil (), "Invalid argument. input.WorkloadClusterClient can't be nil when calling verifyMachineAndNodeTaints" )
295+ Expect (input .ClusterName ).NotTo (BeEmpty (), "Invalid argument. input.ClusterName can't be empty when calling verifyMachineAndNodeTaints" )
296+ Expect (input .MachineDeployments ).NotTo (BeNil (), "Invalid argument. input.MachineDeployments can't be nil when calling verifyMachineAndNodeTaints" )
297+
298+ Eventually (func (g Gomega ) {
299+ for _ , md := range input .MachineDeployments {
300+ machines := framework .GetMachinesByMachineDeployments (ctx , framework.GetMachinesByMachineDeploymentsInput {
301+ Lister : input .BootstrapClusterClient ,
302+ ClusterName : input .ClusterName ,
303+ Namespace : md .Namespace ,
304+ MachineDeployment : * md ,
305+ })
306+ g .Expect (machines ).To (HaveLen (int (ptr .Deref (md .Spec .Replicas , 0 ))))
307+ for _ , machine := range machines {
308+ g .Expect (machine .Spec .Taints ).To (ConsistOf (input .MachineTaints ))
309+ g .Expect (machine .Status .NodeRef .IsDefined ()).To (BeTrue ())
310+
311+ node := & corev1.Node {}
312+ g .Expect (input .WorkloadClusterClient .Get (ctx , client.ObjectKey {Name : machine .Status .NodeRef .Name }, node )).To (Succeed ())
313+ g .Expect (node .Spec .Taints ).To (ConsistOf (input .NodeTaints ))
314+ }
315+ }
316+ }, "1m" ).Should (Succeed ())
317+ }
318+
319+ func toCoreV1Taints (machineTaints ... clusterv1.MachineTaint ) []corev1.Taint {
320+ taints := []corev1.Taint {}
321+ for _ , machineTaint := range machineTaints {
322+ taints = append (taints , corev1.Taint {
323+ Key : machineTaint .Key ,
324+ Value : ptr .Deref (machineTaint .Value , "" ),
325+ Effect : machineTaint .Effect ,
326+ })
327+ }
328+ return taints
329+ }
0 commit comments