@@ -22,12 +22,15 @@ import (
2222 . "github.com/onsi/gomega"
2323 corev1 "k8s.io/api/core/v1"
2424 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2526 "k8s.io/utils/ptr"
27+ "sigs.k8s.io/controller-runtime/pkg/client"
2628
2729 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2830 controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
2931 "sigs.k8s.io/cluster-api/util/collections"
3032 "sigs.k8s.io/cluster-api/util/conditions"
33+ "sigs.k8s.io/cluster-api/util/patch"
3134)
3235
3336func TestControlPlane (t * testing.T ) {
@@ -61,6 +64,12 @@ func TestControlPlane(t *testing.T) {
6164 controlPlane .Machines .Insert (machine ("machine-5" , withFailureDomain ("unknown" )))
6265 g .Expect (* controlPlane .FailureDomainWithMostMachines (ctx , controlPlane .Machines )).To (Equal ("unknown" ))
6366 })
67+
68+ t .Run ("With failure Domains is set empty" , func (* testing.T ) {
69+ g := NewWithT (t )
70+ controlPlane .Cluster .Status .FailureDomains = nil
71+ g .Expect (* controlPlane .FailureDomainWithMostMachines (ctx , controlPlane .Machines )).To (Equal ("one" ))
72+ })
6473 })
6574
6675 t .Run ("MachinesUpToDate" , func (t * testing.T ) {
@@ -141,6 +150,173 @@ func TestControlPlane(t *testing.T) {
141150 g .Expect (err ).NotTo (HaveOccurred ())
142151 g .Expect (fd ).To (Equal (ptr .To ("two" ))) // deleted up-to-date machines (m4) should not be counted when picking the next failure domain for scale up
143152 })
153+
154+ t .Run ("Next Failure Domains" , func (t * testing.T ) {
155+ g := NewWithT (t )
156+ cluster := clusterv1.Cluster {
157+ Status : clusterv1.ClusterStatus {
158+ FailureDomains : clusterv1.FailureDomains {
159+ "one" : failureDomain (false ),
160+ },
161+ },
162+ }
163+ kcp := & controlplanev1.KubeadmControlPlane {
164+ Spec : controlplanev1.KubeadmControlPlaneSpec {
165+ Version : "v1.31.0" ,
166+ },
167+ }
168+ machines := collections.Machines {
169+ "machine-1" : & clusterv1.Machine {
170+ ObjectMeta : metav1.ObjectMeta {Name : "m1" , DeletionTimestamp : ptr .To (metav1 .Now ())},
171+ Spec : clusterv1.MachineSpec {
172+ Version : ptr .To ("v1.31.0" ), // deleted
173+ FailureDomain : ptr .To ("one" ),
174+ InfrastructureRef : corev1.ObjectReference {Kind : "GenericInfrastructureMachine" , APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" , Name : "m1" },
175+ }},
176+ }
177+ controlPlane , err := NewControlPlane (ctx , nil , env .GetClient (), & cluster , kcp , machines )
178+ g .Expect (err ).NotTo (HaveOccurred ())
179+ fd , err := controlPlane .NextFailureDomainForScaleUp (ctx )
180+ g .Expect (err ).NotTo (HaveOccurred ())
181+ g .Expect (fd ).To (BeNil ())
182+ })
183+
184+ t .Run ("ControlPlane returns infra error" , func (t * testing.T ) {
185+ g := NewWithT (t )
186+ cluster := clusterv1.Cluster {
187+ Status : clusterv1.ClusterStatus {
188+ FailureDomains : clusterv1.FailureDomains {
189+ "one" : failureDomain (true ),
190+ "two" : failureDomain (true ),
191+ "three" : failureDomain (true ),
192+ },
193+ },
194+ }
195+ kcp := & controlplanev1.KubeadmControlPlane {
196+ Spec : controlplanev1.KubeadmControlPlaneSpec {
197+ Version : "v1.31.0" ,
198+ },
199+ }
200+ machines := collections.Machines {
201+ "machine-1" : & clusterv1.Machine {
202+ ObjectMeta : metav1.ObjectMeta {Name : "m1" },
203+ Spec : clusterv1.MachineSpec {
204+ Version : ptr .To ("v1.31.0" ),
205+ FailureDomain : ptr .To ("one" ),
206+ InfrastructureRef : corev1.ObjectReference {Name : "m1" },
207+ }},
208+ }
209+ _ , err := NewControlPlane (ctx , nil , env .GetClient (), & cluster , kcp , machines )
210+ g .Expect (err ).To (HaveOccurred ())
211+ })
212+
213+ t .Run ("When infra and bootstrap config is exists" , func (t * testing.T ) {
214+ g := NewWithT (t )
215+ ns , err := env .CreateNamespace (ctx , "test-machine-watches" )
216+ kcp := & controlplanev1.KubeadmControlPlane {
217+ Spec : controlplanev1.KubeadmControlPlaneSpec {
218+ Version : "v1.31.0" ,
219+ },
220+ }
221+
222+ g .Expect (err ).ToNot (HaveOccurred ())
223+
224+ infraMachine := & unstructured.Unstructured {
225+ Object : map [string ]interface {}{
226+ "kind" : "GenericInfrastructureMachine" ,
227+ "apiVersion" : "infrastructure.cluster.x-k8s.io/v1beta1" ,
228+ "metadata" : map [string ]interface {}{
229+ "name" : "infra-config1" ,
230+ "namespace" : ns .Name ,
231+ },
232+ "spec" : map [string ]interface {}{
233+ "providerID" : "test://id-1" ,
234+ },
235+ "status" : map [string ]interface {}{
236+ "ready" : true ,
237+ "addresses" : []interface {}{
238+ map [string ]interface {}{
239+ "type" : "InternalIP" ,
240+ "address" : "10.0.0.1" ,
241+ },
242+ },
243+ },
244+ },
245+ }
246+
247+ bootstrap := & unstructured.Unstructured {
248+ Object : map [string ]interface {}{
249+ "kind" : "KubeadmConfig" ,
250+ "apiVersion" : "bootstrap.cluster.x-k8s.io/v1beta1" ,
251+ "metadata" : map [string ]interface {}{
252+ "name" : "bootstrap-config-machinereconcile" ,
253+ "namespace" : ns .Name ,
254+ },
255+ "spec" : map [string ]interface {}{
256+ "providerID" : "test://id-1" ,
257+ },
258+ "status" : map [string ]interface {}{
259+ "ready" : true ,
260+ },
261+ },
262+ }
263+
264+ testCluster := & clusterv1.Cluster {
265+ ObjectMeta : metav1.ObjectMeta {Name : "test-cluster" , Namespace : ns .Name },
266+ Status : clusterv1.ClusterStatus {
267+ FailureDomains : clusterv1.FailureDomains {
268+ "one" : failureDomain (true ),
269+ "two" : failureDomain (true ),
270+ "three" : failureDomain (true ),
271+ },
272+ },
273+ }
274+
275+ g .Expect (env .Create (ctx , infraMachine )).To (Succeed ())
276+ g .Expect (env .Create (ctx , bootstrap )).To (Succeed ())
277+
278+ defer func (do ... client.Object ) {
279+ g .Expect (env .Cleanup (ctx , do ... )).To (Succeed ())
280+ }(ns , bootstrap , infraMachine )
281+
282+ // Patch infra machine ready
283+ patchHelper , err := patch .NewHelper (infraMachine , env )
284+ g .Expect (err ).ShouldNot (HaveOccurred ())
285+ g .Expect (unstructured .SetNestedField (infraMachine .Object , true , "status" , "ready" )).To (Succeed ())
286+ g .Expect (patchHelper .Patch (ctx , infraMachine , patch.WithStatusObservedGeneration {})).To (Succeed ())
287+
288+ // Patch bootstrap ready
289+ patchHelper , err = patch .NewHelper (bootstrap , env )
290+ g .Expect (err ).ShouldNot (HaveOccurred ())
291+ g .Expect (unstructured .SetNestedField (bootstrap .Object , true , "status" , "ready" )).To (Succeed ())
292+ g .Expect (patchHelper .Patch (ctx , bootstrap , patch.WithStatusObservedGeneration {})).To (Succeed ())
293+
294+ machines := collections.Machines {
295+ "machine-1" : & clusterv1.Machine {
296+ ObjectMeta : metav1.ObjectMeta {Name : "m1" ,
297+ Namespace : ns .Name },
298+ Spec : clusterv1.MachineSpec {
299+ InfrastructureRef : corev1.ObjectReference {
300+ APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" ,
301+ Kind : "GenericInfrastructureMachine" ,
302+ Name : "infra-config1" ,
303+ Namespace : ns .Name ,
304+ },
305+ Bootstrap : clusterv1.Bootstrap {
306+ ConfigRef : & corev1.ObjectReference {
307+ APIVersion : "bootstrap.cluster.x-k8s.io/v1beta1" ,
308+ Kind : "KubeadmConfig" ,
309+ Name : "bootstrap-config-machinereconcile" ,
310+ Namespace : ns .Name ,
311+ },
312+ },
313+ },
314+ },
315+ }
316+
317+ _ , err = NewControlPlane (ctx , nil , env .GetClient (), testCluster , kcp , machines )
318+ g .Expect (err ).NotTo (HaveOccurred ())
319+ })
144320}
145321
146322func TestHasMachinesToBeRemediated (t * testing.T ) {
@@ -252,6 +428,94 @@ func TestHasHealthyMachineStillProvisioning(t *testing.T) {
252428 })
253429}
254430
431+ func TestMachineInFailureDomainWithMostMachines (t * testing.T ) {
432+ t .Run ("Machines in Failure Domain" , func (t * testing.T ) {
433+ machines := collections.Machines {
434+ "machine-3" : & clusterv1.Machine {
435+ ObjectMeta : metav1.ObjectMeta {Name : "m3" },
436+ Spec : clusterv1.MachineSpec {
437+ Version : ptr .To ("v1.31.0" ),
438+ FailureDomain : ptr .To ("three" ),
439+ InfrastructureRef : corev1.ObjectReference {Kind : "GenericInfrastructureMachine" , APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" , Name : "m3" },
440+ }},
441+ }
442+
443+ c := & ControlPlane {
444+ KCP : & controlplanev1.KubeadmControlPlane {},
445+ Cluster : & clusterv1.Cluster {
446+ Status : clusterv1.ClusterStatus {
447+ FailureDomains : clusterv1.FailureDomains {
448+ "three" : failureDomain (false ),
449+ },
450+ },
451+ },
452+ Machines : collections.Machines {
453+ "machine-3" : machine ("machine-3" , withFailureDomain ("three" )),
454+ },
455+ }
456+
457+ g := NewWithT (t )
458+ _ , err := c .MachineInFailureDomainWithMostMachines (ctx , machines )
459+ g .Expect (err ).NotTo (HaveOccurred ())
460+ })
461+ t .Run ("Return error when no controlplane machine found" , func (t * testing.T ) {
462+ machines := collections.Machines {}
463+
464+ c := & ControlPlane {
465+ KCP : & controlplanev1.KubeadmControlPlane {},
466+ Cluster : & clusterv1.Cluster {
467+ Status : clusterv1.ClusterStatus {
468+ FailureDomains : clusterv1.FailureDomains {},
469+ },
470+ },
471+ Machines : collections.Machines {},
472+ }
473+
474+ g := NewWithT (t )
475+ _ , err := c .MachineInFailureDomainWithMostMachines (ctx , machines )
476+ g .Expect (err ).To (HaveOccurred ())
477+ })
478+ }
479+ func TestMachineWithDeleteAnnotation (t * testing.T ) {
480+ t .Run ("Machines having delete annotation set" , func (t * testing.T ) {
481+ machines := collections.Machines {
482+ "machine-1" : & clusterv1.Machine {
483+ ObjectMeta : metav1.ObjectMeta {Name : "m1" ,
484+ Annotations : map [string ]string {
485+ "cluster.x-k8s.io/delete-machine" : "" ,
486+ },
487+ },
488+ Spec : clusterv1.MachineSpec {
489+ Version : ptr .To ("v1.31.0" ),
490+ FailureDomain : ptr .To ("one" ),
491+ InfrastructureRef : corev1.ObjectReference {Kind : "GenericInfrastructureMachine" , APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" , Name : "m1" },
492+ }},
493+ "machine-2" : & clusterv1.Machine {
494+ ObjectMeta : metav1.ObjectMeta {Name : "m2" ,
495+ Annotations : map [string ]string {
496+ "cluster.x-k8s.io/delete-machine" : "" ,
497+ },
498+ },
499+ Spec : clusterv1.MachineSpec {
500+ Version : ptr .To ("v1.31.0" ),
501+ FailureDomain : ptr .To ("two" ),
502+ InfrastructureRef : corev1.ObjectReference {Kind : "GenericInfrastructureMachine" , APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" , Name : "m2" },
503+ }},
504+ }
505+
506+ c := ControlPlane {
507+ Machines : machines ,
508+ Cluster : & clusterv1.Cluster {
509+ Status : clusterv1.ClusterStatus {},
510+ },
511+ }
512+
513+ g := NewWithT (t )
514+ annotedMachines := c .MachineWithDeleteAnnotation (machines )
515+ g .Expect (annotedMachines ).NotTo (BeNil ())
516+ })
517+ }
518+
255519type machineOpt func (* clusterv1.Machine )
256520
257521func failureDomain (controlPlane bool ) clusterv1.FailureDomainSpec {
0 commit comments