sigs.k8s.io/cluster-api-provider-azure@v1.17.0/controllers/azuremanagedcontrolplane_reconciler.go (about) 1 /* 2 Copyright 2019 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 "github.com/pkg/errors" 24 "k8s.io/client-go/tools/clientcmd" 25 "sigs.k8s.io/cluster-api-provider-azure/azure" 26 "sigs.k8s.io/cluster-api-provider-azure/azure/scope" 27 "sigs.k8s.io/cluster-api-provider-azure/azure/services/aksextensions" 28 "sigs.k8s.io/cluster-api-provider-azure/azure/services/fleetsmembers" 29 "sigs.k8s.io/cluster-api-provider-azure/azure/services/groups" 30 "sigs.k8s.io/cluster-api-provider-azure/azure/services/managedclusters" 31 "sigs.k8s.io/cluster-api-provider-azure/azure/services/privateendpoints" 32 "sigs.k8s.io/cluster-api-provider-azure/azure/services/resourcehealth" 33 "sigs.k8s.io/cluster-api-provider-azure/azure/services/subnets" 34 "sigs.k8s.io/cluster-api-provider-azure/azure/services/virtualnetworks" 35 "sigs.k8s.io/cluster-api-provider-azure/util/tele" 36 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 37 "sigs.k8s.io/cluster-api/util/secret" 38 "sigs.k8s.io/controller-runtime/pkg/client" 39 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 40 ) 41 42 // azureManagedControlPlaneService contains the services required by the cluster controller. 43 type azureManagedControlPlaneService struct { 44 kubeclient client.Client 45 scope managedclusters.ManagedClusterScope 46 services []azure.ServiceReconciler 47 } 48 49 // newAzureManagedControlPlaneReconciler populates all the services based on input scope. 50 func newAzureManagedControlPlaneReconciler(scope *scope.ManagedControlPlaneScope) (*azureManagedControlPlaneService, error) { 51 resourceHealthSvc, err := resourcehealth.New(scope) 52 if err != nil { 53 return nil, err 54 } 55 return &azureManagedControlPlaneService{ 56 kubeclient: scope.Client, 57 scope: scope, 58 services: []azure.ServiceReconciler{ 59 groups.New(scope), 60 virtualnetworks.New(scope), 61 subnets.New(scope), 62 managedclusters.New(scope), 63 privateendpoints.New(scope), 64 fleetsmembers.New(scope), 65 aksextensions.New(scope), 66 resourceHealthSvc, 67 }, 68 }, nil 69 } 70 71 // Reconcile reconciles all the services in a predetermined order. 72 func (r *azureManagedControlPlaneService) Reconcile(ctx context.Context) error { 73 ctx, _, done := tele.StartSpanWithLogger(ctx, "controllers.azureManagedControlPlaneService.Reconcile") 74 defer done() 75 76 for _, service := range r.services { 77 if err := service.Reconcile(ctx); err != nil { 78 return errors.Wrapf(err, "failed to reconcile AzureManagedControlPlane service %s", service.Name()) 79 } 80 } 81 82 if err := r.reconcileKubeconfig(ctx); err != nil { 83 return errors.Wrap(err, "failed to reconcile kubeconfig secret") 84 } 85 86 return nil 87 } 88 89 // Pause pauses all components making up the cluster. 90 func (r *azureManagedControlPlaneService) Pause(ctx context.Context) error { 91 ctx, _, done := tele.StartSpanWithLogger(ctx, "controllers.azureManagedControlPlaneService.Pause") 92 defer done() 93 94 for _, service := range r.services { 95 pauser, ok := service.(azure.Pauser) 96 if !ok { 97 continue 98 } 99 if err := pauser.Pause(ctx); err != nil { 100 return errors.Wrapf(err, "failed to pause AzureManagedControlPlane service %s", service.Name()) 101 } 102 } 103 104 return nil 105 } 106 107 // Delete reconciles all the services in a predetermined order. 108 func (r *azureManagedControlPlaneService) Delete(ctx context.Context) error { 109 ctx, _, done := tele.StartSpanWithLogger(ctx, "controllers.azureManagedControlPlaneService.Delete") 110 defer done() 111 112 // Delete services in reverse order of creation. 113 for i := len(r.services) - 1; i >= 0; i-- { 114 if err := r.services[i].Delete(ctx); err != nil { 115 return errors.Wrapf(err, "failed to delete AzureManagedControlPlane service %s", r.services[i].Name()) 116 } 117 } 118 119 return nil 120 } 121 122 func (r *azureManagedControlPlaneService) reconcileKubeconfig(ctx context.Context) error { 123 ctx, _, done := tele.StartSpanWithLogger(ctx, "controllers.azureManagedControlPlaneService.reconcileKubeconfig") 124 defer done() 125 126 kubeConfigs := [][]byte{r.scope.GetAdminKubeconfigData(), r.scope.GetUserKubeconfigData()} 127 128 for i, kubeConfigData := range kubeConfigs { 129 if len(kubeConfigData) == 0 { 130 continue 131 } 132 kubeConfigSecret := r.scope.MakeEmptyKubeConfigSecret() 133 if i == 1 { 134 // 2nd kubeconfig is the user kubeconfig 135 kubeConfigSecret.Name = fmt.Sprintf("%s-user", kubeConfigSecret.Name) 136 } 137 if _, err := controllerutil.CreateOrUpdate(ctx, r.kubeclient, &kubeConfigSecret, func() error { 138 kubeConfigSecret.Data = map[string][]byte{ 139 secret.KubeconfigDataName: kubeConfigData, 140 } 141 142 // When upgrading from an older version of CAPI, the kubeconfig secret may not have the required 143 // cluster name label. Add it here to avoid kubeconfig issues during upgrades. 144 if _, ok := kubeConfigSecret.Labels[clusterv1.ClusterNameLabel]; !ok { 145 if kubeConfigSecret.Labels == nil { 146 kubeConfigSecret.Labels = make(map[string]string) 147 } 148 kubeConfigSecret.Labels[clusterv1.ClusterNameLabel] = r.scope.ClusterName() 149 } 150 return nil 151 }); err != nil { 152 return errors.Wrap(err, "failed to reconcile kubeconfig secret for cluster") 153 } 154 } 155 156 // store cluster-info for the cluster with the admin kubeconfig. 157 kubeconfigFile, err := clientcmd.Load(kubeConfigs[0]) 158 if err != nil { 159 return errors.Wrap(err, "failed to turn aks credentials into kubeconfig file struct") 160 } 161 162 cluster := kubeconfigFile.Contexts[kubeconfigFile.CurrentContext].Cluster 163 caData := kubeconfigFile.Clusters[cluster].CertificateAuthorityData 164 caSecret := r.scope.MakeClusterCA() 165 if _, err := controllerutil.CreateOrUpdate(ctx, r.kubeclient, caSecret, func() error { 166 caSecret.Data = map[string][]byte{ 167 secret.TLSCrtDataName: caData, 168 secret.TLSKeyDataName: []byte("foo"), 169 } 170 return nil 171 }); err != nil { 172 return errors.Wrapf(err, "failed to reconcile certificate authority data secret for cluster") 173 } 174 175 if err := r.scope.StoreClusterInfo(ctx, caData); err != nil { 176 return errors.Wrap(err, "failed to construct cluster-info") 177 } 178 179 return nil 180 }