sigs.k8s.io/cluster-api-provider-aws@v1.5.5/exp/controlleridentitycreator/awscontrolleridentity_controller.go (about)

     1  /*
     2  Copyright 2021 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 controlleridentitycreator
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"github.com/go-logr/logr"
    24  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/types"
    27  	ctrl "sigs.k8s.io/controller-runtime"
    28  	"sigs.k8s.io/controller-runtime/pkg/client"
    29  	"sigs.k8s.io/controller-runtime/pkg/controller"
    30  	"sigs.k8s.io/controller-runtime/pkg/handler"
    31  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    32  	"sigs.k8s.io/controller-runtime/pkg/source"
    33  
    34  	infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1"
    35  	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1"
    36  	"sigs.k8s.io/cluster-api-provider-aws/feature"
    37  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/scope"
    38  	"sigs.k8s.io/cluster-api/util/predicates"
    39  )
    40  
    41  // AWSControllerIdentityReconciler reconciles a AWSClusterControllerIdentity object.
    42  type AWSControllerIdentityReconciler struct {
    43  	client.Client
    44  	Log              logr.Logger
    45  	Endpoints        []scope.ServiceEndpoint
    46  	WatchFilterValue string
    47  }
    48  
    49  // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsclustercontrolleridentities,verbs=get;list;watch;create
    50  
    51  func (r *AWSControllerIdentityReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    52  	log := ctrl.LoggerFrom(ctx)
    53  
    54  	var identityRef *infrav1.AWSIdentityReference
    55  
    56  	// Fetch the AWSCluster instance
    57  	awsCluster := &infrav1.AWSCluster{}
    58  	clusterFound := true
    59  	err := r.Get(ctx, req.NamespacedName, awsCluster)
    60  	if err != nil {
    61  		if !apierrors.IsNotFound(err) {
    62  			return reconcile.Result{}, err
    63  		}
    64  		log.V(4).Info("AWSCluster not found, trying AWSManagedControlPlane")
    65  		clusterFound = false
    66  	} else {
    67  		log.V(4).Info("Found identityRef on AWSCluster")
    68  		identityRef = awsCluster.Spec.IdentityRef
    69  	}
    70  
    71  	// If AWSCluster is not found, check if AWSManagedControlPlane is used.
    72  	if !clusterFound && feature.Gates.Enabled(feature.EKS) {
    73  		awsControlPlane := &ekscontrolplanev1.AWSManagedControlPlane{}
    74  		if err := r.Client.Get(ctx, req.NamespacedName, awsControlPlane); err != nil {
    75  			if apierrors.IsNotFound(err) {
    76  				log.V(4).Info("AWSManagedMachinePool not found, no identityRef so no action taken")
    77  				return ctrl.Result{}, nil
    78  			}
    79  			return reconcile.Result{}, err
    80  		}
    81  		log.V(4).Info("Found identityRef on AWSManagedControlPlane")
    82  		identityRef = awsControlPlane.Spec.IdentityRef
    83  	}
    84  
    85  	log = log.WithValues("cluster", req.Name)
    86  	if identityRef == nil {
    87  		log.Info("IdentityRef is nil, skipping reconciliation")
    88  		return ctrl.Result{Requeue: true}, nil
    89  	}
    90  
    91  	// If identity type is not AWSClusterControllerIdentity, then no need to create AWSClusterControllerIdentity singleton.
    92  	if identityRef.Kind == infrav1.ClusterRoleIdentityKind ||
    93  		identityRef.Kind == infrav1.ClusterStaticIdentityKind {
    94  		log.V(4).Info("Cluster does not use AWSClusterControllerIdentity as identityRef, skipping new instance creation")
    95  		return ctrl.Result{}, nil
    96  	}
    97  
    98  	// Fetch the AWSClusterControllerIdentity instance
    99  	controllerIdentity := &infrav1.AWSClusterControllerIdentity{}
   100  	err = r.Get(ctx, types.NamespacedName{Name: infrav1.AWSClusterControllerIdentityName}, controllerIdentity)
   101  	// If AWSClusterControllerIdentity instance already exists, then do not update it.
   102  	if err == nil {
   103  		return ctrl.Result{}, nil
   104  	}
   105  	if apierrors.IsNotFound(err) {
   106  		log.Info("AWSClusterControllerIdentity instance not found, creating a new instance")
   107  		// Fetch the AWSClusterControllerIdentity instance
   108  		controllerIdentity = &infrav1.AWSClusterControllerIdentity{
   109  			TypeMeta: metav1.TypeMeta{
   110  				APIVersion: infrav1.GroupVersion.String(),
   111  				Kind:       string(infrav1.ControllerIdentityKind),
   112  			},
   113  			ObjectMeta: metav1.ObjectMeta{
   114  				Name: infrav1.AWSClusterControllerIdentityName,
   115  			},
   116  			Spec: infrav1.AWSClusterControllerIdentitySpec{
   117  				AWSClusterIdentitySpec: infrav1.AWSClusterIdentitySpec{
   118  					AllowedNamespaces: &infrav1.AllowedNamespaces{},
   119  				},
   120  			},
   121  		}
   122  		err := r.Create(ctx, controllerIdentity)
   123  		if err != nil {
   124  			if apierrors.IsAlreadyExists(err) {
   125  				return reconcile.Result{}, nil
   126  			}
   127  			return reconcile.Result{}, err
   128  		}
   129  		return reconcile.Result{}, nil
   130  	}
   131  	return reconcile.Result{}, err
   132  }
   133  
   134  func (r *AWSControllerIdentityReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
   135  	controller := ctrl.NewControllerManagedBy(mgr).
   136  		For(&infrav1.AWSCluster{}).
   137  		WithOptions(options).
   138  		WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue))
   139  
   140  	if feature.Gates.Enabled(feature.EKS) {
   141  		controller.Watches(
   142  			&source.Kind{Type: &ekscontrolplanev1.AWSManagedControlPlane{}},
   143  			handler.EnqueueRequestsFromMapFunc(r.managedControlPlaneMap),
   144  		)
   145  	}
   146  
   147  	return controller.Complete(r)
   148  }
   149  
   150  func (r *AWSControllerIdentityReconciler) managedControlPlaneMap(o client.Object) []ctrl.Request {
   151  	managedControlPlane, ok := o.(*ekscontrolplanev1.AWSManagedControlPlane)
   152  	if !ok {
   153  		panic(fmt.Sprintf("Expected a managedControlPlane but got a %T", o))
   154  	}
   155  
   156  	return []ctrl.Request{
   157  		{
   158  			NamespacedName: types.NamespacedName{
   159  				Name:      managedControlPlane.Name,
   160  				Namespace: managedControlPlane.Namespace,
   161  			},
   162  		},
   163  	}
   164  }