sigs.k8s.io/cluster-api@v1.7.1/controlplane/kubeadm/internal/control_plane_test.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package internal 18 19 import ( 20 "testing" 21 22 . "github.com/onsi/gomega" 23 corev1 "k8s.io/api/core/v1" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 26 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 27 controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" 28 "sigs.k8s.io/cluster-api/util/collections" 29 "sigs.k8s.io/cluster-api/util/conditions" 30 ) 31 32 func TestControlPlane(t *testing.T) { 33 g := NewWithT(t) 34 35 t.Run("Failure domains", func(t *testing.T) { 36 controlPlane := &ControlPlane{ 37 KCP: &controlplanev1.KubeadmControlPlane{}, 38 Cluster: &clusterv1.Cluster{ 39 Status: clusterv1.ClusterStatus{ 40 FailureDomains: clusterv1.FailureDomains{ 41 "one": failureDomain(true), 42 "two": failureDomain(true), 43 "three": failureDomain(true), 44 "four": failureDomain(false), 45 }, 46 }, 47 }, 48 Machines: collections.Machines{ 49 "machine-1": machine("machine-1", withFailureDomain("one")), 50 "machine-2": machine("machine-2", withFailureDomain("two")), 51 "machine-3": machine("machine-3", withFailureDomain("two")), 52 }, 53 } 54 55 t.Run("With all machines in known failure domain, should return the FD with most number of machines", func(*testing.T) { 56 g.Expect(*controlPlane.FailureDomainWithMostMachines(ctx, controlPlane.Machines)).To(Equal("two")) 57 }) 58 59 t.Run("With some machines in non defined failure domains", func(*testing.T) { 60 controlPlane.Machines.Insert(machine("machine-5", withFailureDomain("unknown"))) 61 g.Expect(*controlPlane.FailureDomainWithMostMachines(ctx, controlPlane.Machines)).To(Equal("unknown")) 62 }) 63 }) 64 } 65 66 func TestHasUnhealthyMachine(t *testing.T) { 67 // healthy machine (without MachineHealthCheckSucceded condition) 68 healthyMachine1 := &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "healthyMachine1"}} 69 // healthy machine (with MachineHealthCheckSucceded == true) 70 healthyMachine2 := &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "healthyMachine2"}} 71 conditions.MarkTrue(healthyMachine2, clusterv1.MachineHealthCheckSucceededCondition) 72 // unhealthy machine NOT eligible for KCP remediation (with MachineHealthCheckSucceded == False, but without MachineOwnerRemediated condition) 73 unhealthyMachineNOTOwnerRemediated := &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "unhealthyMachineNOTOwnerRemediated"}} 74 conditions.MarkFalse(unhealthyMachineNOTOwnerRemediated, clusterv1.MachineHealthCheckSucceededCondition, clusterv1.MachineHasFailureReason, clusterv1.ConditionSeverityWarning, "Something is wrong") 75 // unhealthy machine eligible for KCP remediation (with MachineHealthCheckSucceded == False, with MachineOwnerRemediated condition) 76 unhealthyMachineOwnerRemediated := &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "unhealthyMachineOwnerRemediated"}} 77 conditions.MarkFalse(unhealthyMachineOwnerRemediated, clusterv1.MachineHealthCheckSucceededCondition, clusterv1.MachineHasFailureReason, clusterv1.ConditionSeverityWarning, "Something is wrong") 78 conditions.MarkFalse(unhealthyMachineOwnerRemediated, clusterv1.MachineOwnerRemediatedCondition, clusterv1.WaitingForRemediationReason, clusterv1.ConditionSeverityWarning, "KCP should remediate this issue") 79 80 t.Run("One unhealthy machine to be remediated by KCP", func(t *testing.T) { 81 c := ControlPlane{ 82 Machines: collections.FromMachines( 83 healthyMachine1, // healthy machine, should be ignored 84 healthyMachine2, // healthy machine, should be ignored (the MachineHealthCheckSucceededCondition is true) 85 unhealthyMachineNOTOwnerRemediated, // unhealthy machine, but KCP should not remediate it, should be ignored. 86 unhealthyMachineOwnerRemediated, 87 ), 88 } 89 90 g := NewWithT(t) 91 g.Expect(c.HasUnhealthyMachineByMachineHealthCheck()).To(BeTrue()) 92 }) 93 94 t.Run("No unhealthy machine to be remediated by KCP", func(t *testing.T) { 95 c := ControlPlane{ 96 Machines: collections.FromMachines( 97 healthyMachine1, // healthy machine, should be ignored 98 healthyMachine2, // healthy machine, should be ignored (the MachineHealthCheckSucceededCondition is true) 99 unhealthyMachineNOTOwnerRemediated, // unhealthy machine, but KCP should not remediate it, should be ignored. 100 ), 101 } 102 103 g := NewWithT(t) 104 g.Expect(c.HasUnhealthyMachineByMachineHealthCheck()).To(BeFalse()) 105 }) 106 } 107 108 func TestHasHealthyMachineStillProvisioning(t *testing.T) { 109 // healthy machine (without MachineHealthCheckSucceded condition) still provisioning (without NodeRef) 110 healthyMachineStillProvisioning1 := &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "healthyMachineStillProvisioning1"}} 111 112 // healthy machine (without MachineHealthCheckSucceded condition) provisioned (with NodeRef) 113 healthyMachineProvisioned1 := &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "healthyMachineProvisioned1"}} 114 healthyMachineProvisioned1.Status.NodeRef = &corev1.ObjectReference{} 115 116 // unhealthy machine (with MachineHealthCheckSucceded condition) still provisioning (without NodeRef) 117 unhealthyMachineStillProvisioning1 := &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "unhealthyMachineStillProvisioning1"}} 118 conditions.MarkFalse(unhealthyMachineStillProvisioning1, clusterv1.MachineHealthCheckSucceededCondition, clusterv1.MachineHasFailureReason, clusterv1.ConditionSeverityWarning, "Something is wrong") 119 conditions.MarkFalse(unhealthyMachineStillProvisioning1, clusterv1.MachineOwnerRemediatedCondition, clusterv1.WaitingForRemediationReason, clusterv1.ConditionSeverityWarning, "KCP should remediate this issue") 120 121 // unhealthy machine (with MachineHealthCheckSucceded condition) provisioned (with NodeRef) 122 unhealthyMachineProvisioned1 := &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "unhealthyMachineProvisioned1"}} 123 unhealthyMachineProvisioned1.Status.NodeRef = &corev1.ObjectReference{} 124 conditions.MarkFalse(unhealthyMachineProvisioned1, clusterv1.MachineHealthCheckSucceededCondition, clusterv1.MachineHasFailureReason, clusterv1.ConditionSeverityWarning, "Something is wrong") 125 conditions.MarkFalse(unhealthyMachineProvisioned1, clusterv1.MachineOwnerRemediatedCondition, clusterv1.WaitingForRemediationReason, clusterv1.ConditionSeverityWarning, "KCP should remediate this issue") 126 127 t.Run("Healthy machine still provisioning", func(t *testing.T) { 128 c := ControlPlane{ 129 Machines: collections.FromMachines( 130 healthyMachineStillProvisioning1, 131 unhealthyMachineStillProvisioning1, // unhealthy, should be ignored 132 healthyMachineProvisioned1, // already provisioned, should be ignored 133 unhealthyMachineProvisioned1, // unhealthy and already provisioned, should be ignored 134 ), 135 } 136 137 g := NewWithT(t) 138 g.Expect(c.HasHealthyMachineStillProvisioning()).To(BeTrue()) 139 }) 140 t.Run("No machines still provisioning", func(t *testing.T) { 141 c := ControlPlane{ 142 Machines: collections.FromMachines( 143 unhealthyMachineStillProvisioning1, // unhealthy, should be ignored 144 healthyMachineProvisioned1, // already provisioned, should be ignored 145 unhealthyMachineProvisioned1, // unhealthy and already provisioned, should be ignored 146 ), 147 } 148 149 g := NewWithT(t) 150 g.Expect(c.HasHealthyMachineStillProvisioning()).To(BeFalse()) 151 }) 152 } 153 154 type machineOpt func(*clusterv1.Machine) 155 156 func failureDomain(controlPlane bool) clusterv1.FailureDomainSpec { 157 return clusterv1.FailureDomainSpec{ 158 ControlPlane: controlPlane, 159 } 160 } 161 162 func withFailureDomain(fd string) machineOpt { 163 return func(m *clusterv1.Machine) { 164 m.Spec.FailureDomain = &fd 165 } 166 } 167 168 func machine(name string, opts ...machineOpt) *clusterv1.Machine { 169 m := &clusterv1.Machine{ 170 ObjectMeta: metav1.ObjectMeta{ 171 Name: name, 172 }, 173 } 174 for _, opt := range opts { 175 opt(m) 176 } 177 return m 178 }