@@ -24,136 +24,149 @@ 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+ // AzureClusterWebhook is a webhook for AzureCluster.
47+ type AzureClusterWebhook struct {}
48+
49+ var (
50+ _ webhook.CustomValidator = & AzureClusterWebhook {}
51+ _ webhook.CustomDefaulter = & AzureClusterWebhook {}
52+ )
53+
4454// Default implements webhook.Defaulter so a webhook will be registered for the type.
45- func (c * AzureCluster ) Default (_ context.Context , _ runtime.Object ) error {
55+ func (* AzureClusterWebhook ) Default (_ context.Context , obj runtime.Object ) error {
56+ c := obj .(* AzureCluster )
4657 c .setDefaults ()
4758 return nil
4859}
4960
5061// 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 ) {
62+ func (* AzureClusterWebhook ) ValidateCreate (_ context.Context , newObj runtime.Object ) (admission.Warnings , error ) {
63+ c := newObj .(* AzureCluster )
5264 return c .validateCluster (nil )
5365}
5466
5567// 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 ) {
68+ func (* AzureClusterWebhook ) ValidateUpdate (_ context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
5769 var allErrs field.ErrorList
58- old := oldRaw .(* AzureCluster )
70+ oldAzureCluster := oldObj .(* AzureCluster )
71+ newAzureCluster := newObj .(* AzureCluster )
5972
6073 if err := webhookutils .ValidateImmutable (
6174 field .NewPath ("spec" , "resourceGroup" ),
62- old .Spec .ResourceGroup ,
63- c .Spec .ResourceGroup ); err != nil {
75+ oldAzureCluster .Spec .ResourceGroup ,
76+ newAzureCluster .Spec .ResourceGroup ); err != nil {
6477 allErrs = append (allErrs , err )
6578 }
6679
6780 if err := webhookutils .ValidateImmutable (
6881 field .NewPath ("spec" , "subscriptionID" ),
69- old .Spec .SubscriptionID ,
70- c .Spec .SubscriptionID ); err != nil {
82+ oldAzureCluster .Spec .SubscriptionID ,
83+ newAzureCluster .Spec .SubscriptionID ); err != nil {
7184 allErrs = append (allErrs , err )
7285 }
7386
7487 if err := webhookutils .ValidateImmutable (
7588 field .NewPath ("spec" , "location" ),
76- old .Spec .Location ,
77- c .Spec .Location ); err != nil {
89+ oldAzureCluster .Spec .Location ,
90+ newAzureCluster .Spec .Location ); err != nil {
7891 allErrs = append (allErrs , err )
7992 }
8093
81- if old .Spec .ControlPlaneEndpoint .Host != "" && c .Spec .ControlPlaneEndpoint .Host != old .Spec .ControlPlaneEndpoint .Host {
94+ if oldAzureCluster .Spec .ControlPlaneEndpoint .Host != "" && newAzureCluster .Spec .ControlPlaneEndpoint .Host != oldAzureCluster .Spec .ControlPlaneEndpoint .Host {
8295 allErrs = append (allErrs ,
8396 field .Invalid (field .NewPath ("spec" , "controlPlaneEndpoint" , "host" ),
84- c .Spec .ControlPlaneEndpoint .Host , "field is immutable" ),
97+ newAzureCluster .Spec .ControlPlaneEndpoint .Host , "field is immutable" ),
8598 )
8699 }
87100
88- if old .Spec .ControlPlaneEndpoint .Port != 0 && c .Spec .ControlPlaneEndpoint .Port != old .Spec .ControlPlaneEndpoint .Port {
101+ if oldAzureCluster .Spec .ControlPlaneEndpoint .Port != 0 && newAzureCluster .Spec .ControlPlaneEndpoint .Port != oldAzureCluster .Spec .ControlPlaneEndpoint .Port {
89102 allErrs = append (allErrs ,
90103 field .Invalid (field .NewPath ("spec" , "controlPlaneEndpoint" , "port" ),
91- c .Spec .ControlPlaneEndpoint .Port , "field is immutable" ),
104+ newAzureCluster .Spec .ControlPlaneEndpoint .Port , "field is immutable" ),
92105 )
93106 }
94107
95- if ! reflect .DeepEqual (c .Spec .AzureEnvironment , old .Spec .AzureEnvironment ) {
108+ if ! reflect .DeepEqual (newAzureCluster .Spec .AzureEnvironment , oldAzureCluster .Spec .AzureEnvironment ) {
96109 // 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.
110+ // the new object `r` will have run through the default webhooks but the old object `oldAzureCluster ` would not have so.
98111 // This means if the old object was in v1alpha3, it would not get the new defaults set in v1beta1 resulting
99112 // in object inequality. To workaround this, we set the v1beta1 defaults here so that the old object also gets
100113 // the new defaults.
101- old .setAzureEnvironmentDefault ()
114+ oldAzureCluster .setAzureEnvironmentDefault ()
102115
103116 // if it's still not equal, return error.
104- if ! reflect .DeepEqual (c .Spec .AzureEnvironment , old .Spec .AzureEnvironment ) {
117+ if ! reflect .DeepEqual (newAzureCluster .Spec .AzureEnvironment , oldAzureCluster .Spec .AzureEnvironment ) {
105118 allErrs = append (allErrs ,
106119 field .Invalid (field .NewPath ("spec" , "azureEnvironment" ),
107- c .Spec .AzureEnvironment , "field is immutable" ),
120+ newAzureCluster .Spec .AzureEnvironment , "field is immutable" ),
108121 )
109122 }
110123 }
111124
112125 if err := webhookutils .ValidateImmutable (
113126 field .NewPath ("spec" , "networkSpec" , "privateDNSZoneName" ),
114- old .Spec .NetworkSpec .PrivateDNSZoneName ,
115- c .Spec .NetworkSpec .PrivateDNSZoneName ); err != nil {
127+ oldAzureCluster .Spec .NetworkSpec .PrivateDNSZoneName ,
128+ newAzureCluster .Spec .NetworkSpec .PrivateDNSZoneName ); err != nil {
116129 allErrs = append (allErrs , err )
117130 }
118131
119132 if err := webhookutils .ValidateImmutable (
120133 field .NewPath ("spec" , "networkSpec" , "privateDNSZoneResourceGroup" ),
121- old .Spec .NetworkSpec .PrivateDNSZoneResourceGroup ,
122- c .Spec .NetworkSpec .PrivateDNSZoneResourceGroup ); err != nil {
134+ oldAzureCluster .Spec .NetworkSpec .PrivateDNSZoneResourceGroup ,
135+ newAzureCluster .Spec .NetworkSpec .PrivateDNSZoneResourceGroup ); err != nil {
123136 allErrs = append (allErrs , err )
124137 }
125138
126139 // 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 ) {
140+ if oldAzureCluster .Spec .BastionSpec .AzureBastion != nil && ! reflect .DeepEqual (oldAzureCluster .Spec .BastionSpec .AzureBastion , newAzureCluster .Spec .BastionSpec .AzureBastion ) {
128141 allErrs = append (allErrs ,
129142 field .Invalid (field .NewPath ("spec" , "bastionSpec" , "azureBastion" ),
130- c .Spec .BastionSpec .AzureBastion , "azure bastion cannot be removed from a cluster" ),
143+ newAzureCluster .Spec .BastionSpec .AzureBastion , "azure bastion cannot be removed from a cluster" ),
131144 )
132145 }
133146
134147 if err := webhookutils .ValidateImmutable (
135148 field .NewPath ("spec" , "networkSpec" , "controlPlaneOutboundLB" ),
136- old .Spec .NetworkSpec .ControlPlaneOutboundLB ,
137- c .Spec .NetworkSpec .ControlPlaneOutboundLB ); err != nil {
149+ oldAzureCluster .Spec .NetworkSpec .ControlPlaneOutboundLB ,
150+ newAzureCluster .Spec .NetworkSpec .ControlPlaneOutboundLB ); err != nil {
138151 allErrs = append (allErrs , err )
139152 }
140153
141- allErrs = append (allErrs , c .validateSubnetUpdate (old )... )
154+ allErrs = append (allErrs , newAzureCluster .validateSubnetUpdate (oldAzureCluster )... )
142155
143156 if len (allErrs ) == 0 {
144- return c .validateCluster (old )
157+ return newAzureCluster .validateCluster (oldAzureCluster )
145158 }
146159
147- return nil , apierrors .NewInvalid (GroupVersion .WithKind (AzureClusterKind ).GroupKind (), c .Name , allErrs )
160+ return nil , apierrors .NewInvalid (GroupVersion .WithKind (AzureClusterKind ).GroupKind (), newAzureCluster .Name , allErrs )
148161}
149162
150163// validateSubnetUpdate validates a ClusterSpec.NetworkSpec.Subnets for immutability.
151- func (c * AzureCluster ) validateSubnetUpdate (old * AzureCluster ) field.ErrorList {
164+ func (c * AzureCluster ) validateSubnetUpdate (oldAzureCluster * AzureCluster ) field.ErrorList {
152165 var allErrs field.ErrorList
153166
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 {
167+ oldSubnetMap := make (map [string ]SubnetSpec , len (oldAzureCluster .Spec .NetworkSpec .Subnets ))
168+ oldSubnetIndex := make (map [string ]int , len (oldAzureCluster .Spec .NetworkSpec .Subnets ))
169+ for i , subnet := range oldAzureCluster .Spec .NetworkSpec .Subnets {
157170 oldSubnetMap [subnet .Name ] = subnet
158171 oldSubnetIndex [subnet .Name ] = i
159172 }
@@ -165,7 +178,7 @@ func (c *AzureCluster) validateSubnetUpdate(old *AzureCluster) field.ErrorList {
165178 // This technically allows the cidr block to be modified in the brief
166179 // moments before the Vnet is created (because the tags haven't been
167180 // 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 ) {
181+ if oldAzureCluster .Spec .NetworkSpec .Vnet .Tags .HasOwned (oldAzureCluster .Name ) && ! reflect .DeepEqual (subnet .CIDRBlocks , oldSubnet .CIDRBlocks ) {
169182 allErrs = append (allErrs ,
170183 field .Invalid (field .NewPath ("spec" , "networkSpec" , "subnets" ).Index (oldSubnetIndex [subnet .Name ]).Child ("CIDRBlocks" ),
171184 c .Spec .NetworkSpec .Subnets [i ].CIDRBlocks , "field is immutable" ),
@@ -196,6 +209,6 @@ func (c *AzureCluster) validateSubnetUpdate(old *AzureCluster) field.ErrorList {
196209}
197210
198211// 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 ) {
212+ func (* AzureClusterWebhook ) ValidateDelete (_ context.Context , _ runtime.Object ) (admission.Warnings , error ) {
200213 return nil , nil
201214}
0 commit comments