sigs.k8s.io/cluster-api-provider-azure@v1.17.0/controllers/agentpooladopt_controller.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 "fmt" 22 23 asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime" 27 "k8s.io/utils/ptr" 28 infrav1alpha "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha1" 29 "sigs.k8s.io/cluster-api-provider-azure/util/tele" 30 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 31 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 32 ctrl "sigs.k8s.io/controller-runtime" 33 "sigs.k8s.io/controller-runtime/pkg/client" 34 "sigs.k8s.io/controller-runtime/pkg/controller" 35 "sigs.k8s.io/controller-runtime/pkg/event" 36 "sigs.k8s.io/controller-runtime/pkg/predicate" 37 ) 38 39 // AgentPoolAdoptReconciler adopts ASO ManagedClustersAgentPool resources into a CAPI Cluster. 40 type AgentPoolAdoptReconciler struct { 41 client.Client 42 } 43 44 // SetupWithManager sets up the controller with the Manager. 45 func (r *AgentPoolAdoptReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { 46 _, err := ctrl.NewControllerManagedBy(mgr). 47 WithOptions(options). 48 For(&asocontainerservicev1.ManagedClustersAgentPool{}). 49 WithEventFilter(predicate.Funcs{ 50 UpdateFunc: func(ev event.UpdateEvent) bool { 51 return ev.ObjectOld.GetAnnotations()[adoptAnnotation] != ev.ObjectNew.GetAnnotations()[adoptAnnotation] 52 }, 53 DeleteFunc: func(_ event.DeleteEvent) bool { return false }, 54 }). 55 Build(r) 56 if err != nil { 57 return err 58 } 59 60 return nil 61 } 62 63 // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machinepools,verbs=create 64 65 // Reconcile reconciles an AzureASOManagedCluster. 66 func (r *AgentPoolAdoptReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, resultErr error) { 67 ctx, log, done := tele.StartSpanWithLogger(ctx, 68 "controllers.AgentPoolAdoptReconciler.Reconcile", 69 tele.KVP("namespace", req.Namespace), 70 tele.KVP("name", req.Name), 71 tele.KVP("kind", "ManagedCluster"), 72 ) 73 defer done() 74 75 agentPool := &asocontainerservicev1.ManagedClustersAgentPool{} 76 err := r.Get(ctx, req.NamespacedName, agentPool) 77 if err != nil { 78 return ctrl.Result{}, client.IgnoreNotFound(err) 79 } 80 81 if agentPool.GetAnnotations()[adoptAnnotation] != adoptAnnotationValue { 82 return ctrl.Result{}, nil 83 } 84 85 for _, owner := range agentPool.GetOwnerReferences() { 86 if owner.APIVersion == infrav1alpha.GroupVersion.Identifier() && 87 owner.Kind == infrav1alpha.AzureASOManagedMachinePoolKind { 88 return ctrl.Result{}, nil 89 } 90 } 91 92 log.Info("adopting") 93 94 namespace := agentPool.Namespace 95 96 // filter down to what will be persisted in the AzureASOManagedMachinePool 97 agentPool = &asocontainerservicev1.ManagedClustersAgentPool{ 98 TypeMeta: metav1.TypeMeta{ 99 APIVersion: asocontainerservicev1.GroupVersion.Identifier(), 100 Kind: "ManagedClustersAgentPool", 101 }, 102 ObjectMeta: metav1.ObjectMeta{ 103 Name: agentPool.Name, 104 }, 105 Spec: agentPool.Spec, 106 } 107 108 var replicas *int32 109 if agentPool.Spec.Count != nil { 110 replicas = ptr.To(int32(*agentPool.Spec.Count)) 111 agentPool.Spec.Count = nil 112 } 113 114 managedCluster := &asocontainerservicev1.ManagedCluster{} 115 if agentPool.Owner() == nil { 116 return ctrl.Result{}, fmt.Errorf("agent pool %s/%s has no owner", namespace, agentPool.Name) 117 } 118 managedClusterKey := client.ObjectKey{ 119 Namespace: namespace, 120 Name: agentPool.Owner().Name, 121 } 122 err = r.Get(ctx, managedClusterKey, managedCluster) 123 if err != nil { 124 return ctrl.Result{}, fmt.Errorf("failed to get ManagedCluster %s: %w", managedClusterKey, err) 125 } 126 var managedControlPlaneOwner *metav1.OwnerReference 127 for _, owner := range managedCluster.GetOwnerReferences() { 128 if owner.APIVersion == infrav1alpha.GroupVersion.Identifier() && 129 owner.Kind == infrav1alpha.AzureASOManagedControlPlaneKind && 130 owner.Name == agentPool.Owner().Name { 131 managedControlPlaneOwner = ptr.To(owner) 132 break 133 } 134 } 135 if managedControlPlaneOwner == nil { 136 return ctrl.Result{}, fmt.Errorf("ManagedCluster %s is not owned by any AzureASOManagedControlPlane", managedClusterKey) 137 } 138 asoManagedControlPlane := &infrav1alpha.AzureASOManagedControlPlane{} 139 managedControlPlaneKey := client.ObjectKey{ 140 Namespace: namespace, 141 Name: managedControlPlaneOwner.Name, 142 } 143 err = r.Get(ctx, managedControlPlaneKey, asoManagedControlPlane) 144 if err != nil { 145 return ctrl.Result{}, fmt.Errorf("failed to get AzureASOManagedControlPlane %s: %w", managedControlPlaneKey, err) 146 } 147 clusterName := asoManagedControlPlane.Labels[clusterv1.ClusterNameLabel] 148 149 asoManagedMachinePool := &infrav1alpha.AzureASOManagedMachinePool{ 150 ObjectMeta: metav1.ObjectMeta{ 151 Namespace: namespace, 152 Name: agentPool.Name, 153 }, 154 Spec: infrav1alpha.AzureASOManagedMachinePoolSpec{ 155 AzureASOManagedMachinePoolTemplateResourceSpec: infrav1alpha.AzureASOManagedMachinePoolTemplateResourceSpec{ 156 Resources: []runtime.RawExtension{ 157 {Object: agentPool}, 158 }, 159 }, 160 }, 161 } 162 163 machinePool := &expv1.MachinePool{ 164 ObjectMeta: metav1.ObjectMeta{ 165 Namespace: namespace, 166 Name: agentPool.Name, 167 }, 168 Spec: expv1.MachinePoolSpec{ 169 ClusterName: clusterName, 170 Replicas: replicas, 171 Template: clusterv1.MachineTemplateSpec{ 172 Spec: clusterv1.MachineSpec{ 173 Bootstrap: clusterv1.Bootstrap{ 174 DataSecretName: ptr.To(""), 175 }, 176 ClusterName: clusterName, 177 InfrastructureRef: corev1.ObjectReference{ 178 APIVersion: infrav1alpha.GroupVersion.Identifier(), 179 Kind: infrav1alpha.AzureASOManagedMachinePoolKind, 180 Name: asoManagedMachinePool.Name, 181 }, 182 }, 183 }, 184 }, 185 } 186 187 if ptr.Deref(agentPool.Spec.EnableAutoScaling, false) { 188 machinePool.Annotations = map[string]string{ 189 clusterv1.ReplicasManagedByAnnotation: infrav1alpha.ReplicasManagedByAKS, 190 } 191 } 192 193 err = r.Create(ctx, machinePool) 194 if client.IgnoreAlreadyExists(err) != nil { 195 return ctrl.Result{}, err 196 } 197 198 err = r.Create(ctx, asoManagedMachinePool) 199 if client.IgnoreAlreadyExists(err) != nil { 200 return ctrl.Result{}, err 201 } 202 203 return ctrl.Result{}, nil 204 }