sigs.k8s.io/cluster-api-provider-aws@v1.5.5/exp/api/v1beta1/awsfargateprofile_webhook.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 v1beta1
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/google/go-cmp/cmp"
    23  	"github.com/pkg/errors"
    24  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	"k8s.io/apimachinery/pkg/util/validation/field"
    27  	ctrl "sigs.k8s.io/controller-runtime"
    28  	"sigs.k8s.io/controller-runtime/pkg/webhook"
    29  
    30  	"sigs.k8s.io/cluster-api-provider-aws/pkg/eks"
    31  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    32  )
    33  
    34  const (
    35  	maxProfileNameLength = 100
    36  	maxIAMRoleNameLength = 64
    37  )
    38  
    39  // SetupWebhookWithManager will setup the webhooks for the AWSFargateProfile.
    40  func (r *AWSFargateProfile) SetupWebhookWithManager(mgr ctrl.Manager) error {
    41  	return ctrl.NewWebhookManagedBy(mgr).
    42  		For(r).
    43  		Complete()
    44  }
    45  
    46  // +kubebuilder:webhook:verbs=create;update,path=/mutate-infrastructure-cluster-x-k8s-io-v1beta1-awsfargateprofile,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=awsfargateprofiles,versions=v1beta1,name=default.awsfargateprofile.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1
    47  // +kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-awsfargateprofile,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=awsfargateprofiles,versions=v1beta1,name=validation.awsfargateprofile.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1
    48  
    49  var _ webhook.Defaulter = &AWSFargateProfile{}
    50  var _ webhook.Validator = &AWSFargateProfile{}
    51  
    52  // Default will set default values for the AWSFargateProfile.
    53  func (r *AWSFargateProfile) Default() {
    54  	if r.Labels == nil {
    55  		r.Labels = make(map[string]string)
    56  	}
    57  	r.Labels[clusterv1.ClusterLabelName] = r.Spec.ClusterName
    58  
    59  	if r.Spec.ProfileName == "" {
    60  		name, err := eks.GenerateEKSName(r.Name, r.Namespace, maxProfileNameLength)
    61  		if err != nil {
    62  			mmpLog.Error(err, "failed to create EKS nodegroup name")
    63  			return
    64  		}
    65  
    66  		r.Spec.ProfileName = name
    67  	}
    68  }
    69  
    70  // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
    71  func (r *AWSFargateProfile) ValidateUpdate(oldObj runtime.Object) error {
    72  	gv := r.GroupVersionKind().GroupKind()
    73  	old, ok := oldObj.(*AWSFargateProfile)
    74  	if !ok {
    75  		return apierrors.NewInvalid(gv, r.Name, field.ErrorList{
    76  			field.InternalError(nil, errors.Errorf("failed to convert old %s to object", gv.Kind)),
    77  		})
    78  	}
    79  
    80  	var allErrs field.ErrorList
    81  
    82  	// Spec is immutable, but if the new RoleName is the generated one(or default if EnableIAM is disabled) and
    83  	// the old RoleName is nil, then ignore checking that field.
    84  	if old.Spec.RoleName == "" {
    85  		roleName, err := eks.GenerateEKSName(
    86  			"fargate",
    87  			fmt.Sprintf("%s-%s", r.Spec.ClusterName, r.Spec.ProfileName),
    88  			maxIAMRoleNameLength,
    89  		)
    90  		if err != nil {
    91  			mmpLog.Error(err, "failed to create EKS fargate role name")
    92  		}
    93  
    94  		if r.Spec.RoleName == roleName || r.Spec.RoleName == DefaultEKSFargateRole {
    95  			r.Spec.RoleName = ""
    96  		}
    97  	}
    98  
    99  	// Spec is immutable, but if the new ProfileName is the defaulted one and
   100  	// the old ProfileName is nil, then ignore checking that field.
   101  	if old.Spec.ProfileName == "" {
   102  		name, err := eks.GenerateEKSName(old.Name, old.Namespace, maxProfileNameLength)
   103  		if err != nil {
   104  			mmpLog.Error(err, "failed to create EKS nodegroup name")
   105  		}
   106  		if r.Spec.ProfileName == name {
   107  			r.Spec.ProfileName = ""
   108  		}
   109  	}
   110  
   111  	allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...)
   112  	// remove additionalTags from equal check since they are mutable
   113  	old.Spec.AdditionalTags = nil
   114  	r.Spec.AdditionalTags = nil
   115  
   116  	if !cmp.Equal(old.Spec, r.Spec) {
   117  		allErrs = append(
   118  			allErrs,
   119  			field.Invalid(field.NewPath("spec"), r.Spec, "is immutable"),
   120  		)
   121  	}
   122  
   123  	if len(allErrs) == 0 {
   124  		return nil
   125  	}
   126  
   127  	return apierrors.NewInvalid(
   128  		gv,
   129  		r.Name,
   130  		allErrs,
   131  	)
   132  }
   133  
   134  // ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
   135  func (r *AWSFargateProfile) ValidateCreate() error {
   136  	var allErrs field.ErrorList
   137  
   138  	allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...)
   139  
   140  	if len(allErrs) == 0 {
   141  		return nil
   142  	}
   143  	return apierrors.NewInvalid(
   144  		r.GroupVersionKind().GroupKind(),
   145  		r.Name,
   146  		allErrs,
   147  	)
   148  }
   149  
   150  // ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
   151  func (r *AWSFargateProfile) ValidateDelete() error {
   152  	return nil
   153  }