@@ -24,136 +24,148 @@ import (
2424 "k8s.io/apimachinery/pkg/runtime"
2525 "k8s.io/apimachinery/pkg/util/validation/field"
2626 ctrl "sigs.k8s.io/controller-runtime"
27+ "sigs.k8s.io/controller-runtime/pkg/webhook"
2728 "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2829
2930 webhookutils "sigs.k8s.io/cluster-api-provider-azure/util/webhook"
3031)
3132
3233// SetupWebhookWithManager sets up and registers the webhook with the manager.
3334func (c * AzureCluster ) SetupWebhookWithManager (mgr ctrl.Manager ) error {
35+ w := new (azureClusterWebhook )
3436 return ctrl .NewWebhookManagedBy (mgr ).
3537 For (c ).
36- WithDefaulter (& AzureCluster {} ).
37- WithValidator (& AzureCluster {} ).
38+ WithDefaulter (w ).
39+ WithValidator (w ).
3840 Complete ()
3941}
4042
4143// +kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-azurecluster,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=azureclusters,versions=v1beta1,name=validation.azurecluster.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
4244// +kubebuilder:webhook:verbs=create;update,path=/mutate-infrastructure-cluster-x-k8s-io-v1beta1-azurecluster,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=azureclusters,versions=v1beta1,name=default.azurecluster.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
4345
46+ type azureClusterWebhook struct {}
47+
48+ var (
49+ _ webhook.CustomValidator = & azureClusterWebhook {}
50+ _ webhook.CustomDefaulter = & azureClusterWebhook {}
51+ )
52+
4453// Default implements webhook.Defaulter so a webhook will be registered for the type.
45- func (c * AzureCluster ) Default (_ context.Context , _ runtime.Object ) error {
54+ func (_ * azureClusterWebhook ) Default (_ context.Context , obj runtime.Object ) error {
55+ c := obj .(* AzureCluster )
4656 c .setDefaults ()
4757 return nil
4858}
4959
5060// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
51- func (c * AzureCluster ) ValidateCreate (_ context.Context , _ runtime.Object ) (admission.Warnings , error ) {
61+ func (_ * azureClusterWebhook ) ValidateCreate (_ context.Context , newObj runtime.Object ) (admission.Warnings , error ) {
62+ c := newObj .(* AzureCluster )
5263 return c .validateCluster (nil )
5364}
5465
5566// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
56- func (c * AzureCluster ) ValidateUpdate (_ context.Context , _ runtime. Object , oldRaw runtime.Object ) (admission.Warnings , error ) {
67+ func (_ * azureClusterWebhook ) ValidateUpdate (_ context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
5768 var allErrs field.ErrorList
58- old := oldRaw .(* AzureCluster )
69+ oldAzureCluster := oldObj .(* AzureCluster )
70+ newAzureCluster := newObj .(* AzureCluster )
5971
6072 if err := webhookutils .ValidateImmutable (
6173 field .NewPath ("spec" , "resourceGroup" ),
62- old .Spec .ResourceGroup ,
63- c .Spec .ResourceGroup ); err != nil {
74+ oldAzureCluster .Spec .ResourceGroup ,
75+ newAzureCluster .Spec .ResourceGroup ); err != nil {
6476 allErrs = append (allErrs , err )
6577 }
6678
6779 if err := webhookutils .ValidateImmutable (
6880 field .NewPath ("spec" , "subscriptionID" ),
69- old .Spec .SubscriptionID ,
70- c .Spec .SubscriptionID ); err != nil {
81+ oldAzureCluster .Spec .SubscriptionID ,
82+ newAzureCluster .Spec .SubscriptionID ); err != nil {
7183 allErrs = append (allErrs , err )
7284 }
7385
7486 if err := webhookutils .ValidateImmutable (
7587 field .NewPath ("spec" , "location" ),
76- old .Spec .Location ,
77- c .Spec .Location ); err != nil {
88+ oldAzureCluster .Spec .Location ,
89+ newAzureCluster .Spec .Location ); err != nil {
7890 allErrs = append (allErrs , err )
7991 }
8092
81- if old .Spec .ControlPlaneEndpoint .Host != "" && c .Spec .ControlPlaneEndpoint .Host != old .Spec .ControlPlaneEndpoint .Host {
93+ if oldAzureCluster .Spec .ControlPlaneEndpoint .Host != "" && newAzureCluster .Spec .ControlPlaneEndpoint .Host != oldAzureCluster .Spec .ControlPlaneEndpoint .Host {
8294 allErrs = append (allErrs ,
8395 field .Invalid (field .NewPath ("spec" , "controlPlaneEndpoint" , "host" ),
84- c .Spec .ControlPlaneEndpoint .Host , "field is immutable" ),
96+ newAzureCluster .Spec .ControlPlaneEndpoint .Host , "field is immutable" ),
8597 )
8698 }
8799
88- if old .Spec .ControlPlaneEndpoint .Port != 0 && c .Spec .ControlPlaneEndpoint .Port != old .Spec .ControlPlaneEndpoint .Port {
100+ if oldAzureCluster .Spec .ControlPlaneEndpoint .Port != 0 && newAzureCluster .Spec .ControlPlaneEndpoint .Port != oldAzureCluster .Spec .ControlPlaneEndpoint .Port {
89101 allErrs = append (allErrs ,
90102 field .Invalid (field .NewPath ("spec" , "controlPlaneEndpoint" , "port" ),
91- c .Spec .ControlPlaneEndpoint .Port , "field is immutable" ),
103+ newAzureCluster .Spec .ControlPlaneEndpoint .Port , "field is immutable" ),
92104 )
93105 }
94106
95- if ! reflect .DeepEqual (c .Spec .AzureEnvironment , old .Spec .AzureEnvironment ) {
107+ if ! reflect .DeepEqual (newAzureCluster .Spec .AzureEnvironment , oldAzureCluster .Spec .AzureEnvironment ) {
96108 // The equality failure could be because of default mismatch between v1alpha3 and v1beta1. This happens because
97- // the new object `r` will have run through the default webhooks but the old object `old ` would not have so.
109+ // the new object `r` will have run through the default webhooks but the old object `oldAzureCluster ` would not have so.
98110 // This means if the old object was in v1alpha3, it would not get the new defaults set in v1beta1 resulting
99111 // in object inequality. To workaround this, we set the v1beta1 defaults here so that the old object also gets
100112 // the new defaults.
101- old .setAzureEnvironmentDefault ()
113+ oldAzureCluster .setAzureEnvironmentDefault ()
102114
103115 // if it's still not equal, return error.
104- if ! reflect .DeepEqual (c .Spec .AzureEnvironment , old .Spec .AzureEnvironment ) {
116+ if ! reflect .DeepEqual (newAzureCluster .Spec .AzureEnvironment , oldAzureCluster .Spec .AzureEnvironment ) {
105117 allErrs = append (allErrs ,
106118 field .Invalid (field .NewPath ("spec" , "azureEnvironment" ),
107- c .Spec .AzureEnvironment , "field is immutable" ),
119+ newAzureCluster .Spec .AzureEnvironment , "field is immutable" ),
108120 )
109121 }
110122 }
111123
112124 if err := webhookutils .ValidateImmutable (
113125 field .NewPath ("spec" , "networkSpec" , "privateDNSZoneName" ),
114- old .Spec .NetworkSpec .PrivateDNSZoneName ,
115- c .Spec .NetworkSpec .PrivateDNSZoneName ); err != nil {
126+ oldAzureCluster .Spec .NetworkSpec .PrivateDNSZoneName ,
127+ newAzureCluster .Spec .NetworkSpec .PrivateDNSZoneName ); err != nil {
116128 allErrs = append (allErrs , err )
117129 }
118130
119131 if err := webhookutils .ValidateImmutable (
120132 field .NewPath ("spec" , "networkSpec" , "privateDNSZoneResourceGroup" ),
121- old .Spec .NetworkSpec .PrivateDNSZoneResourceGroup ,
122- c .Spec .NetworkSpec .PrivateDNSZoneResourceGroup ); err != nil {
133+ oldAzureCluster .Spec .NetworkSpec .PrivateDNSZoneResourceGroup ,
134+ newAzureCluster .Spec .NetworkSpec .PrivateDNSZoneResourceGroup ); err != nil {
123135 allErrs = append (allErrs , err )
124136 }
125137
126138 // Allow enabling azure bastion but avoid disabling it.
127- if old .Spec .BastionSpec .AzureBastion != nil && ! reflect .DeepEqual (old .Spec .BastionSpec .AzureBastion , c .Spec .BastionSpec .AzureBastion ) {
139+ if oldAzureCluster .Spec .BastionSpec .AzureBastion != nil && ! reflect .DeepEqual (oldAzureCluster .Spec .BastionSpec .AzureBastion , newAzureCluster .Spec .BastionSpec .AzureBastion ) {
128140 allErrs = append (allErrs ,
129141 field .Invalid (field .NewPath ("spec" , "bastionSpec" , "azureBastion" ),
130- c .Spec .BastionSpec .AzureBastion , "azure bastion cannot be removed from a cluster" ),
142+ newAzureCluster .Spec .BastionSpec .AzureBastion , "azure bastion cannot be removed from a cluster" ),
131143 )
132144 }
133145
134146 if err := webhookutils .ValidateImmutable (
135147 field .NewPath ("spec" , "networkSpec" , "controlPlaneOutboundLB" ),
136- old .Spec .NetworkSpec .ControlPlaneOutboundLB ,
137- c .Spec .NetworkSpec .ControlPlaneOutboundLB ); err != nil {
148+ oldAzureCluster .Spec .NetworkSpec .ControlPlaneOutboundLB ,
149+ newAzureCluster .Spec .NetworkSpec .ControlPlaneOutboundLB ); err != nil {
138150 allErrs = append (allErrs , err )
139151 }
140152
141- allErrs = append (allErrs , c .validateSubnetUpdate (old )... )
153+ allErrs = append (allErrs , newAzureCluster .validateSubnetUpdate (oldAzureCluster )... )
142154
143155 if len (allErrs ) == 0 {
144- return c .validateCluster (old )
156+ return newAzureCluster .validateCluster (oldAzureCluster )
145157 }
146158
147- return nil , apierrors .NewInvalid (GroupVersion .WithKind (AzureClusterKind ).GroupKind (), c .Name , allErrs )
159+ return nil , apierrors .NewInvalid (GroupVersion .WithKind (AzureClusterKind ).GroupKind (), newAzureCluster .Name , allErrs )
148160}
149161
150162// validateSubnetUpdate validates a ClusterSpec.NetworkSpec.Subnets for immutability.
151- func (c * AzureCluster ) validateSubnetUpdate (old * AzureCluster ) field.ErrorList {
163+ func (c * AzureCluster ) validateSubnetUpdate (oldAzureCluster * AzureCluster ) field.ErrorList {
152164 var allErrs field.ErrorList
153165
154- oldSubnetMap := make (map [string ]SubnetSpec , len (old .Spec .NetworkSpec .Subnets ))
155- oldSubnetIndex := make (map [string ]int , len (old .Spec .NetworkSpec .Subnets ))
156- for i , subnet := range old .Spec .NetworkSpec .Subnets {
166+ oldSubnetMap := make (map [string ]SubnetSpec , len (oldAzureCluster .Spec .NetworkSpec .Subnets ))
167+ oldSubnetIndex := make (map [string ]int , len (oldAzureCluster .Spec .NetworkSpec .Subnets ))
168+ for i , subnet := range oldAzureCluster .Spec .NetworkSpec .Subnets {
157169 oldSubnetMap [subnet .Name ] = subnet
158170 oldSubnetIndex [subnet .Name ] = i
159171 }
@@ -165,7 +177,7 @@ func (c *AzureCluster) validateSubnetUpdate(old *AzureCluster) field.ErrorList {
165177 // This technically allows the cidr block to be modified in the brief
166178 // moments before the Vnet is created (because the tags haven't been
167179 // set yet) but once the Vnet has been created it becomes immutable.
168- if old .Spec .NetworkSpec .Vnet .Tags .HasOwned (old .Name ) && ! reflect .DeepEqual (subnet .CIDRBlocks , oldSubnet .CIDRBlocks ) {
180+ if oldAzureCluster .Spec .NetworkSpec .Vnet .Tags .HasOwned (oldAzureCluster .Name ) && ! reflect .DeepEqual (subnet .CIDRBlocks , oldSubnet .CIDRBlocks ) {
169181 allErrs = append (allErrs ,
170182 field .Invalid (field .NewPath ("spec" , "networkSpec" , "subnets" ).Index (oldSubnetIndex [subnet .Name ]).Child ("CIDRBlocks" ),
171183 c .Spec .NetworkSpec .Subnets [i ].CIDRBlocks , "field is immutable" ),
@@ -196,6 +208,6 @@ func (c *AzureCluster) validateSubnetUpdate(old *AzureCluster) field.ErrorList {
196208}
197209
198210// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
199- func (c * AzureCluster ) ValidateDelete (_ context.Context , _ runtime.Object ) (admission.Warnings , error ) {
211+ func (_ * azureClusterWebhook ) ValidateDelete (_ context.Context , _ runtime.Object ) (admission.Warnings , error ) {
200212 return nil , nil
201213}
0 commit comments