@@ -193,6 +193,62 @@ func (*openStackClusterWebhook) ValidateUpdate(_ context.Context, oldObjRaw, new
193193 newObj .Spec .ManagedSecurityGroups .AllowAllInClusterTraffic = false
194194 }
195195
196+ // Allow changes only to DNSNameservers in ManagedSubnets spec
197+ if newObj .Spec .ManagedSubnets != nil && oldObj .Spec .ManagedSubnets != nil {
198+ // Check if any fields other than DNSNameservers have changed
199+ if len (oldObj .Spec .ManagedSubnets ) != len (newObj .Spec .ManagedSubnets ) {
200+ allErrs = append (allErrs , field .Forbidden (field .NewPath ("spec" , "managedSubnets" ), "cannot add or remove subnets" ))
201+ } else {
202+ // Build maps of subnets by CIDR
203+ oldSubnetMap := make (map [string ]infrav1.SubnetSpec )
204+ newSubnetMap := make (map [string ]infrav1.SubnetSpec )
205+
206+ for _ , subnet := range oldObj .Spec .ManagedSubnets {
207+ oldSubnetMap [subnet .CIDR ] = subnet
208+ }
209+
210+ // Check if all new subnets have matching old subnets with the same CIDR
211+ for _ , newSubnet := range newObj .Spec .ManagedSubnets {
212+ oldSubnet , exists := oldSubnetMap [newSubnet .CIDR ]
213+ if ! exists {
214+ allErrs = append (allErrs , field .Forbidden (
215+ field .NewPath ("spec" , "managedSubnets" ),
216+ fmt .Sprintf ("cannot change subnet CIDR from existing value to %s" , newSubnet .CIDR ),
217+ ))
218+ continue
219+ }
220+
221+ // Check if AllocationPools have changed
222+ if ! reflect .DeepEqual (oldSubnet .AllocationPools , newSubnet .AllocationPools ) {
223+ allErrs = append (allErrs , field .Forbidden (
224+ field .NewPath ("spec" , "managedSubnets" ).Child ("allocationPools" ),
225+ "cannot modify allocation pools in existing subnet" ,
226+ ))
227+ }
228+
229+ newSubnetMap [newSubnet .CIDR ] = newSubnet
230+ }
231+
232+ // Create modified copies of the subnets with DNSNameservers cleared
233+ oldSubnets := make ([]infrav1.SubnetSpec , 0 , len (oldObj .Spec .ManagedSubnets ))
234+ newSubnets := make ([]infrav1.SubnetSpec , 0 , len (newObj .Spec .ManagedSubnets ))
235+ for _ , subnet := range oldObj .Spec .ManagedSubnets {
236+ subnetCopy := subnet
237+ subnetCopy .DNSNameservers = nil
238+ oldSubnets = append (oldSubnets , subnetCopy )
239+
240+ if newSubnet , exists := newSubnetMap [subnet .CIDR ]; exists {
241+ newSubnetCopy := newSubnet
242+ newSubnetCopy .DNSNameservers = nil
243+ newSubnets = append (newSubnets , newSubnetCopy )
244+ }
245+ }
246+
247+ oldObj .Spec .ManagedSubnets = oldSubnets
248+ newObj .Spec .ManagedSubnets = newSubnets
249+ }
250+ }
251+
196252 // Allow changes on AllowedCIDRs
197253 if newObj .Spec .APIServerLoadBalancer != nil && oldObj .Spec .APIServerLoadBalancer != nil {
198254 oldObj .Spec .APIServerLoadBalancer .AllowedCIDRs = []string {}
0 commit comments