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 }