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

     1  /*
     2  Copyright 2020 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/go-logr/logr"
    24  	"github.com/pkg/errors"
    25  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    26  	"k8s.io/client-go/tools/record"
    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/controller/controllerutil"
    31  	"sigs.k8s.io/controller-runtime/pkg/handler"
    32  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    33  	"sigs.k8s.io/controller-runtime/pkg/source"
    34  
    35  	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1"
    36  	expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/exp/api/v1beta1"
    37  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/scope"
    38  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/eks"
    39  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    40  	"sigs.k8s.io/cluster-api/util"
    41  	"sigs.k8s.io/cluster-api/util/conditions"
    42  	"sigs.k8s.io/cluster-api/util/predicates"
    43  )
    44  
    45  // AWSFargateProfileReconciler reconciles a AWSFargateProfile object.
    46  type AWSFargateProfileReconciler struct {
    47  	client.Client
    48  	Recorder         record.EventRecorder
    49  	Endpoints        []scope.ServiceEndpoint
    50  	EnableIAM        bool
    51  	WatchFilterValue string
    52  }
    53  
    54  // SetupWithManager is used to setup the controller.
    55  func (r *AWSFargateProfileReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
    56  	managedControlPlaneToFargateProfileMap := managedControlPlaneToFargateProfileMapFunc(r.Client, ctrl.LoggerFrom(ctx))
    57  	return ctrl.NewControllerManagedBy(mgr).
    58  		For(&expinfrav1.AWSFargateProfile{}).
    59  		WithOptions(options).
    60  		WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
    61  		Watches(
    62  			&source.Kind{Type: &ekscontrolplanev1.AWSManagedControlPlane{}},
    63  			handler.EnqueueRequestsFromMapFunc(managedControlPlaneToFargateProfileMap),
    64  		).
    65  		Complete(r)
    66  }
    67  
    68  // +kubebuilder:rbac:groups=core,resources=events,verbs=get;list;watch;create;patch
    69  // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch
    70  // +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=awsmanagedcontrolplanes;awsmanagedcontrolplanes/status,verbs=get;list;watch
    71  // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsfargateprofiles,verbs=get;list;watch;create;update;patch;delete
    72  // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=awsfargateprofiles/status,verbs=get;update;patch
    73  
    74  // Reconcile reconciles AWSFargateProfiles.
    75  func (r *AWSFargateProfileReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) {
    76  	log := ctrl.LoggerFrom(ctx)
    77  
    78  	fargateProfile := &expinfrav1.AWSFargateProfile{}
    79  	if err := r.Get(ctx, req.NamespacedName, fargateProfile); err != nil {
    80  		if apierrors.IsNotFound(err) {
    81  			return ctrl.Result{}, nil
    82  		}
    83  		return ctrl.Result{Requeue: true}, nil
    84  	}
    85  
    86  	cluster, err := util.GetClusterByName(ctx, r.Client, fargateProfile.Namespace, fargateProfile.Spec.ClusterName)
    87  	if err != nil {
    88  		log.Info("Failed to retrieve Cluster from AWSFargateProfile")
    89  		return reconcile.Result{}, nil
    90  	}
    91  
    92  	log = log.WithValues("Cluster", cluster.Name)
    93  
    94  	controlPlaneKey := client.ObjectKey{
    95  		Namespace: fargateProfile.Namespace,
    96  		Name:      cluster.Spec.ControlPlaneRef.Name,
    97  	}
    98  	controlPlane := &ekscontrolplanev1.AWSManagedControlPlane{}
    99  	if err := r.Client.Get(ctx, controlPlaneKey, controlPlane); err != nil {
   100  		log.Info("Failed to retrieve ControlPlane from AWSFargateProfile")
   101  		return reconcile.Result{}, nil
   102  	}
   103  
   104  	fargateProfileScope, err := scope.NewFargateProfileScope(scope.FargateProfileScopeParams{
   105  		Client:         r.Client,
   106  		ControllerName: "awsfargateprofile",
   107  		Cluster:        cluster,
   108  		ControlPlane:   controlPlane,
   109  		FargateProfile: fargateProfile,
   110  		EnableIAM:      r.EnableIAM,
   111  		Endpoints:      r.Endpoints,
   112  	})
   113  	if err != nil {
   114  		return ctrl.Result{}, errors.Wrap(err, "failed to create scope")
   115  	}
   116  
   117  	defer func() {
   118  		applicableConditions := []clusterv1.ConditionType{
   119  			expinfrav1.IAMFargateRolesReadyCondition,
   120  			expinfrav1.EKSFargateProfileReadyCondition,
   121  		}
   122  
   123  		conditions.SetSummary(fargateProfileScope.FargateProfile, conditions.WithConditions(applicableConditions...), conditions.WithStepCounter())
   124  
   125  		if err := fargateProfileScope.Close(); err != nil && reterr == nil {
   126  			reterr = err
   127  		}
   128  	}()
   129  
   130  	if !controlPlane.Status.Ready {
   131  		log.Info("Control plane is not ready yet")
   132  		conditions.MarkFalse(fargateProfile, clusterv1.ReadyCondition, expinfrav1.WaitingForEKSControlPlaneReason, clusterv1.ConditionSeverityInfo, "")
   133  		return ctrl.Result{}, nil
   134  	}
   135  
   136  	if !fargateProfile.ObjectMeta.DeletionTimestamp.IsZero() {
   137  		return r.reconcileDelete(ctx, fargateProfileScope)
   138  	}
   139  
   140  	return r.reconcileNormal(ctx, fargateProfileScope)
   141  }
   142  
   143  func (r *AWSFargateProfileReconciler) reconcileNormal(
   144  	_ context.Context,
   145  	fargateProfileScope *scope.FargateProfileScope,
   146  ) (ctrl.Result, error) {
   147  	fargateProfileScope.Info("Reconciling AWSFargateProfile")
   148  
   149  	controllerutil.AddFinalizer(fargateProfileScope.FargateProfile, expinfrav1.FargateProfileFinalizer)
   150  	if err := fargateProfileScope.PatchObject(); err != nil {
   151  		return ctrl.Result{}, err
   152  	}
   153  
   154  	ekssvc := eks.NewFargateService(fargateProfileScope)
   155  
   156  	res, err := ekssvc.Reconcile()
   157  	if err != nil {
   158  		return res, errors.Wrapf(err, "failed to reconcile fargate profile for AWSFargateProfile %s/%s", fargateProfileScope.FargateProfile.Namespace, fargateProfileScope.FargateProfile.Name)
   159  	}
   160  
   161  	return res, nil
   162  }
   163  
   164  func (r *AWSFargateProfileReconciler) reconcileDelete(
   165  	_ context.Context,
   166  	fargateProfileScope *scope.FargateProfileScope,
   167  ) (ctrl.Result, error) {
   168  	fargateProfileScope.Info("Reconciling deletion of AWSFargateProfile")
   169  
   170  	ekssvc := eks.NewFargateService(fargateProfileScope)
   171  
   172  	res, err := ekssvc.ReconcileDelete()
   173  	if err != nil {
   174  		return res, errors.Wrapf(err, "failed to reconcile fargate profile deletion for AWSFargateProfile %s/%s", fargateProfileScope.FargateProfile.Namespace, fargateProfileScope.FargateProfile.Name)
   175  	}
   176  
   177  	if res.IsZero() {
   178  		controllerutil.RemoveFinalizer(fargateProfileScope.FargateProfile, expinfrav1.FargateProfileFinalizer)
   179  	}
   180  
   181  	return res, nil
   182  }
   183  
   184  func managedControlPlaneToFargateProfileMapFunc(c client.Client, log logr.Logger) handler.MapFunc {
   185  	return func(o client.Object) []ctrl.Request {
   186  		ctx := context.Background()
   187  
   188  		awsControlPlane, ok := o.(*ekscontrolplanev1.AWSManagedControlPlane)
   189  		if !ok {
   190  			panic(fmt.Sprintf("Expected a AWSManagedControlPlane but got a %T", o))
   191  		}
   192  
   193  		if !awsControlPlane.ObjectMeta.DeletionTimestamp.IsZero() {
   194  			return nil
   195  		}
   196  
   197  		clusterKey, err := GetOwnerClusterKey(awsControlPlane.ObjectMeta)
   198  		if err != nil {
   199  			log.Error(err, "couldn't get AWS control plane owner ObjectKey")
   200  			return nil
   201  		}
   202  		if clusterKey == nil {
   203  			return nil
   204  		}
   205  
   206  		fargateProfileForClusterList := expinfrav1.AWSFargateProfileList{}
   207  		if err := c.List(
   208  			ctx, &fargateProfileForClusterList, client.InNamespace(clusterKey.Namespace), client.MatchingLabels{clusterv1.ClusterLabelName: clusterKey.Name},
   209  		); err != nil {
   210  			log.Error(err, "couldn't list fargate profiles for cluster")
   211  			return nil
   212  		}
   213  
   214  		var results []ctrl.Request
   215  		for i := range fargateProfileForClusterList.Items {
   216  			fp := fargateProfileForClusterList.Items[i]
   217  			results = append(results, reconcile.Request{
   218  				NamespacedName: client.ObjectKey{
   219  					Namespace: fp.Namespace,
   220  					Name:      fp.Name,
   221  				},
   222  			})
   223  		}
   224  
   225  		return results
   226  	}
   227  }