@@ -139,6 +139,62 @@ func (*openStackClusterWebhook) ValidateUpdate(_ context.Context, oldObjRaw, new
139139 newObj .Spec .ManagedSecurityGroups .AllowAllInClusterTraffic = false
140140 }
141141
142+ // Allow changes only to DNSNameservers in ManagedSubnets spec
143+ if newObj .Spec .ManagedSubnets != nil && oldObj .Spec .ManagedSubnets != nil {
144+ // Check if any fields other than DNSNameservers have changed
145+ if len (oldObj .Spec .ManagedSubnets ) != len (newObj .Spec .ManagedSubnets ) {
146+ allErrs = append (allErrs , field .Forbidden (field .NewPath ("spec" , "managedSubnets" ), "cannot add or remove subnets" ))
147+ } else {
148+ // Build maps of subnets by CIDR
149+ oldSubnetMap := make (map [string ]infrav1.SubnetSpec )
150+ newSubnetMap := make (map [string ]infrav1.SubnetSpec )
151+
152+ for _ , subnet := range oldObj .Spec .ManagedSubnets {
153+ oldSubnetMap [subnet .CIDR ] = subnet
154+ }
155+
156+ // Check if all new subnets have matching old subnets with the same CIDR
157+ for _ , newSubnet := range newObj .Spec .ManagedSubnets {
158+ oldSubnet , exists := oldSubnetMap [newSubnet .CIDR ]
159+ if ! exists {
160+ allErrs = append (allErrs , field .Forbidden (
161+ field .NewPath ("spec" , "managedSubnets" ),
162+ fmt .Sprintf ("cannot change subnet CIDR from existing value to %s" , newSubnet .CIDR ),
163+ ))
164+ continue
165+ }
166+
167+ // Check if AllocationPools have changed
168+ if ! reflect .DeepEqual (oldSubnet .AllocationPools , newSubnet .AllocationPools ) {
169+ allErrs = append (allErrs , field .Forbidden (
170+ field .NewPath ("spec" , "managedSubnets" ).Child ("allocationPools" ),
171+ "cannot modify allocation pools in existing subnet" ,
172+ ))
173+ }
174+
175+ newSubnetMap [newSubnet .CIDR ] = newSubnet
176+ }
177+
178+ // Create modified copies of the subnets with DNSNameservers cleared
179+ oldSubnets := make ([]infrav1.SubnetSpec , 0 , len (oldObj .Spec .ManagedSubnets ))
180+ newSubnets := make ([]infrav1.SubnetSpec , 0 , len (newObj .Spec .ManagedSubnets ))
181+ for _ , subnet := range oldObj .Spec .ManagedSubnets {
182+ subnetCopy := subnet
183+ subnetCopy .DNSNameservers = nil
184+ oldSubnets = append (oldSubnets , subnetCopy )
185+
186+ if newSubnet , exists := newSubnetMap [subnet .CIDR ]; exists {
187+ newSubnetCopy := newSubnet
188+ newSubnetCopy .DNSNameservers = nil
189+ newSubnets = append (newSubnets , newSubnetCopy )
190+ }
191+ }
192+
193+ oldObj .Spec .ManagedSubnets = oldSubnets
194+ newObj .Spec .ManagedSubnets = newSubnets
195+ }
196+ }
197+
142198 // Allow changes on AllowedCIDRs
143199 if newObj .Spec .APIServerLoadBalancer != nil && oldObj .Spec .APIServerLoadBalancer != nil {
144200 oldObj .Spec .APIServerLoadBalancer .AllowedCIDRs = []string {}
0 commit comments