sigs.k8s.io/cluster-api-provider-azure@v1.17.0/controllers/managedclusteradopt_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 asoresourcesv1 "github.com/Azure/azure-service-operator/v2/api/resources/v1api20200601" 25 corev1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime" 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 ctrl "sigs.k8s.io/controller-runtime" 32 "sigs.k8s.io/controller-runtime/pkg/client" 33 "sigs.k8s.io/controller-runtime/pkg/controller" 34 "sigs.k8s.io/controller-runtime/pkg/event" 35 "sigs.k8s.io/controller-runtime/pkg/predicate" 36 ) 37 38 const ( 39 adoptAnnotation = "sigs.k8s.io/cluster-api-provider-azure-adopt" 40 adoptAnnotationValue = "true" 41 ) 42 43 // ManagedClusterAdoptReconciler adopts ASO ManagedCluster resources into a CAPI Cluster. 44 type ManagedClusterAdoptReconciler struct { 45 client.Client 46 } 47 48 // SetupWithManager sets up the controller with the Manager. 49 func (r *ManagedClusterAdoptReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { 50 _, err := ctrl.NewControllerManagedBy(mgr). 51 WithOptions(options). 52 For(&asocontainerservicev1.ManagedCluster{}). 53 WithEventFilter(predicate.Funcs{ 54 UpdateFunc: func(ev event.UpdateEvent) bool { 55 return ev.ObjectOld.GetAnnotations()[adoptAnnotation] != ev.ObjectNew.GetAnnotations()[adoptAnnotation] 56 }, 57 DeleteFunc: func(_ event.DeleteEvent) bool { return false }, 58 }). 59 Build(r) 60 if err != nil { 61 return err 62 } 63 64 return nil 65 } 66 67 // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters,verbs=create 68 69 // Reconcile reconciles an AzureASOManagedCluster. 70 func (r *ManagedClusterAdoptReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, resultErr error) { 71 ctx, log, done := tele.StartSpanWithLogger(ctx, 72 "controllers.ManagedClusterAdoptReconciler.Reconcile", 73 tele.KVP("namespace", req.Namespace), 74 tele.KVP("name", req.Name), 75 tele.KVP("kind", "ManagedCluster"), 76 ) 77 defer done() 78 79 managedCluster := &asocontainerservicev1.ManagedCluster{} 80 err := r.Get(ctx, req.NamespacedName, managedCluster) 81 if err != nil { 82 return ctrl.Result{}, client.IgnoreNotFound(err) 83 } 84 85 if managedCluster.GetAnnotations()[adoptAnnotation] != adoptAnnotationValue { 86 return ctrl.Result{}, nil 87 } 88 89 for _, owner := range managedCluster.GetOwnerReferences() { 90 if owner.APIVersion == infrav1alpha.GroupVersion.Identifier() && 91 owner.Kind == infrav1alpha.AzureASOManagedControlPlaneKind { 92 return ctrl.Result{}, nil 93 } 94 } 95 96 log.Info("adopting") 97 98 cluster := &clusterv1.Cluster{ 99 ObjectMeta: metav1.ObjectMeta{ 100 Namespace: managedCluster.Namespace, 101 Name: managedCluster.Name, 102 }, 103 Spec: clusterv1.ClusterSpec{ 104 InfrastructureRef: &corev1.ObjectReference{ 105 APIVersion: infrav1alpha.GroupVersion.Identifier(), 106 Kind: infrav1alpha.AzureASOManagedClusterKind, 107 Name: managedCluster.Name, 108 }, 109 ControlPlaneRef: &corev1.ObjectReference{ 110 APIVersion: infrav1alpha.GroupVersion.Identifier(), 111 Kind: infrav1alpha.AzureASOManagedControlPlaneKind, 112 Name: managedCluster.Name, 113 }, 114 }, 115 } 116 err = r.Create(ctx, cluster) 117 if client.IgnoreAlreadyExists(err) != nil { 118 return ctrl.Result{}, err 119 } 120 121 resourceGroup := &asoresourcesv1.ResourceGroup{ 122 ObjectMeta: metav1.ObjectMeta{ 123 Namespace: managedCluster.Namespace, 124 Name: managedCluster.Owner().Name, 125 }, 126 } 127 128 err = r.Get(ctx, client.ObjectKeyFromObject(resourceGroup), resourceGroup) 129 if err != nil { 130 return ctrl.Result{}, fmt.Errorf("error getting ResourceGroup %s: %w", client.ObjectKeyFromObject(resourceGroup), err) 131 } 132 133 // filter down to what will be persisted in the AzureASOManagedCluster 134 resourceGroup = &asoresourcesv1.ResourceGroup{ 135 TypeMeta: metav1.TypeMeta{ 136 APIVersion: asoresourcesv1.GroupVersion.Identifier(), 137 Kind: "ResourceGroup", 138 }, 139 ObjectMeta: metav1.ObjectMeta{ 140 Name: resourceGroup.Name, 141 }, 142 Spec: resourceGroup.Spec, 143 } 144 145 asoManagedCluster := &infrav1alpha.AzureASOManagedCluster{ 146 ObjectMeta: metav1.ObjectMeta{ 147 Namespace: managedCluster.Namespace, 148 Name: managedCluster.Name, 149 }, 150 Spec: infrav1alpha.AzureASOManagedClusterSpec{ 151 AzureASOManagedClusterTemplateResourceSpec: infrav1alpha.AzureASOManagedClusterTemplateResourceSpec{ 152 Resources: []runtime.RawExtension{ 153 {Object: resourceGroup}, 154 }, 155 }, 156 }, 157 } 158 err = r.Create(ctx, asoManagedCluster) 159 if client.IgnoreAlreadyExists(err) != nil { 160 return ctrl.Result{}, err 161 } 162 163 // agent pools are defined by AzureASOManagedMachinePools. Remove them from this resource. 164 managedClusterBefore := managedCluster.DeepCopy() 165 managedCluster.Spec.AgentPoolProfiles = nil 166 err = r.Patch(ctx, managedCluster, client.MergeFrom(managedClusterBefore)) 167 if err != nil { 168 return ctrl.Result{}, err 169 } 170 171 managedCluster = &asocontainerservicev1.ManagedCluster{ 172 TypeMeta: metav1.TypeMeta{ 173 APIVersion: asocontainerservicev1.GroupVersion.Identifier(), 174 Kind: "ManagedCluster", 175 }, 176 ObjectMeta: metav1.ObjectMeta{ 177 Name: managedCluster.Name, 178 }, 179 Spec: managedCluster.Spec, 180 } 181 182 asoManagedControlPlane := &infrav1alpha.AzureASOManagedControlPlane{ 183 ObjectMeta: metav1.ObjectMeta{ 184 Namespace: cluster.Namespace, 185 Name: managedCluster.Name, 186 }, 187 Spec: infrav1alpha.AzureASOManagedControlPlaneSpec{ 188 AzureASOManagedControlPlaneTemplateResourceSpec: infrav1alpha.AzureASOManagedControlPlaneTemplateResourceSpec{ 189 Resources: []runtime.RawExtension{ 190 {Object: managedCluster}, 191 }, 192 }, 193 }, 194 } 195 err = r.Create(ctx, asoManagedControlPlane) 196 if client.IgnoreAlreadyExists(err) != nil { 197 return ctrl.Result{}, err 198 } 199 200 return ctrl.Result{}, nil 201 }