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  }