sigs.k8s.io/cluster-api-provider-azure@v1.17.0/controllers/azureasomanagedmachinepool_controller_test.go (about) 1 /* 2 Copyright 2024 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 controllers 18 19 import ( 20 "context" 21 "encoding/json" 22 "testing" 23 "time" 24 25 asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" 26 "github.com/Azure/azure-service-operator/v2/pkg/genruntime" 27 . "github.com/onsi/gomega" 28 corev1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 31 "k8s.io/apimachinery/pkg/runtime" 32 "k8s.io/apimachinery/pkg/types" 33 "k8s.io/utils/ptr" 34 infrav1alpha "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha1" 35 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 36 clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" 37 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 38 ctrl "sigs.k8s.io/controller-runtime" 39 "sigs.k8s.io/controller-runtime/pkg/client" 40 fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" 41 ) 42 43 type FakeClusterTracker struct { 44 getClientFunc func(context.Context, types.NamespacedName) (client.Client, error) 45 } 46 47 func (c *FakeClusterTracker) GetClient(ctx context.Context, name types.NamespacedName) (client.Client, error) { 48 if c.getClientFunc == nil { 49 return nil, nil 50 } 51 return c.getClientFunc(ctx, name) 52 } 53 54 func TestAzureASOManagedMachinePoolReconcile(t *testing.T) { 55 ctx := context.Background() 56 57 s := runtime.NewScheme() 58 sb := runtime.NewSchemeBuilder( 59 infrav1alpha.AddToScheme, 60 clusterv1.AddToScheme, 61 expv1.AddToScheme, 62 asocontainerservicev1.AddToScheme, 63 ) 64 NewGomegaWithT(t).Expect(sb.AddToScheme(s)).To(Succeed()) 65 fakeClientBuilder := func() *fakeclient.ClientBuilder { 66 return fakeclient.NewClientBuilder(). 67 WithScheme(s). 68 WithStatusSubresource(&infrav1alpha.AzureASOManagedMachinePool{}) 69 } 70 71 t.Run("AzureASOManagedMachinePool does not exist", func(t *testing.T) { 72 g := NewGomegaWithT(t) 73 74 c := fakeClientBuilder(). 75 Build() 76 r := &AzureASOManagedMachinePoolReconciler{ 77 Client: c, 78 } 79 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "doesn't", Name: "exist"}}) 80 g.Expect(err).NotTo(HaveOccurred()) 81 g.Expect(result).To(Equal(ctrl.Result{})) 82 }) 83 84 t.Run("MachinePool does not exist", func(t *testing.T) { 85 g := NewGomegaWithT(t) 86 87 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 88 ObjectMeta: metav1.ObjectMeta{ 89 Name: "ammp", 90 Namespace: "ns", 91 OwnerReferences: []metav1.OwnerReference{ 92 { 93 APIVersion: expv1.GroupVersion.Identifier(), 94 Kind: "MachinePool", 95 Name: "mp", 96 }, 97 }, 98 }, 99 } 100 c := fakeClientBuilder(). 101 WithObjects(asoManagedMachinePool). 102 Build() 103 r := &AzureASOManagedMachinePoolReconciler{ 104 Client: c, 105 } 106 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)}) 107 g.Expect(err).To(HaveOccurred()) 108 g.Expect(err.Error()).To(ContainSubstring("machinepools.cluster.x-k8s.io \"mp\" not found")) 109 g.Expect(result).To(Equal(ctrl.Result{})) 110 }) 111 112 t.Run("Cluster does not exist", func(t *testing.T) { 113 g := NewGomegaWithT(t) 114 115 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 116 ObjectMeta: metav1.ObjectMeta{ 117 Name: "ammp", 118 Namespace: "ns", 119 OwnerReferences: []metav1.OwnerReference{ 120 { 121 APIVersion: expv1.GroupVersion.Identifier(), 122 Kind: "MachinePool", 123 Name: "mp", 124 }, 125 }, 126 }, 127 } 128 machinePool := &expv1.MachinePool{ 129 ObjectMeta: metav1.ObjectMeta{ 130 Name: "mp", 131 Namespace: asoManagedMachinePool.Namespace, 132 Labels: map[string]string{ 133 clusterv1.ClusterNameLabel: "cluster", 134 }, 135 }, 136 } 137 c := fakeClientBuilder(). 138 WithObjects(asoManagedMachinePool, machinePool). 139 Build() 140 r := &AzureASOManagedMachinePoolReconciler{ 141 Client: c, 142 } 143 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)}) 144 g.Expect(err).To(HaveOccurred()) 145 g.Expect(err.Error()).To(ContainSubstring("clusters.cluster.x-k8s.io \"cluster\" not found")) 146 g.Expect(result).To(Equal(ctrl.Result{})) 147 }) 148 149 t.Run("adds a finalizer and block-move annotation", func(t *testing.T) { 150 g := NewGomegaWithT(t) 151 152 cluster := &clusterv1.Cluster{ 153 ObjectMeta: metav1.ObjectMeta{ 154 Name: "cluster", 155 Namespace: "ns", 156 }, 157 Spec: clusterv1.ClusterSpec{ 158 ControlPlaneRef: &corev1.ObjectReference{ 159 APIVersion: infrav1alpha.GroupVersion.Identifier(), 160 Kind: infrav1alpha.AzureASOManagedControlPlaneKind, 161 }, 162 }, 163 } 164 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 165 ObjectMeta: metav1.ObjectMeta{ 166 Name: "ammp", 167 Namespace: cluster.Namespace, 168 OwnerReferences: []metav1.OwnerReference{ 169 { 170 APIVersion: expv1.GroupVersion.Identifier(), 171 Kind: "MachinePool", 172 Name: "mp", 173 }, 174 }, 175 }, 176 } 177 machinePool := &expv1.MachinePool{ 178 ObjectMeta: metav1.ObjectMeta{ 179 Name: "mp", 180 Namespace: cluster.Namespace, 181 Labels: map[string]string{ 182 clusterv1.ClusterNameLabel: "cluster", 183 }, 184 }, 185 } 186 c := fakeClientBuilder(). 187 WithObjects(asoManagedMachinePool, machinePool, cluster). 188 Build() 189 r := &AzureASOManagedMachinePoolReconciler{ 190 Client: c, 191 } 192 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)}) 193 g.Expect(err).NotTo(HaveOccurred()) 194 g.Expect(result).To(Equal(ctrl.Result{Requeue: true})) 195 196 g.Expect(c.Get(ctx, client.ObjectKeyFromObject(asoManagedMachinePool), asoManagedMachinePool)).To(Succeed()) 197 g.Expect(asoManagedMachinePool.GetFinalizers()).To(ContainElement(clusterv1.ClusterFinalizer)) 198 g.Expect(asoManagedMachinePool.GetAnnotations()).To(HaveKey(clusterctlv1.BlockMoveAnnotation)) 199 }) 200 201 t.Run("reconciles resources that are not ready", func(t *testing.T) { 202 g := NewGomegaWithT(t) 203 204 cluster := &clusterv1.Cluster{ 205 ObjectMeta: metav1.ObjectMeta{ 206 Name: "cluster", 207 Namespace: "ns", 208 }, 209 Spec: clusterv1.ClusterSpec{ 210 ControlPlaneRef: &corev1.ObjectReference{ 211 APIVersion: infrav1alpha.GroupVersion.Identifier(), 212 Kind: infrav1alpha.AzureASOManagedControlPlaneKind, 213 }, 214 }, 215 } 216 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 217 ObjectMeta: metav1.ObjectMeta{ 218 Name: "ammp", 219 Namespace: cluster.Namespace, 220 OwnerReferences: []metav1.OwnerReference{ 221 { 222 APIVersion: expv1.GroupVersion.Identifier(), 223 Kind: "MachinePool", 224 Name: "mp", 225 }, 226 }, 227 Finalizers: []string{ 228 clusterv1.ClusterFinalizer, 229 }, 230 Annotations: map[string]string{ 231 clusterctlv1.BlockMoveAnnotation: "true", 232 }, 233 }, 234 Spec: infrav1alpha.AzureASOManagedMachinePoolSpec{ 235 AzureASOManagedMachinePoolTemplateResourceSpec: infrav1alpha.AzureASOManagedMachinePoolTemplateResourceSpec{ 236 Resources: []runtime.RawExtension{ 237 { 238 Raw: apJSON(g, &asocontainerservicev1.ManagedClustersAgentPool{ 239 ObjectMeta: metav1.ObjectMeta{ 240 Name: "ap", 241 }, 242 }), 243 }, 244 }, 245 }, 246 }, 247 Status: infrav1alpha.AzureASOManagedMachinePoolStatus{ 248 Ready: true, 249 }, 250 } 251 machinePool := &expv1.MachinePool{ 252 ObjectMeta: metav1.ObjectMeta{ 253 Name: "mp", 254 Namespace: cluster.Namespace, 255 Labels: map[string]string{ 256 clusterv1.ClusterNameLabel: "cluster", 257 }, 258 }, 259 } 260 c := fakeClientBuilder(). 261 WithObjects(asoManagedMachinePool, machinePool, cluster). 262 Build() 263 r := &AzureASOManagedMachinePoolReconciler{ 264 Client: c, 265 newResourceReconciler: func(asoManagedMachinePool *infrav1alpha.AzureASOManagedMachinePool, _ []*unstructured.Unstructured) resourceReconciler { 266 return &fakeResourceReconciler{ 267 owner: asoManagedMachinePool, 268 reconcileFunc: func(ctx context.Context, o client.Object) error { 269 asoManagedMachinePool.SetResourceStatuses([]infrav1alpha.ResourceStatus{ 270 {Ready: true}, 271 {Ready: false}, 272 {Ready: true}, 273 }) 274 return nil 275 }, 276 } 277 }, 278 } 279 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)}) 280 g.Expect(err).NotTo(HaveOccurred()) 281 g.Expect(result).To(Equal(ctrl.Result{})) 282 283 g.Expect(r.Get(ctx, client.ObjectKeyFromObject(asoManagedMachinePool), asoManagedMachinePool)).To(Succeed()) 284 g.Expect(asoManagedMachinePool.Status.Ready).To(BeFalse()) 285 }) 286 287 t.Run("successfully reconciles normally", func(t *testing.T) { 288 g := NewGomegaWithT(t) 289 290 cluster := &clusterv1.Cluster{ 291 ObjectMeta: metav1.ObjectMeta{ 292 Name: "cluster", 293 Namespace: "ns", 294 }, 295 Spec: clusterv1.ClusterSpec{ 296 ControlPlaneRef: &corev1.ObjectReference{ 297 APIVersion: infrav1alpha.GroupVersion.Identifier(), 298 Kind: infrav1alpha.AzureASOManagedControlPlaneKind, 299 }, 300 }, 301 } 302 asoManagedCluster := &asocontainerservicev1.ManagedCluster{ 303 ObjectMeta: metav1.ObjectMeta{ 304 Name: "mc", 305 Namespace: cluster.Namespace, 306 }, 307 Status: asocontainerservicev1.ManagedCluster_STATUS{ 308 NodeResourceGroup: ptr.To("MC_rg"), 309 }, 310 } 311 asoAgentPool := &asocontainerservicev1.ManagedClustersAgentPool{ 312 ObjectMeta: metav1.ObjectMeta{ 313 Name: "ap", 314 Namespace: cluster.Namespace, 315 }, 316 Spec: asocontainerservicev1.ManagedClusters_AgentPool_Spec{ 317 AzureName: "pool1", 318 Owner: &genruntime.KnownResourceReference{ 319 Name: asoManagedCluster.Name, 320 }, 321 }, 322 Status: asocontainerservicev1.ManagedClusters_AgentPool_STATUS{ 323 Count: ptr.To(3), 324 }, 325 } 326 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 327 ObjectMeta: metav1.ObjectMeta{ 328 Name: "ammp", 329 Namespace: cluster.Namespace, 330 OwnerReferences: []metav1.OwnerReference{ 331 { 332 APIVersion: expv1.GroupVersion.Identifier(), 333 Kind: "MachinePool", 334 Name: "mp", 335 }, 336 }, 337 Finalizers: []string{ 338 clusterv1.ClusterFinalizer, 339 }, 340 Annotations: map[string]string{ 341 clusterctlv1.BlockMoveAnnotation: "true", 342 }, 343 }, 344 Spec: infrav1alpha.AzureASOManagedMachinePoolSpec{ 345 AzureASOManagedMachinePoolTemplateResourceSpec: infrav1alpha.AzureASOManagedMachinePoolTemplateResourceSpec{ 346 Resources: []runtime.RawExtension{ 347 { 348 Raw: apJSON(g, asoAgentPool), 349 }, 350 }, 351 }, 352 }, 353 Status: infrav1alpha.AzureASOManagedMachinePoolStatus{ 354 Ready: false, 355 }, 356 } 357 machinePool := &expv1.MachinePool{ 358 ObjectMeta: metav1.ObjectMeta{ 359 Name: "mp", 360 Namespace: cluster.Namespace, 361 Labels: map[string]string{ 362 clusterv1.ClusterNameLabel: "cluster", 363 }, 364 }, 365 Spec: expv1.MachinePoolSpec{ 366 Replicas: ptr.To[int32](1), 367 }, 368 } 369 c := fakeClientBuilder(). 370 WithObjects(asoManagedMachinePool, machinePool, cluster, asoAgentPool, asoManagedCluster). 371 Build() 372 r := &AzureASOManagedMachinePoolReconciler{ 373 Client: c, 374 newResourceReconciler: func(_ *infrav1alpha.AzureASOManagedMachinePool, _ []*unstructured.Unstructured) resourceReconciler { 375 return &fakeResourceReconciler{ 376 reconcileFunc: func(ctx context.Context, o client.Object) error { 377 return nil 378 }, 379 } 380 }, 381 Tracker: &FakeClusterTracker{ 382 getClientFunc: func(_ context.Context, _ types.NamespacedName) (client.Client, error) { 383 return fakeclient.NewClientBuilder(). 384 WithObjects( 385 &corev1.Node{ 386 ObjectMeta: metav1.ObjectMeta{ 387 Name: "node1", 388 Labels: expectedNodeLabels(asoAgentPool.AzureName(), *asoManagedCluster.Status.NodeResourceGroup), 389 }, 390 Spec: corev1.NodeSpec{ 391 ProviderID: "azure://node1", 392 }, 393 }, 394 &corev1.Node{ 395 ObjectMeta: metav1.ObjectMeta{ 396 Name: "node2", 397 Labels: expectedNodeLabels(asoAgentPool.AzureName(), *asoManagedCluster.Status.NodeResourceGroup), 398 }, 399 Spec: corev1.NodeSpec{ 400 ProviderID: "azure://node2", 401 }, 402 }, 403 &corev1.Node{ 404 ObjectMeta: metav1.ObjectMeta{ 405 Name: "no-labels", 406 }, 407 Spec: corev1.NodeSpec{ 408 ProviderID: "azure://node3", 409 }, 410 }, 411 ). 412 Build(), nil 413 }, 414 }, 415 } 416 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)}) 417 g.Expect(err).NotTo(HaveOccurred()) 418 g.Expect(result).To(Equal(ctrl.Result{})) 419 420 g.Expect(r.Get(ctx, client.ObjectKeyFromObject(asoManagedMachinePool), asoManagedMachinePool)).To(Succeed()) 421 g.Expect(asoManagedMachinePool.Spec.ProviderIDList).To(ConsistOf("azure://node1", "azure://node2")) 422 g.Expect(asoManagedMachinePool.Status.Replicas).To(Equal(int32(3))) 423 g.Expect(asoManagedMachinePool.Status.Ready).To(BeTrue()) 424 425 g.Expect(r.Get(ctx, client.ObjectKeyFromObject(machinePool), machinePool)).To(Succeed()) 426 g.Expect(*machinePool.Spec.Replicas).To(Equal(int32(1))) 427 }) 428 429 t.Run("successfully reconciles normally with autoscaling", func(t *testing.T) { 430 g := NewGomegaWithT(t) 431 432 cluster := &clusterv1.Cluster{ 433 ObjectMeta: metav1.ObjectMeta{ 434 Name: "cluster", 435 Namespace: "ns", 436 }, 437 Spec: clusterv1.ClusterSpec{ 438 ControlPlaneRef: &corev1.ObjectReference{ 439 APIVersion: infrav1alpha.GroupVersion.Identifier(), 440 Kind: infrav1alpha.AzureASOManagedControlPlaneKind, 441 }, 442 }, 443 } 444 asoManagedCluster := &asocontainerservicev1.ManagedCluster{ 445 ObjectMeta: metav1.ObjectMeta{ 446 Name: "mc", 447 Namespace: cluster.Namespace, 448 }, 449 Status: asocontainerservicev1.ManagedCluster_STATUS{ 450 NodeResourceGroup: ptr.To("MC_rg"), 451 }, 452 } 453 asoAgentPool := &asocontainerservicev1.ManagedClustersAgentPool{ 454 ObjectMeta: metav1.ObjectMeta{ 455 Name: "ap", 456 Namespace: cluster.Namespace, 457 }, 458 Spec: asocontainerservicev1.ManagedClusters_AgentPool_Spec{ 459 AzureName: "pool1", 460 Owner: &genruntime.KnownResourceReference{ 461 Name: asoManagedCluster.Name, 462 }, 463 EnableAutoScaling: ptr.To(true), 464 }, 465 Status: asocontainerservicev1.ManagedClusters_AgentPool_STATUS{ 466 Count: ptr.To(3), 467 }, 468 } 469 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 470 ObjectMeta: metav1.ObjectMeta{ 471 Name: "ammp", 472 Namespace: cluster.Namespace, 473 OwnerReferences: []metav1.OwnerReference{ 474 { 475 APIVersion: expv1.GroupVersion.Identifier(), 476 Kind: "MachinePool", 477 Name: "mp", 478 }, 479 }, 480 Finalizers: []string{ 481 clusterv1.ClusterFinalizer, 482 }, 483 Annotations: map[string]string{ 484 clusterctlv1.BlockMoveAnnotation: "true", 485 }, 486 }, 487 Spec: infrav1alpha.AzureASOManagedMachinePoolSpec{ 488 AzureASOManagedMachinePoolTemplateResourceSpec: infrav1alpha.AzureASOManagedMachinePoolTemplateResourceSpec{ 489 Resources: []runtime.RawExtension{ 490 { 491 Raw: apJSON(g, asoAgentPool), 492 }, 493 }, 494 }, 495 }, 496 Status: infrav1alpha.AzureASOManagedMachinePoolStatus{ 497 Ready: false, 498 }, 499 } 500 machinePool := &expv1.MachinePool{ 501 ObjectMeta: metav1.ObjectMeta{ 502 Name: "mp", 503 Namespace: cluster.Namespace, 504 Labels: map[string]string{ 505 clusterv1.ClusterNameLabel: "cluster", 506 }, 507 }, 508 } 509 c := fakeClientBuilder(). 510 WithObjects(asoManagedMachinePool, machinePool, cluster, asoAgentPool, asoManagedCluster). 511 Build() 512 r := &AzureASOManagedMachinePoolReconciler{ 513 Client: c, 514 newResourceReconciler: func(_ *infrav1alpha.AzureASOManagedMachinePool, _ []*unstructured.Unstructured) resourceReconciler { 515 return &fakeResourceReconciler{ 516 reconcileFunc: func(ctx context.Context, o client.Object) error { 517 return nil 518 }, 519 } 520 }, 521 Tracker: &FakeClusterTracker{ 522 getClientFunc: func(_ context.Context, _ types.NamespacedName) (client.Client, error) { 523 return fakeclient.NewClientBuilder().Build(), nil 524 }, 525 }, 526 } 527 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)}) 528 g.Expect(err).NotTo(HaveOccurred()) 529 g.Expect(result).To(Equal(ctrl.Result{})) 530 531 g.Expect(r.Get(ctx, client.ObjectKeyFromObject(asoManagedMachinePool), asoManagedMachinePool)).To(Succeed()) 532 g.Expect(asoManagedMachinePool.Status.Replicas).To(Equal(int32(3))) 533 g.Expect(asoManagedMachinePool.Status.Ready).To(BeTrue()) 534 535 g.Expect(r.Get(ctx, client.ObjectKeyFromObject(machinePool), machinePool)).To(Succeed()) 536 g.Expect(*machinePool.Spec.Replicas).To(Equal(int32(3))) 537 }) 538 539 t.Run("successfully reconciles pause", func(t *testing.T) { 540 g := NewGomegaWithT(t) 541 542 cluster := &clusterv1.Cluster{ 543 ObjectMeta: metav1.ObjectMeta{ 544 Name: "cluster", 545 Namespace: "ns", 546 }, 547 Spec: clusterv1.ClusterSpec{ 548 Paused: true, 549 ControlPlaneRef: &corev1.ObjectReference{ 550 APIVersion: infrav1alpha.GroupVersion.Identifier(), 551 Kind: infrav1alpha.AzureASOManagedControlPlaneKind, 552 }, 553 }, 554 } 555 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 556 ObjectMeta: metav1.ObjectMeta{ 557 Name: "ammp", 558 Namespace: cluster.Namespace, 559 OwnerReferences: []metav1.OwnerReference{ 560 { 561 APIVersion: expv1.GroupVersion.Identifier(), 562 Kind: "MachinePool", 563 Name: "mp", 564 }, 565 }, 566 Annotations: map[string]string{ 567 clusterctlv1.BlockMoveAnnotation: "true", 568 }, 569 }, 570 } 571 machinePool := &expv1.MachinePool{ 572 ObjectMeta: metav1.ObjectMeta{ 573 Name: "mp", 574 Namespace: cluster.Namespace, 575 Labels: map[string]string{ 576 clusterv1.ClusterNameLabel: "cluster", 577 }, 578 }, 579 } 580 c := fakeClientBuilder(). 581 WithObjects(asoManagedMachinePool, machinePool, cluster). 582 Build() 583 r := &AzureASOManagedMachinePoolReconciler{ 584 Client: c, 585 newResourceReconciler: func(_ *infrav1alpha.AzureASOManagedMachinePool, _ []*unstructured.Unstructured) resourceReconciler { 586 return &fakeResourceReconciler{ 587 pauseFunc: func(_ context.Context, _ client.Object) error { 588 return nil 589 }, 590 } 591 }, 592 } 593 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)}) 594 g.Expect(err).NotTo(HaveOccurred()) 595 g.Expect(result).To(Equal(ctrl.Result{})) 596 597 g.Expect(c.Get(ctx, client.ObjectKeyFromObject(asoManagedMachinePool), asoManagedMachinePool)).To(Succeed()) 598 g.Expect(asoManagedMachinePool.GetAnnotations()).NotTo(HaveKey(clusterctlv1.BlockMoveAnnotation)) 599 }) 600 601 t.Run("successfully reconciles delete", func(t *testing.T) { 602 g := NewGomegaWithT(t) 603 604 cluster := &clusterv1.Cluster{ 605 ObjectMeta: metav1.ObjectMeta{ 606 Name: "cluster", 607 Namespace: "ns", 608 }, 609 Spec: clusterv1.ClusterSpec{ 610 ControlPlaneRef: &corev1.ObjectReference{ 611 APIVersion: infrav1alpha.GroupVersion.Identifier(), 612 Kind: infrav1alpha.AzureASOManagedControlPlaneKind, 613 }, 614 }, 615 } 616 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 617 ObjectMeta: metav1.ObjectMeta{ 618 Name: "ammp", 619 Namespace: cluster.Namespace, 620 OwnerReferences: []metav1.OwnerReference{ 621 { 622 APIVersion: expv1.GroupVersion.Identifier(), 623 Kind: "MachinePool", 624 Name: "mp", 625 }, 626 }, 627 DeletionTimestamp: &metav1.Time{Time: time.Date(1, 0, 0, 0, 0, 0, 0, time.UTC)}, 628 Finalizers: []string{ 629 clusterv1.ClusterFinalizer, 630 }, 631 }, 632 } 633 machinePool := &expv1.MachinePool{ 634 ObjectMeta: metav1.ObjectMeta{ 635 Name: "mp", 636 Namespace: cluster.Namespace, 637 Labels: map[string]string{ 638 clusterv1.ClusterNameLabel: "cluster", 639 }, 640 }, 641 } 642 c := fakeClientBuilder(). 643 WithObjects(asoManagedMachinePool, machinePool, cluster). 644 Build() 645 r := &AzureASOManagedMachinePoolReconciler{ 646 Client: c, 647 newResourceReconciler: func(_ *infrav1alpha.AzureASOManagedMachinePool, _ []*unstructured.Unstructured) resourceReconciler { 648 return &fakeResourceReconciler{ 649 deleteFunc: func(ctx context.Context, o client.Object) error { 650 return nil 651 }, 652 } 653 }, 654 } 655 result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)}) 656 g.Expect(err).NotTo(HaveOccurred()) 657 g.Expect(result).To(Equal(ctrl.Result{})) 658 }) 659 } 660 661 func apJSON(g Gomega, ap *asocontainerservicev1.ManagedClustersAgentPool) []byte { 662 ap.SetGroupVersionKind(asocontainerservicev1.GroupVersion.WithKind("ManagedClustersAgentPool")) 663 j, err := json.Marshal(ap) 664 g.Expect(err).NotTo(HaveOccurred()) 665 return j 666 }