Skip to content

Commit 4e249ee

Browse files
committed
Add UTs for failure domain
1 parent 526ea91 commit 4e249ee

File tree

2 files changed

+607
-0
lines changed

2 files changed

+607
-0
lines changed

controlplane/kubeadm/internal/control_plane_test.go

+264
Original file line numberDiff line numberDiff line change
@@ -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

3336
func 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

146322
func 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+
255519
type machineOpt func(*clusterv1.Machine)
256520

257521
func failureDomain(controlPlane bool) clusterv1.FailureDomainSpec {

0 commit comments

Comments
 (0)