Skip to content

Commit 39189af

Browse files
authored
Merge pull request #4798 from nojnhuh/v2-machinepools
ASOAPI: propagate machinepool values to ManagedClustersAgentPools
2 parents daf5081 + 368425e commit 39189af

11 files changed

+856
-20
lines changed

exp/api/v1alpha1/azureasomanagedmachinepool_types.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@ import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2121
)
2222

23-
// AzureASOManagedMachinePoolKind is the kind for AzureASOManagedMachinePool.
24-
const AzureASOManagedMachinePoolKind = "AzureASOManagedMachinePool"
23+
const (
24+
// AzureASOManagedMachinePoolKind is the kind for AzureASOManagedMachinePool.
25+
AzureASOManagedMachinePoolKind = "AzureASOManagedMachinePool"
26+
27+
// ReplicasManagedByAKS is the value of the CAPI replica manager annotation that maps to the AKS built-in autoscaler.
28+
ReplicasManagedByAKS = "aks"
29+
)
2530

2631
// AzureASOManagedMachinePoolSpec defines the desired state of AzureASOManagedMachinePool.
2732
type AzureASOManagedMachinePoolSpec struct {

exp/controllers/azureasomanagedmachinepool_controller.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ func (r *AzureASOManagedMachinePoolReconciler) Reconcile(ctx context.Context, re
196196
return r.reconcileNormal(ctx, asoManagedMachinePool, machinePool, cluster)
197197
}
198198

199-
//nolint:unparam // these parameters will be used soon enough
200199
func (r *AzureASOManagedMachinePoolReconciler) reconcileNormal(ctx context.Context, asoManagedMachinePool *infrav1exp.AzureASOManagedMachinePool, machinePool *expv1.MachinePool, cluster *clusterv1.Cluster) (ctrl.Result, error) {
201200
ctx, log, done := tele.StartSpanWithLogger(ctx,
202201
"controllers.AzureASOManagedMachinePoolReconciler.reconcileNormal",
@@ -209,7 +208,7 @@ func (r *AzureASOManagedMachinePoolReconciler) reconcileNormal(ctx context.Conte
209208
return ctrl.Result{Requeue: true}, nil
210209
}
211210

212-
resources, err := mutators.ApplyMutators(ctx, asoManagedMachinePool.Spec.Resources)
211+
resources, err := mutators.ApplyMutators(ctx, asoManagedMachinePool.Spec.Resources, mutators.SetAgentPoolDefaults(asoManagedMachinePool, machinePool))
213212
if err != nil {
214213
return ctrl.Result{}, err
215214
}
@@ -223,7 +222,7 @@ func (r *AzureASOManagedMachinePoolReconciler) reconcileNormal(ctx context.Conte
223222
}
224223
}
225224
if agentPoolName == "" {
226-
return ctrl.Result{}, reconcile.TerminalError(fmt.Errorf("no %s ManagedClustersAgentPools defined in AzureASOManagedMachinePool spec.resources", asocontainerservicev1.GroupVersion.Group))
225+
return ctrl.Result{}, reconcile.TerminalError(mutators.ErrNoManagedClustersAgentPoolDefined)
227226
}
228227

229228
resourceReconciler := r.newResourceReconciler(asoManagedMachinePool, resources)
@@ -276,6 +275,9 @@ func (r *AzureASOManagedMachinePoolReconciler) reconcileNormal(ctx context.Conte
276275
slices.Sort(providerIDs)
277276
asoManagedMachinePool.Spec.ProviderIDList = providerIDs
278277
asoManagedMachinePool.Status.Replicas = int32(ptr.Deref(agentPool.Status.Count, 0))
278+
if machinePool.Annotations[clusterv1.ReplicasManagedByAnnotation] == infrav1exp.ReplicasManagedByAKS {
279+
machinePool.Spec.Replicas = &asoManagedMachinePool.Status.Replicas
280+
}
279281

280282
asoManagedMachinePool.Status.Ready = true
281283

exp/controllers/azureasomanagedmachinepool_controller_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ func TestAzureASOManagedMachinePoolReconcile(t *testing.T) {
354354
clusterv1.ClusterNameLabel: "cluster",
355355
},
356356
},
357+
Spec: expv1.MachinePoolSpec{
358+
Replicas: ptr.To[int32](1),
359+
},
357360
}
358361
c := fakeClientBuilder().
359362
WithObjects(asoManagedMachinePool, machinePool, cluster, asoAgentPool, asoManagedCluster).
@@ -410,6 +413,116 @@ func TestAzureASOManagedMachinePoolReconcile(t *testing.T) {
410413
g.Expect(asoManagedMachinePool.Spec.ProviderIDList).To(ConsistOf("azure://node1", "azure://node2"))
411414
g.Expect(asoManagedMachinePool.Status.Replicas).To(Equal(int32(3)))
412415
g.Expect(asoManagedMachinePool.Status.Ready).To(BeTrue())
416+
417+
g.Expect(r.Get(ctx, client.ObjectKeyFromObject(machinePool), machinePool)).To(Succeed())
418+
g.Expect(*machinePool.Spec.Replicas).To(Equal(int32(1)))
419+
})
420+
421+
t.Run("successfully reconciles normally with autoscaling", func(t *testing.T) {
422+
g := NewGomegaWithT(t)
423+
424+
cluster := &clusterv1.Cluster{
425+
ObjectMeta: metav1.ObjectMeta{
426+
Name: "cluster",
427+
Namespace: "ns",
428+
},
429+
Spec: clusterv1.ClusterSpec{
430+
ControlPlaneRef: &corev1.ObjectReference{
431+
APIVersion: infrav1exp.GroupVersion.Identifier(),
432+
Kind: infrav1exp.AzureASOManagedControlPlaneKind,
433+
},
434+
},
435+
}
436+
asoManagedCluster := &asocontainerservicev1.ManagedCluster{
437+
ObjectMeta: metav1.ObjectMeta{
438+
Name: "mc",
439+
Namespace: cluster.Namespace,
440+
},
441+
Status: asocontainerservicev1.ManagedCluster_STATUS{
442+
NodeResourceGroup: ptr.To("MC_rg"),
443+
},
444+
}
445+
asoAgentPool := &asocontainerservicev1.ManagedClustersAgentPool{
446+
ObjectMeta: metav1.ObjectMeta{
447+
Name: "ap",
448+
Namespace: cluster.Namespace,
449+
},
450+
Spec: asocontainerservicev1.ManagedClusters_AgentPool_Spec{
451+
AzureName: "pool1",
452+
Owner: &genruntime.KnownResourceReference{
453+
Name: asoManagedCluster.Name,
454+
},
455+
EnableAutoScaling: ptr.To(true),
456+
},
457+
Status: asocontainerservicev1.ManagedClusters_AgentPool_STATUS{
458+
Count: ptr.To(3),
459+
},
460+
}
461+
asoManagedMachinePool := &infrav1exp.AzureASOManagedMachinePool{
462+
ObjectMeta: metav1.ObjectMeta{
463+
Name: "ammp",
464+
Namespace: cluster.Namespace,
465+
OwnerReferences: []metav1.OwnerReference{
466+
{
467+
APIVersion: expv1.GroupVersion.Identifier(),
468+
Kind: "MachinePool",
469+
Name: "mp",
470+
},
471+
},
472+
Finalizers: []string{
473+
clusterv1.ClusterFinalizer,
474+
},
475+
},
476+
Spec: infrav1exp.AzureASOManagedMachinePoolSpec{
477+
AzureASOManagedMachinePoolTemplateResourceSpec: infrav1exp.AzureASOManagedMachinePoolTemplateResourceSpec{
478+
Resources: []runtime.RawExtension{
479+
{
480+
Raw: apJSON(g, asoAgentPool),
481+
},
482+
},
483+
},
484+
},
485+
Status: infrav1exp.AzureASOManagedMachinePoolStatus{
486+
Ready: false,
487+
},
488+
}
489+
machinePool := &expv1.MachinePool{
490+
ObjectMeta: metav1.ObjectMeta{
491+
Name: "mp",
492+
Namespace: cluster.Namespace,
493+
Labels: map[string]string{
494+
clusterv1.ClusterNameLabel: "cluster",
495+
},
496+
},
497+
}
498+
c := fakeClientBuilder().
499+
WithObjects(asoManagedMachinePool, machinePool, cluster, asoAgentPool, asoManagedCluster).
500+
Build()
501+
r := &AzureASOManagedMachinePoolReconciler{
502+
Client: c,
503+
newResourceReconciler: func(_ *infrav1exp.AzureASOManagedMachinePool, _ []*unstructured.Unstructured) resourceReconciler {
504+
return &fakeResourceReconciler{
505+
reconcileFunc: func(ctx context.Context, o client.Object) error {
506+
return nil
507+
},
508+
}
509+
},
510+
Tracker: &FakeClusterTracker{
511+
getClientFunc: func(_ context.Context, _ types.NamespacedName) (client.Client, error) {
512+
return fakeclient.NewClientBuilder().Build(), nil
513+
},
514+
},
515+
}
516+
result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedMachinePool)})
517+
g.Expect(err).NotTo(HaveOccurred())
518+
g.Expect(result).To(Equal(ctrl.Result{}))
519+
520+
g.Expect(r.Get(ctx, client.ObjectKeyFromObject(asoManagedMachinePool), asoManagedMachinePool)).To(Succeed())
521+
g.Expect(asoManagedMachinePool.Status.Replicas).To(Equal(int32(3)))
522+
g.Expect(asoManagedMachinePool.Status.Ready).To(BeTrue())
523+
524+
g.Expect(r.Get(ctx, client.ObjectKeyFromObject(machinePool), machinePool)).To(Succeed())
525+
g.Expect(*machinePool.Spec.Replicas).To(Equal(int32(3)))
413526
})
414527

415528
t.Run("successfully reconciles pause", func(t *testing.T) {

exp/mutators/azureasomanagedcontrolplane.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ import (
2525
asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001"
2626
asocontainerservicev1hub "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001/storage"
2727
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28+
"k8s.io/utils/ptr"
2829
"sigs.k8s.io/cluster-api-provider-azure/azure"
2930
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
3031
"sigs.k8s.io/cluster-api-provider-azure/util/tele"
3132
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
33+
exputil "sigs.k8s.io/cluster-api/exp/util"
3234
"sigs.k8s.io/controller-runtime/pkg/client"
3335
"sigs.k8s.io/controller-runtime/pkg/conversion"
3436
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -237,7 +239,7 @@ func setManagedClusterAgentPoolProfiles(ctx context.Context, ctrlClient client.C
237239
}
238240

239241
func agentPoolsFromManagedMachinePools(ctx context.Context, ctrlClient client.Client, clusterName string, namespace string) ([]conversion.Convertible, error) {
240-
ctx, _, done := tele.StartSpanWithLogger(ctx, "mutators.agentPoolsFromManagedMachinePools")
242+
ctx, log, done := tele.StartSpanWithLogger(ctx, "mutators.agentPoolsFromManagedMachinePools")
241243
defer done()
242244

243245
asoManagedMachinePools := &infrav1exp.AzureASOManagedMachinePoolList{}
@@ -253,7 +255,18 @@ func agentPoolsFromManagedMachinePools(ctx context.Context, ctrlClient client.Cl
253255

254256
var agentPools []conversion.Convertible
255257
for _, asoManagedMachinePool := range asoManagedMachinePools.Items {
256-
resources, err := ApplyMutators(ctx, asoManagedMachinePool.Spec.Resources)
258+
machinePool, err := exputil.GetOwnerMachinePool(ctx, ctrlClient, asoManagedMachinePool.ObjectMeta)
259+
if err != nil {
260+
return nil, err
261+
}
262+
if machinePool == nil {
263+
log.V(2).Info("Waiting for MachinePool Controller to set OwnerRef on AzureASOManagedMachinePool")
264+
return nil, nil
265+
}
266+
267+
resources, err := ApplyMutators(ctx, asoManagedMachinePool.Spec.Resources,
268+
SetAgentPoolDefaults(ptr.To(asoManagedMachinePool), machinePool),
269+
)
257270
if err != nil {
258271
return nil, err
259272
}

exp/mutators/azureasomanagedcontrolplane_test.go

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"k8s.io/utils/ptr"
3232
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
3333
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
34+
expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
3435
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
3536
"sigs.k8s.io/controller-runtime/pkg/conversion"
3637
)
@@ -494,6 +495,7 @@ func TestSetManagedClusterAgentPoolProfiles(t *testing.T) {
494495
s := runtime.NewScheme()
495496
g.Expect(asocontainerservicev1.AddToScheme(s)).To(Succeed())
496497
g.Expect(infrav1exp.AddToScheme(s)).To(Succeed())
498+
g.Expect(expv1.AddToScheme(s)).To(Succeed())
497499
fakeClientBuilder := func() *fakeclient.ClientBuilder {
498500
return fakeclient.NewClientBuilder().WithScheme(s)
499501
}
@@ -558,6 +560,13 @@ func TestSetManagedClusterAgentPoolProfiles(t *testing.T) {
558560
Labels: map[string]string{
559561
clusterv1.ClusterNameLabel: "not-" + clusterName,
560562
},
563+
OwnerReferences: []metav1.OwnerReference{
564+
{
565+
APIVersion: expv1.GroupVersion.Identifier(),
566+
Kind: "MachinePool",
567+
Name: "wrong-label",
568+
},
569+
},
561570
},
562571
Spec: infrav1exp.AzureASOManagedMachinePoolSpec{
563572
AzureASOManagedMachinePoolTemplateResourceSpec: infrav1exp.AzureASOManagedMachinePoolTemplateResourceSpec{
@@ -580,6 +589,13 @@ func TestSetManagedClusterAgentPoolProfiles(t *testing.T) {
580589
Labels: map[string]string{
581590
clusterv1.ClusterNameLabel: clusterName,
582591
},
592+
OwnerReferences: []metav1.OwnerReference{
593+
{
594+
APIVersion: expv1.GroupVersion.Identifier(),
595+
Kind: "MachinePool",
596+
Name: "wrong-namespace",
597+
},
598+
},
583599
},
584600
Spec: infrav1exp.AzureASOManagedMachinePoolSpec{
585601
AzureASOManagedMachinePoolTemplateResourceSpec: infrav1exp.AzureASOManagedMachinePoolTemplateResourceSpec{
@@ -602,6 +618,13 @@ func TestSetManagedClusterAgentPoolProfiles(t *testing.T) {
602618
Labels: map[string]string{
603619
clusterv1.ClusterNameLabel: clusterName,
604620
},
621+
OwnerReferences: []metav1.OwnerReference{
622+
{
623+
APIVersion: expv1.GroupVersion.Identifier(),
624+
Kind: "MachinePool",
625+
Name: "pool0",
626+
},
627+
},
605628
},
606629
Spec: infrav1exp.AzureASOManagedMachinePoolSpec{
607630
AzureASOManagedMachinePoolTemplateResourceSpec: infrav1exp.AzureASOManagedMachinePoolTemplateResourceSpec{
@@ -624,6 +647,13 @@ func TestSetManagedClusterAgentPoolProfiles(t *testing.T) {
624647
Labels: map[string]string{
625648
clusterv1.ClusterNameLabel: clusterName,
626649
},
650+
OwnerReferences: []metav1.OwnerReference{
651+
{
652+
APIVersion: expv1.GroupVersion.Identifier(),
653+
Kind: "MachinePool",
654+
Name: "pool1",
655+
},
656+
},
627657
},
628658
Spec: infrav1exp.AzureASOManagedMachinePoolSpec{
629659
AzureASOManagedMachinePoolTemplateResourceSpec: infrav1exp.AzureASOManagedMachinePoolTemplateResourceSpec{
@@ -641,17 +671,51 @@ func TestSetManagedClusterAgentPoolProfiles(t *testing.T) {
641671
},
642672
},
643673
}
674+
machinePools := &expv1.MachinePoolList{
675+
Items: []expv1.MachinePool{
676+
{
677+
ObjectMeta: metav1.ObjectMeta{
678+
Namespace: namespace,
679+
Name: "wrong-label",
680+
},
681+
},
682+
{
683+
ObjectMeta: metav1.ObjectMeta{
684+
Namespace: "not-" + namespace,
685+
Name: "wrong-namespace",
686+
},
687+
},
688+
{
689+
ObjectMeta: metav1.ObjectMeta{
690+
Namespace: namespace,
691+
Name: "pool0",
692+
},
693+
Spec: expv1.MachinePoolSpec{
694+
Replicas: ptr.To[int32](1),
695+
},
696+
},
697+
{
698+
ObjectMeta: metav1.ObjectMeta{
699+
Namespace: namespace,
700+
Name: "pool1",
701+
},
702+
Spec: expv1.MachinePoolSpec{
703+
Replicas: ptr.To[int32](2),
704+
},
705+
},
706+
},
707+
}
644708
expected := &asocontainerservicev1.ManagedCluster{
645709
Spec: asocontainerservicev1.ManagedCluster_Spec{
646710
AgentPoolProfiles: []asocontainerservicev1.ManagedClusterAgentPoolProfile{
647-
{Name: ptr.To("azpool0")},
648-
{Name: ptr.To("azpool1")},
711+
{Name: ptr.To("azpool0"), Count: ptr.To(1)},
712+
{Name: ptr.To("azpool1"), Count: ptr.To(2)},
649713
},
650714
},
651715
}
652716

653717
c := fakeClientBuilder().
654-
WithLists(asoManagedMachinePools).
718+
WithLists(asoManagedMachinePools, machinePools).
655719
Build()
656720

657721
cluster := &clusterv1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: clusterName}}
@@ -770,3 +834,11 @@ func mcUnstructured(g Gomega, mc *asocontainerservicev1.ManagedCluster) *unstruc
770834
g.Expect(s.Convert(mc, u, nil)).To(Succeed())
771835
return u
772836
}
837+
838+
func apUnstructured(g Gomega, ap *asocontainerservicev1.ManagedClustersAgentPool) *unstructured.Unstructured {
839+
s := runtime.NewScheme()
840+
g.Expect(asocontainerservicev1.AddToScheme(s)).To(Succeed())
841+
u := &unstructured.Unstructured{}
842+
g.Expect(s.Convert(ap, u, nil)).To(Succeed())
843+
return u
844+
}

0 commit comments

Comments
 (0)