@@ -24,13 +24,16 @@ import (
2424 . "github.com/onsi/gomega"
2525 corev1 "k8s.io/api/core/v1"
2626 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2728 "k8s.io/utils/ptr"
29+ "sigs.k8s.io/controller-runtime/pkg/client"
2830
2931 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
3032 controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
3133 "sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/etcd"
3234 "sigs.k8s.io/cluster-api/util/collections"
3335 "sigs.k8s.io/cluster-api/util/conditions"
36+ "sigs.k8s.io/cluster-api/util/patch"
3437)
3538
3639func TestControlPlane (t * testing.T ) {
@@ -64,6 +67,12 @@ func TestControlPlane(t *testing.T) {
6467 controlPlane .Machines .Insert (machine ("machine-5" , withFailureDomain ("unknown" )))
6568 g .Expect (* controlPlane .FailureDomainWithMostMachines (ctx , controlPlane .Machines )).To (Equal ("unknown" ))
6669 })
70+
71+ t .Run ("With failure Domains is set empty" , func (* testing.T ) {
72+ g := NewWithT (t )
73+ controlPlane .Cluster .Status .FailureDomains = nil
74+ g .Expect (* controlPlane .FailureDomainWithMostMachines (ctx , controlPlane .Machines )).To (Equal ("one" ))
75+ })
6776 })
6877
6978 t .Run ("MachinesUpToDate" , func (t * testing.T ) {
@@ -144,6 +153,173 @@ func TestControlPlane(t *testing.T) {
144153 g .Expect (err ).NotTo (HaveOccurred ())
145154 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
146155 })
156+
157+ t .Run ("Next Failure Domains" , func (t * testing.T ) {
158+ g := NewWithT (t )
159+ cluster := clusterv1.Cluster {
160+ Status : clusterv1.ClusterStatus {
161+ FailureDomains : clusterv1.FailureDomains {
162+ "one" : failureDomain (false ),
163+ },
164+ },
165+ }
166+ kcp := & controlplanev1.KubeadmControlPlane {
167+ Spec : controlplanev1.KubeadmControlPlaneSpec {
168+ Version : "v1.31.0" ,
169+ },
170+ }
171+ machines := collections.Machines {
172+ "machine-1" : & clusterv1.Machine {
173+ ObjectMeta : metav1.ObjectMeta {Name : "m1" , DeletionTimestamp : ptr .To (metav1 .Now ())},
174+ Spec : clusterv1.MachineSpec {
175+ Version : ptr .To ("v1.31.0" ), // deleted
176+ FailureDomain : ptr .To ("one" ),
177+ InfrastructureRef : corev1.ObjectReference {Kind : "GenericInfrastructureMachine" , APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" , Name : "m1" },
178+ }},
179+ }
180+ controlPlane , err := NewControlPlane (ctx , nil , env .GetClient (), & cluster , kcp , machines )
181+ g .Expect (err ).NotTo (HaveOccurred ())
182+ fd , err := controlPlane .NextFailureDomainForScaleUp (ctx )
183+ g .Expect (err ).NotTo (HaveOccurred ())
184+ g .Expect (fd ).To (BeNil ())
185+ })
186+
187+ t .Run ("ControlPlane returns infra error" , func (t * testing.T ) {
188+ g := NewWithT (t )
189+ cluster := clusterv1.Cluster {
190+ Status : clusterv1.ClusterStatus {
191+ FailureDomains : clusterv1.FailureDomains {
192+ "one" : failureDomain (true ),
193+ "two" : failureDomain (true ),
194+ "three" : failureDomain (true ),
195+ },
196+ },
197+ }
198+ kcp := & controlplanev1.KubeadmControlPlane {
199+ Spec : controlplanev1.KubeadmControlPlaneSpec {
200+ Version : "v1.31.0" ,
201+ },
202+ }
203+ machines := collections.Machines {
204+ "machine-1" : & clusterv1.Machine {
205+ ObjectMeta : metav1.ObjectMeta {Name : "m1" },
206+ Spec : clusterv1.MachineSpec {
207+ Version : ptr .To ("v1.31.0" ),
208+ FailureDomain : ptr .To ("one" ),
209+ InfrastructureRef : corev1.ObjectReference {Name : "m1" },
210+ }},
211+ }
212+ _ , err := NewControlPlane (ctx , nil , env .GetClient (), & cluster , kcp , machines )
213+ g .Expect (err ).To (HaveOccurred ())
214+ })
215+
216+ t .Run ("When infra and bootstrap config is exists" , func (t * testing.T ) {
217+ g := NewWithT (t )
218+ ns , err := env .CreateNamespace (ctx , "test-machine-watches" )
219+ kcp := & controlplanev1.KubeadmControlPlane {
220+ Spec : controlplanev1.KubeadmControlPlaneSpec {
221+ Version : "v1.31.0" ,
222+ },
223+ }
224+
225+ g .Expect (err ).ToNot (HaveOccurred ())
226+
227+ infraMachine := & unstructured.Unstructured {
228+ Object : map [string ]interface {}{
229+ "kind" : "GenericInfrastructureMachine" ,
230+ "apiVersion" : "infrastructure.cluster.x-k8s.io/v1beta1" ,
231+ "metadata" : map [string ]interface {}{
232+ "name" : "infra-config1" ,
233+ "namespace" : ns .Name ,
234+ },
235+ "spec" : map [string ]interface {}{
236+ "providerID" : "test://id-1" ,
237+ },
238+ "status" : map [string ]interface {}{
239+ "ready" : true ,
240+ "addresses" : []interface {}{
241+ map [string ]interface {}{
242+ "type" : "InternalIP" ,
243+ "address" : "10.0.0.1" ,
244+ },
245+ },
246+ },
247+ },
248+ }
249+
250+ bootstrap := & unstructured.Unstructured {
251+ Object : map [string ]interface {}{
252+ "kind" : "KubeadmConfig" ,
253+ "apiVersion" : "bootstrap.cluster.x-k8s.io/v1beta1" ,
254+ "metadata" : map [string ]interface {}{
255+ "name" : "bootstrap-config-machinereconcile" ,
256+ "namespace" : ns .Name ,
257+ },
258+ "spec" : map [string ]interface {}{
259+ "providerID" : "test://id-1" ,
260+ },
261+ "status" : map [string ]interface {}{
262+ "ready" : true ,
263+ },
264+ },
265+ }
266+
267+ testCluster := & clusterv1.Cluster {
268+ ObjectMeta : metav1.ObjectMeta {Name : "test-cluster" , Namespace : ns .Name },
269+ Status : clusterv1.ClusterStatus {
270+ FailureDomains : clusterv1.FailureDomains {
271+ "one" : failureDomain (true ),
272+ "two" : failureDomain (true ),
273+ "three" : failureDomain (true ),
274+ },
275+ },
276+ }
277+
278+ g .Expect (env .Create (ctx , infraMachine )).To (Succeed ())
279+ g .Expect (env .Create (ctx , bootstrap )).To (Succeed ())
280+
281+ defer func (do ... client.Object ) {
282+ g .Expect (env .Cleanup (ctx , do ... )).To (Succeed ())
283+ }(ns , bootstrap , infraMachine )
284+
285+ // Patch infra machine ready
286+ patchHelper , err := patch .NewHelper (infraMachine , env )
287+ g .Expect (err ).ShouldNot (HaveOccurred ())
288+ g .Expect (unstructured .SetNestedField (infraMachine .Object , true , "status" , "ready" )).To (Succeed ())
289+ g .Expect (patchHelper .Patch (ctx , infraMachine , patch.WithStatusObservedGeneration {})).To (Succeed ())
290+
291+ // Patch bootstrap ready
292+ patchHelper , err = patch .NewHelper (bootstrap , env )
293+ g .Expect (err ).ShouldNot (HaveOccurred ())
294+ g .Expect (unstructured .SetNestedField (bootstrap .Object , true , "status" , "ready" )).To (Succeed ())
295+ g .Expect (patchHelper .Patch (ctx , bootstrap , patch.WithStatusObservedGeneration {})).To (Succeed ())
296+
297+ machines := collections.Machines {
298+ "machine-1" : & clusterv1.Machine {
299+ ObjectMeta : metav1.ObjectMeta {Name : "m1" ,
300+ Namespace : ns .Name },
301+ Spec : clusterv1.MachineSpec {
302+ InfrastructureRef : corev1.ObjectReference {
303+ APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" ,
304+ Kind : "GenericInfrastructureMachine" ,
305+ Name : "infra-config1" ,
306+ Namespace : ns .Name ,
307+ },
308+ Bootstrap : clusterv1.Bootstrap {
309+ ConfigRef : & corev1.ObjectReference {
310+ APIVersion : "bootstrap.cluster.x-k8s.io/v1beta1" ,
311+ Kind : "KubeadmConfig" ,
312+ Name : "bootstrap-config-machinereconcile" ,
313+ Namespace : ns .Name ,
314+ },
315+ },
316+ },
317+ },
318+ }
319+
320+ _ , err = NewControlPlane (ctx , nil , env .GetClient (), testCluster , kcp , machines )
321+ g .Expect (err ).NotTo (HaveOccurred ())
322+ })
147323}
148324
149325func TestHasMachinesToBeRemediated (t * testing.T ) {
@@ -324,6 +500,94 @@ func TestStatusToLogKeyAndValues(t *testing.T) {
324500 g .Expect (got [3 ]).To (Equal ("m1, m2, m3" ))
325501}
326502
503+ func TestMachineInFailureDomainWithMostMachines (t * testing.T ) {
504+ t .Run ("Machines in Failure Domain" , func (t * testing.T ) {
505+ machines := collections.Machines {
506+ "machine-3" : & clusterv1.Machine {
507+ ObjectMeta : metav1.ObjectMeta {Name : "m3" },
508+ Spec : clusterv1.MachineSpec {
509+ Version : ptr .To ("v1.31.0" ),
510+ FailureDomain : ptr .To ("three" ),
511+ InfrastructureRef : corev1.ObjectReference {Kind : "GenericInfrastructureMachine" , APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" , Name : "m3" },
512+ }},
513+ }
514+
515+ c := & ControlPlane {
516+ KCP : & controlplanev1.KubeadmControlPlane {},
517+ Cluster : & clusterv1.Cluster {
518+ Status : clusterv1.ClusterStatus {
519+ FailureDomains : clusterv1.FailureDomains {
520+ "three" : failureDomain (false ),
521+ },
522+ },
523+ },
524+ Machines : collections.Machines {
525+ "machine-3" : machine ("machine-3" , withFailureDomain ("three" )),
526+ },
527+ }
528+
529+ g := NewWithT (t )
530+ _ , err := c .MachineInFailureDomainWithMostMachines (ctx , machines )
531+ g .Expect (err ).NotTo (HaveOccurred ())
532+ })
533+ t .Run ("Return error when no controlplane machine found" , func (t * testing.T ) {
534+ machines := collections.Machines {}
535+
536+ c := & ControlPlane {
537+ KCP : & controlplanev1.KubeadmControlPlane {},
538+ Cluster : & clusterv1.Cluster {
539+ Status : clusterv1.ClusterStatus {
540+ FailureDomains : clusterv1.FailureDomains {},
541+ },
542+ },
543+ Machines : collections.Machines {},
544+ }
545+
546+ g := NewWithT (t )
547+ _ , err := c .MachineInFailureDomainWithMostMachines (ctx , machines )
548+ g .Expect (err ).To (HaveOccurred ())
549+ })
550+ }
551+ func TestMachineWithDeleteAnnotation (t * testing.T ) {
552+ t .Run ("Machines having delete annotation set" , func (t * testing.T ) {
553+ machines := collections.Machines {
554+ "machine-1" : & clusterv1.Machine {
555+ ObjectMeta : metav1.ObjectMeta {Name : "m1" ,
556+ Annotations : map [string ]string {
557+ "cluster.x-k8s.io/delete-machine" : "" ,
558+ },
559+ },
560+ Spec : clusterv1.MachineSpec {
561+ Version : ptr .To ("v1.31.0" ),
562+ FailureDomain : ptr .To ("one" ),
563+ InfrastructureRef : corev1.ObjectReference {Kind : "GenericInfrastructureMachine" , APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" , Name : "m1" },
564+ }},
565+ "machine-2" : & clusterv1.Machine {
566+ ObjectMeta : metav1.ObjectMeta {Name : "m2" ,
567+ Annotations : map [string ]string {
568+ "cluster.x-k8s.io/delete-machine" : "" ,
569+ },
570+ },
571+ Spec : clusterv1.MachineSpec {
572+ Version : ptr .To ("v1.31.0" ),
573+ FailureDomain : ptr .To ("two" ),
574+ InfrastructureRef : corev1.ObjectReference {Kind : "GenericInfrastructureMachine" , APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" , Name : "m2" },
575+ }},
576+ }
577+
578+ c := ControlPlane {
579+ Machines : machines ,
580+ Cluster : & clusterv1.Cluster {
581+ Status : clusterv1.ClusterStatus {},
582+ },
583+ }
584+
585+ g := NewWithT (t )
586+ annotedMachines := c .MachineWithDeleteAnnotation (machines )
587+ g .Expect (annotedMachines ).NotTo (BeNil ())
588+ })
589+ }
590+
327591type machineOpt func (* clusterv1.Machine )
328592
329593func failureDomain (controlPlane bool ) clusterv1.FailureDomainSpec {
0 commit comments