sigs.k8s.io/cluster-api@v1.7.1/util/collections/machine_filters_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 collections_test 18 19 import ( 20 "testing" 21 "time" 22 23 . "github.com/onsi/gomega" 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/utils/ptr" 27 "sigs.k8s.io/controller-runtime/pkg/client/fake" 28 29 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 30 controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" 31 "sigs.k8s.io/cluster-api/util/collections" 32 "sigs.k8s.io/cluster-api/util/conditions" 33 ) 34 35 func falseFilter(_ *clusterv1.Machine) bool { 36 return false 37 } 38 39 func trueFilter(_ *clusterv1.Machine) bool { 40 return true 41 } 42 43 func TestNot(t *testing.T) { 44 t.Run("returns false given a machine filter that returns true", func(t *testing.T) { 45 g := NewWithT(t) 46 m := &clusterv1.Machine{} 47 g.Expect(collections.Not(trueFilter)(m)).To(BeFalse()) 48 }) 49 t.Run("returns true given a machine filter that returns false", func(t *testing.T) { 50 g := NewWithT(t) 51 m := &clusterv1.Machine{} 52 g.Expect(collections.Not(falseFilter)(m)).To(BeTrue()) 53 }) 54 } 55 56 func TestAnd(t *testing.T) { 57 t.Run("returns true if both given machine filters return true", func(t *testing.T) { 58 g := NewWithT(t) 59 m := &clusterv1.Machine{} 60 g.Expect(collections.And(trueFilter, trueFilter)(m)).To(BeTrue()) 61 }) 62 t.Run("returns false if either given machine filter returns false", func(t *testing.T) { 63 g := NewWithT(t) 64 m := &clusterv1.Machine{} 65 g.Expect(collections.And(trueFilter, falseFilter)(m)).To(BeFalse()) 66 }) 67 } 68 69 func TestOr(t *testing.T) { 70 t.Run("returns true if either given machine filters return true", func(t *testing.T) { 71 g := NewWithT(t) 72 m := &clusterv1.Machine{} 73 g.Expect(collections.Or(trueFilter, falseFilter)(m)).To(BeTrue()) 74 }) 75 t.Run("returns false if both given machine filter returns false", func(t *testing.T) { 76 g := NewWithT(t) 77 m := &clusterv1.Machine{} 78 g.Expect(collections.Or(falseFilter, falseFilter)(m)).To(BeFalse()) 79 }) 80 } 81 82 func TestHasUnhealthyCondition(t *testing.T) { 83 t.Run("healthy machine (without HealthCheckSucceeded condition) should return false", func(t *testing.T) { 84 g := NewWithT(t) 85 m := &clusterv1.Machine{} 86 g.Expect(collections.HasUnhealthyCondition(m)).To(BeFalse()) 87 }) 88 t.Run("healthy machine (with HealthCheckSucceeded condition == True) should return false", func(t *testing.T) { 89 g := NewWithT(t) 90 m := &clusterv1.Machine{} 91 conditions.MarkTrue(m, clusterv1.MachineHealthCheckSucceededCondition) 92 g.Expect(collections.HasUnhealthyCondition(m)).To(BeFalse()) 93 }) 94 t.Run("unhealthy machine NOT eligible for KCP remediation (with withHealthCheckSucceeded condition == False but without OwnerRemediated) should return false", func(t *testing.T) { 95 g := NewWithT(t) 96 m := &clusterv1.Machine{} 97 conditions.MarkFalse(m, clusterv1.MachineHealthCheckSucceededCondition, clusterv1.MachineHasFailureReason, clusterv1.ConditionSeverityWarning, "") 98 g.Expect(collections.HasUnhealthyCondition(m)).To(BeFalse()) 99 }) 100 t.Run("unhealthy machine eligible for KCP (with HealthCheckSucceeded condition == False and with OwnerRemediated) should return true", func(t *testing.T) { 101 g := NewWithT(t) 102 m := &clusterv1.Machine{} 103 conditions.MarkFalse(m, clusterv1.MachineHealthCheckSucceededCondition, clusterv1.MachineHasFailureReason, clusterv1.ConditionSeverityWarning, "") 104 conditions.MarkFalse(m, clusterv1.MachineOwnerRemediatedCondition, clusterv1.WaitingForRemediationReason, clusterv1.ConditionSeverityWarning, "") 105 g.Expect(collections.HasUnhealthyCondition(m)).To(BeTrue()) 106 }) 107 } 108 109 func TestHasDeletionTimestamp(t *testing.T) { 110 t.Run("machine with deletion timestamp returns true", func(t *testing.T) { 111 g := NewWithT(t) 112 m := &clusterv1.Machine{} 113 now := metav1.Now() 114 m.SetDeletionTimestamp(&now) 115 g.Expect(collections.HasDeletionTimestamp(m)).To(BeTrue()) 116 }) 117 t.Run("machine with nil deletion timestamp returns false", func(t *testing.T) { 118 g := NewWithT(t) 119 m := &clusterv1.Machine{} 120 g.Expect(collections.HasDeletionTimestamp(m)).To(BeFalse()) 121 }) 122 t.Run("machine with zero deletion timestamp returns false", func(t *testing.T) { 123 g := NewWithT(t) 124 m := &clusterv1.Machine{} 125 zero := metav1.NewTime(time.Time{}) 126 m.SetDeletionTimestamp(&zero) 127 g.Expect(collections.HasDeletionTimestamp(m)).To(BeFalse()) 128 }) 129 } 130 131 func TestShouldRolloutAfter(t *testing.T) { 132 reconciliationTime := metav1.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) 133 t.Run("if the machine is nil it returns false", func(t *testing.T) { 134 g := NewWithT(t) 135 g.Expect(collections.ShouldRolloutAfter(&reconciliationTime, &reconciliationTime)(nil)).To(BeFalse()) 136 }) 137 t.Run("if the reconciliationTime is nil it returns false", func(t *testing.T) { 138 g := NewWithT(t) 139 m := &clusterv1.Machine{} 140 g.Expect(collections.ShouldRolloutAfter(nil, &reconciliationTime)(m)).To(BeFalse()) 141 }) 142 t.Run("if the rolloutAfter is nil it returns false", func(t *testing.T) { 143 g := NewWithT(t) 144 m := &clusterv1.Machine{} 145 g.Expect(collections.ShouldRolloutAfter(&reconciliationTime, nil)(m)).To(BeFalse()) 146 }) 147 t.Run("if rolloutAfter is after the reconciliation time, return false", func(t *testing.T) { 148 g := NewWithT(t) 149 m := &clusterv1.Machine{} 150 rolloutAfter := metav1.NewTime(reconciliationTime.Add(+1 * time.Hour)) 151 g.Expect(collections.ShouldRolloutAfter(&reconciliationTime, &rolloutAfter)(m)).To(BeFalse()) 152 }) 153 t.Run("if rolloutAfter is before the reconciliation time and the machine was created before rolloutAfter, return true", func(t *testing.T) { 154 g := NewWithT(t) 155 m := &clusterv1.Machine{} 156 m.SetCreationTimestamp(metav1.NewTime(reconciliationTime.Add(-2 * time.Hour))) 157 rolloutAfter := metav1.NewTime(reconciliationTime.Add(-1 * time.Hour)) 158 g.Expect(collections.ShouldRolloutAfter(&reconciliationTime, &rolloutAfter)(m)).To(BeTrue()) 159 }) 160 t.Run("if rolloutAfter is before the reconciliation time and the machine was created after rolloutAfter, return false", func(t *testing.T) { 161 g := NewWithT(t) 162 m := &clusterv1.Machine{} 163 m.SetCreationTimestamp(metav1.NewTime(reconciliationTime.Add(+1 * time.Hour))) 164 rolloutAfter := metav1.NewTime(reconciliationTime.Add(-1 * time.Hour)) 165 g.Expect(collections.ShouldRolloutAfter(&reconciliationTime, &rolloutAfter)(m)).To(BeFalse()) 166 }) 167 } 168 169 func TestShouldRolloutBeforeCertificatesExpire(t *testing.T) { 170 reconciliationTime := &metav1.Time{Time: time.Now()} 171 t.Run("if rolloutBefore is nil it should return false", func(t *testing.T) { 172 g := NewWithT(t) 173 m := &clusterv1.Machine{} 174 g.Expect(collections.ShouldRolloutBefore(reconciliationTime, nil)(m)).To(BeFalse()) 175 }) 176 t.Run("if rolloutBefore.certificatesExpiryDays is nil it should return false", func(t *testing.T) { 177 g := NewWithT(t) 178 m := &clusterv1.Machine{} 179 g.Expect(collections.ShouldRolloutBefore(reconciliationTime, &controlplanev1.RolloutBefore{})(m)).To(BeFalse()) 180 }) 181 t.Run("if machine is nil it should return false", func(t *testing.T) { 182 g := NewWithT(t) 183 rb := &controlplanev1.RolloutBefore{CertificatesExpiryDays: ptr.To[int32](10)} 184 g.Expect(collections.ShouldRolloutBefore(reconciliationTime, rb)(nil)).To(BeFalse()) 185 }) 186 t.Run("if the machine certificate expiry information is not available it should return false", func(t *testing.T) { 187 g := NewWithT(t) 188 m := &clusterv1.Machine{} 189 rb := &controlplanev1.RolloutBefore{CertificatesExpiryDays: ptr.To[int32](10)} 190 g.Expect(collections.ShouldRolloutBefore(reconciliationTime, rb)(m)).To(BeFalse()) 191 }) 192 t.Run("if the machine certificates are not going to expire within the expiry time it should return false", func(t *testing.T) { 193 g := NewWithT(t) 194 certificateExpiryTime := reconciliationTime.Add(60 * 24 * time.Hour) // certificates will expire in 60 days from 'now'. 195 m := &clusterv1.Machine{ 196 Status: clusterv1.MachineStatus{ 197 CertificatesExpiryDate: &metav1.Time{Time: certificateExpiryTime}, 198 }, 199 } 200 rb := &controlplanev1.RolloutBefore{CertificatesExpiryDays: ptr.To[int32](10)} 201 g.Expect(collections.ShouldRolloutBefore(reconciliationTime, rb)(m)).To(BeFalse()) 202 }) 203 t.Run("if machine certificates will expire within the expiry time then it should return true", func(t *testing.T) { 204 g := NewWithT(t) 205 certificateExpiryTime := reconciliationTime.Add(5 * 24 * time.Hour) // certificates will expire in 5 days from 'now'. 206 m := &clusterv1.Machine{ 207 Status: clusterv1.MachineStatus{ 208 CertificatesExpiryDate: &metav1.Time{Time: certificateExpiryTime}, 209 }, 210 } 211 rb := &controlplanev1.RolloutBefore{CertificatesExpiryDays: ptr.To[int32](10)} 212 g.Expect(collections.ShouldRolloutBefore(reconciliationTime, rb)(m)).To(BeTrue()) 213 }) 214 } 215 216 func TestHashAnnotationKey(t *testing.T) { 217 t.Run("machine with specified annotation returns true", func(t *testing.T) { 218 g := NewWithT(t) 219 m := &clusterv1.Machine{} 220 m.SetAnnotations(map[string]string{"test": ""}) 221 g.Expect(collections.HasAnnotationKey("test")(m)).To(BeTrue()) 222 }) 223 t.Run("machine with specified annotation with non-empty value returns true", func(t *testing.T) { 224 g := NewWithT(t) 225 m := &clusterv1.Machine{} 226 m.SetAnnotations(map[string]string{"test": "blue"}) 227 g.Expect(collections.HasAnnotationKey("test")(m)).To(BeTrue()) 228 }) 229 t.Run("machine without specified annotation returns false", func(t *testing.T) { 230 g := NewWithT(t) 231 m := &clusterv1.Machine{} 232 g.Expect(collections.HasAnnotationKey("foo")(m)).To(BeFalse()) 233 }) 234 } 235 236 func TestInFailureDomain(t *testing.T) { 237 t.Run("nil machine returns false", func(t *testing.T) { 238 g := NewWithT(t) 239 g.Expect(collections.InFailureDomains(ptr.To("test"))(nil)).To(BeFalse()) 240 }) 241 t.Run("machine with given failure domain returns true", func(t *testing.T) { 242 g := NewWithT(t) 243 m := &clusterv1.Machine{Spec: clusterv1.MachineSpec{FailureDomain: ptr.To("test")}} 244 g.Expect(collections.InFailureDomains(ptr.To("test"))(m)).To(BeTrue()) 245 }) 246 t.Run("machine with a different failure domain returns false", func(t *testing.T) { 247 g := NewWithT(t) 248 m := &clusterv1.Machine{Spec: clusterv1.MachineSpec{FailureDomain: ptr.To("notTest")}} 249 g.Expect(collections.InFailureDomains( 250 ptr.To("test"), 251 ptr.To("test2"), 252 ptr.To("test3"), 253 nil, 254 ptr.To("foo"))(m)).To(BeFalse()) 255 }) 256 t.Run("machine without failure domain returns false", func(t *testing.T) { 257 g := NewWithT(t) 258 m := &clusterv1.Machine{} 259 g.Expect(collections.InFailureDomains(ptr.To("test"))(m)).To(BeFalse()) 260 }) 261 t.Run("machine without failure domain returns true, when nil used for failure domain", func(t *testing.T) { 262 g := NewWithT(t) 263 m := &clusterv1.Machine{} 264 g.Expect(collections.InFailureDomains(nil)(m)).To(BeTrue()) 265 }) 266 t.Run("machine with failure domain returns true, when one of multiple failure domains match", func(t *testing.T) { 267 g := NewWithT(t) 268 m := &clusterv1.Machine{Spec: clusterv1.MachineSpec{FailureDomain: ptr.To("test")}} 269 g.Expect(collections.InFailureDomains(ptr.To("foo"), ptr.To("test"))(m)).To(BeTrue()) 270 }) 271 } 272 273 func TestActiveMachinesInCluster(t *testing.T) { 274 t.Run("machine with deletion timestamp returns false", func(t *testing.T) { 275 g := NewWithT(t) 276 m := &clusterv1.Machine{} 277 now := metav1.Now() 278 m.SetDeletionTimestamp(&now) 279 g.Expect(collections.ActiveMachines(m)).To(BeFalse()) 280 }) 281 t.Run("machine with nil deletion timestamp returns true", func(t *testing.T) { 282 g := NewWithT(t) 283 m := &clusterv1.Machine{} 284 g.Expect(collections.ActiveMachines(m)).To(BeTrue()) 285 }) 286 t.Run("machine with zero deletion timestamp returns true", func(t *testing.T) { 287 g := NewWithT(t) 288 m := &clusterv1.Machine{} 289 zero := metav1.NewTime(time.Time{}) 290 m.SetDeletionTimestamp(&zero) 291 g.Expect(collections.ActiveMachines(m)).To(BeTrue()) 292 }) 293 } 294 295 func TestMatchesKubernetesVersion(t *testing.T) { 296 t.Run("nil machine returns false", func(t *testing.T) { 297 g := NewWithT(t) 298 g.Expect(collections.MatchesKubernetesVersion("some_ver")(nil)).To(BeFalse()) 299 }) 300 301 t.Run("nil machine.Spec.Version returns false", func(t *testing.T) { 302 g := NewWithT(t) 303 machine := &clusterv1.Machine{ 304 Spec: clusterv1.MachineSpec{ 305 Version: nil, 306 }, 307 } 308 g.Expect(collections.MatchesKubernetesVersion("some_ver")(machine)).To(BeFalse()) 309 }) 310 311 t.Run("machine.Spec.Version returns true if matches", func(t *testing.T) { 312 g := NewWithT(t) 313 kversion := "some_ver" 314 machine := &clusterv1.Machine{ 315 Spec: clusterv1.MachineSpec{ 316 Version: &kversion, 317 }, 318 } 319 g.Expect(collections.MatchesKubernetesVersion("some_ver")(machine)).To(BeTrue()) 320 }) 321 322 t.Run("machine.Spec.Version returns false if does not match", func(t *testing.T) { 323 g := NewWithT(t) 324 kversion := "some_ver_2" 325 machine := &clusterv1.Machine{ 326 Spec: clusterv1.MachineSpec{ 327 Version: &kversion, 328 }, 329 } 330 g.Expect(collections.MatchesKubernetesVersion("some_ver")(machine)).To(BeFalse()) 331 }) 332 } 333 334 func TestWithVersion(t *testing.T) { 335 t.Run("nil machine returns false", func(t *testing.T) { 336 g := NewWithT(t) 337 g.Expect(collections.WithVersion()(nil)).To(BeFalse()) 338 }) 339 340 t.Run("nil machine.Spec.Version returns false", func(t *testing.T) { 341 g := NewWithT(t) 342 machine := &clusterv1.Machine{ 343 Spec: clusterv1.MachineSpec{ 344 Version: nil, 345 }, 346 } 347 g.Expect(collections.WithVersion()(machine)).To(BeFalse()) 348 }) 349 350 t.Run("empty machine.Spec.Version returns false", func(t *testing.T) { 351 g := NewWithT(t) 352 machine := &clusterv1.Machine{ 353 Spec: clusterv1.MachineSpec{ 354 Version: ptr.To(""), 355 }, 356 } 357 g.Expect(collections.WithVersion()(machine)).To(BeFalse()) 358 }) 359 360 t.Run("invalid machine.Spec.Version returns false", func(t *testing.T) { 361 g := NewWithT(t) 362 machine := &clusterv1.Machine{ 363 Spec: clusterv1.MachineSpec{ 364 Version: ptr.To("1..20"), 365 }, 366 } 367 g.Expect(collections.WithVersion()(machine)).To(BeFalse()) 368 }) 369 370 t.Run("valid machine.Spec.Version returns true", func(t *testing.T) { 371 g := NewWithT(t) 372 machine := &clusterv1.Machine{ 373 Spec: clusterv1.MachineSpec{ 374 Version: ptr.To("1.20"), 375 }, 376 } 377 g.Expect(collections.WithVersion()(machine)).To(BeTrue()) 378 }) 379 } 380 381 func TestHealthyAPIServer(t *testing.T) { 382 t.Run("nil machine returns false", func(t *testing.T) { 383 g := NewWithT(t) 384 g.Expect(collections.HealthyAPIServer()(nil)).To(BeFalse()) 385 }) 386 387 t.Run("unhealthy machine returns false", func(t *testing.T) { 388 g := NewWithT(t) 389 machine := &clusterv1.Machine{} 390 g.Expect(collections.HealthyAPIServer()(machine)).To(BeFalse()) 391 }) 392 393 t.Run("healthy machine returns true", func(t *testing.T) { 394 g := NewWithT(t) 395 machine := &clusterv1.Machine{} 396 conditions.Set(machine, conditions.TrueCondition(controlplanev1.MachineAPIServerPodHealthyCondition)) 397 g.Expect(collections.HealthyAPIServer()(machine)).To(BeTrue()) 398 }) 399 } 400 401 func TestGetFilteredMachinesForCluster(t *testing.T) { 402 g := NewWithT(t) 403 404 cluster := &clusterv1.Cluster{ 405 ObjectMeta: metav1.ObjectMeta{ 406 Namespace: "my-namespace", 407 Name: "my-cluster", 408 }, 409 } 410 411 c := fake.NewClientBuilder(). 412 WithObjects(cluster, 413 testControlPlaneMachine("first-machine"), 414 testMachine("second-machine"), 415 testMachine("third-machine")). 416 Build() 417 418 machines, err := collections.GetFilteredMachinesForCluster(ctx, c, cluster) 419 g.Expect(err).ToNot(HaveOccurred()) 420 g.Expect(machines).To(HaveLen(3)) 421 422 // Test the ControlPlaneMachines works 423 machines, err = collections.GetFilteredMachinesForCluster(ctx, c, cluster, collections.ControlPlaneMachines("my-cluster")) 424 g.Expect(err).ToNot(HaveOccurred()) 425 g.Expect(machines).To(HaveLen(1)) 426 427 // Test that the filters use AND logic instead of OR logic 428 nameFilter := func(cluster *clusterv1.Machine) bool { 429 return cluster.Name == "first-machine" 430 } 431 machines, err = collections.GetFilteredMachinesForCluster(ctx, c, cluster, collections.ControlPlaneMachines("my-cluster"), nameFilter) 432 g.Expect(err).ToNot(HaveOccurred()) 433 g.Expect(machines).To(HaveLen(1)) 434 } 435 436 func TestHasNode(t *testing.T) { 437 t.Run("nil machine returns false", func(t *testing.T) { 438 g := NewWithT(t) 439 g.Expect(collections.HasNode()(nil)).To(BeFalse()) 440 }) 441 442 t.Run("machine without node returns false", func(t *testing.T) { 443 g := NewWithT(t) 444 machine := &clusterv1.Machine{} 445 g.Expect(collections.HasNode()(machine)).To(BeFalse()) 446 }) 447 448 t.Run("machine with node returns true", func(t *testing.T) { 449 g := NewWithT(t) 450 machine := &clusterv1.Machine{ 451 Status: clusterv1.MachineStatus{NodeRef: &corev1.ObjectReference{Name: "foo"}}, 452 } 453 g.Expect(collections.HasNode()(machine)).To(BeTrue()) 454 }) 455 } 456 457 func TestHasUnhealthyControlPlaneComponentCondition(t *testing.T) { 458 t.Run("nil machine returns false", func(t *testing.T) { 459 g := NewWithT(t) 460 g.Expect(collections.HasUnhealthyControlPlaneComponents(false)(nil)).To(BeFalse()) 461 }) 462 463 t.Run("machine without node returns false", func(t *testing.T) { 464 g := NewWithT(t) 465 machine := &clusterv1.Machine{} 466 g.Expect(collections.HasUnhealthyControlPlaneComponents(false)(machine)).To(BeFalse()) 467 }) 468 469 t.Run("machine with all healthy controlPlane component conditions returns false when the Etcd is not managed", func(t *testing.T) { 470 g := NewWithT(t) 471 machine := &clusterv1.Machine{} 472 machine.Status.NodeRef = &corev1.ObjectReference{ 473 Name: "node1", 474 } 475 machine.Status.Conditions = clusterv1.Conditions{ 476 *conditions.TrueCondition(controlplanev1.MachineAPIServerPodHealthyCondition), 477 *conditions.TrueCondition(controlplanev1.MachineControllerManagerPodHealthyCondition), 478 *conditions.TrueCondition(controlplanev1.MachineSchedulerPodHealthyCondition), 479 } 480 g.Expect(collections.HasUnhealthyControlPlaneComponents(false)(machine)).To(BeFalse()) 481 }) 482 483 t.Run("machine with unhealthy 'APIServerPodHealthy' condition returns true when the Etcd is not managed", func(t *testing.T) { 484 g := NewWithT(t) 485 machine := &clusterv1.Machine{} 486 machine.Status.NodeRef = &corev1.ObjectReference{ 487 Name: "node1", 488 } 489 machine.Status.Conditions = clusterv1.Conditions{ 490 *conditions.TrueCondition(controlplanev1.MachineControllerManagerPodHealthyCondition), 491 *conditions.TrueCondition(controlplanev1.MachineSchedulerPodHealthyCondition), 492 *conditions.FalseCondition(controlplanev1.MachineAPIServerPodHealthyCondition, "", 493 clusterv1.ConditionSeverityWarning, ""), 494 } 495 g.Expect(collections.HasUnhealthyControlPlaneComponents(false)(machine)).To(BeTrue()) 496 }) 497 498 t.Run("machine with unhealthy etcd component conditions returns false when Etcd is not managed", func(t *testing.T) { 499 g := NewWithT(t) 500 machine := &clusterv1.Machine{} 501 machine.Status.NodeRef = &corev1.ObjectReference{ 502 Name: "node1", 503 } 504 machine.Status.Conditions = clusterv1.Conditions{ 505 *conditions.TrueCondition(controlplanev1.MachineAPIServerPodHealthyCondition), 506 *conditions.TrueCondition(controlplanev1.MachineControllerManagerPodHealthyCondition), 507 *conditions.TrueCondition(controlplanev1.MachineSchedulerPodHealthyCondition), 508 *conditions.FalseCondition(controlplanev1.MachineEtcdPodHealthyCondition, "", 509 clusterv1.ConditionSeverityWarning, ""), 510 *conditions.FalseCondition(controlplanev1.MachineEtcdMemberHealthyCondition, "", 511 clusterv1.ConditionSeverityWarning, ""), 512 } 513 g.Expect(collections.HasUnhealthyControlPlaneComponents(false)(machine)).To(BeFalse()) 514 }) 515 516 t.Run("machine with unhealthy etcd conditions returns true when Etcd is managed", func(t *testing.T) { 517 g := NewWithT(t) 518 machine := &clusterv1.Machine{} 519 machine.Status.NodeRef = &corev1.ObjectReference{ 520 Name: "node1", 521 } 522 machine.Status.Conditions = clusterv1.Conditions{ 523 *conditions.TrueCondition(controlplanev1.MachineAPIServerPodHealthyCondition), 524 *conditions.TrueCondition(controlplanev1.MachineControllerManagerPodHealthyCondition), 525 *conditions.TrueCondition(controlplanev1.MachineSchedulerPodHealthyCondition), 526 *conditions.FalseCondition(controlplanev1.MachineEtcdPodHealthyCondition, "", 527 clusterv1.ConditionSeverityWarning, ""), 528 *conditions.FalseCondition(controlplanev1.MachineEtcdMemberHealthyCondition, "", 529 clusterv1.ConditionSeverityWarning, ""), 530 } 531 g.Expect(collections.HasUnhealthyControlPlaneComponents(true)(machine)).To(BeTrue()) 532 }) 533 534 t.Run("machine with all healthy controlPlane and the Etcd component conditions returns false when Etcd is managed", func(t *testing.T) { 535 g := NewWithT(t) 536 machine := &clusterv1.Machine{} 537 machine.Status.NodeRef = &corev1.ObjectReference{ 538 Name: "node1", 539 } 540 machine.Status.Conditions = clusterv1.Conditions{ 541 *conditions.TrueCondition(controlplanev1.MachineAPIServerPodHealthyCondition), 542 *conditions.TrueCondition(controlplanev1.MachineControllerManagerPodHealthyCondition), 543 *conditions.TrueCondition(controlplanev1.MachineSchedulerPodHealthyCondition), 544 *conditions.TrueCondition(controlplanev1.MachineEtcdPodHealthyCondition), 545 *conditions.TrueCondition(controlplanev1.MachineEtcdMemberHealthyCondition), 546 } 547 g.Expect(collections.HasUnhealthyControlPlaneComponents(true)(machine)).To(BeFalse()) 548 }) 549 } 550 551 func testControlPlaneMachine(name string) *clusterv1.Machine { 552 owned := true 553 ownedRef := []metav1.OwnerReference{ 554 { 555 Kind: "KubeadmControlPlane", 556 Name: "my-control-plane", 557 Controller: &owned, 558 }, 559 } 560 controlPlaneMachine := testMachine(name) 561 controlPlaneMachine.ObjectMeta.Labels[clusterv1.MachineControlPlaneLabel] = "" 562 controlPlaneMachine.OwnerReferences = ownedRef 563 564 return controlPlaneMachine 565 } 566 567 func testMachine(name string) *clusterv1.Machine { 568 return &clusterv1.Machine{ 569 TypeMeta: metav1.TypeMeta{}, 570 ObjectMeta: metav1.ObjectMeta{ 571 Name: name, 572 Namespace: "my-namespace", 573 Labels: map[string]string{ 574 clusterv1.ClusterNameLabel: "my-cluster", 575 }, 576 }, 577 } 578 }