@@ -17,6 +17,7 @@ import (
1717 azic "github.com/openshift/installer/pkg/asset/installconfig/azure"
1818 "github.com/openshift/installer/pkg/asset/manifests/capiutils"
1919 "github.com/openshift/installer/pkg/asset/manifests/capiutils/cidr"
20+ "github.com/openshift/installer/pkg/ipnet"
2021 "github.com/openshift/installer/pkg/types"
2122 "github.com/openshift/installer/pkg/types/azure"
2223)
@@ -104,6 +105,48 @@ func GenerateClusterAssets(installConfig *installconfig.InstallConfig, clusterID
104105 }
105106
106107 virtualNetworkID := ""
108+ lbip := capz .DefaultInternalLBIPAddress
109+ lbip = getIPWithinCIDR (subnets , lbip )
110+
111+ if controlPlaneSub := installConfig .Config .Azure .ControlPlaneSubnet ; controlPlaneSub != "" {
112+ client , err := installConfig .Azure .Client ()
113+ if err != nil {
114+ return nil , fmt .Errorf ("failed to get azure client: %w" , err )
115+ }
116+ ctx := context .TODO ()
117+ controlPlaneSubnet , err := client .GetControlPlaneSubnet (ctx , installConfig .Config .Azure .NetworkResourceGroupName , installConfig .Config .Azure .VirtualNetwork , controlPlaneSub )
118+ if err != nil || controlPlaneSubnet == nil {
119+ return nil , fmt .Errorf ("failed to get azure control plane subnet: %w" , err )
120+ } else if controlPlaneSubnet .AddressPrefixes == nil && controlPlaneSubnet .AddressPrefix == nil {
121+ return nil , fmt .Errorf ("failed to get azure control plane subnet addresses: %w" , err )
122+ }
123+ subnetList := []* net.IPNet {}
124+ if controlPlaneSubnet .AddressPrefixes != nil {
125+ for _ , sub := range * controlPlaneSubnet .AddressPrefixes {
126+ _ , ipnet , err := net .ParseCIDR (sub )
127+ if err != nil {
128+ return nil , fmt .Errorf ("failed to get translate azure control plane subnet addresses: %w" , err )
129+ }
130+ subnetList = append (subnetList , ipnet )
131+ }
132+ }
133+
134+ if controlPlaneSubnet .AddressPrefix != nil {
135+ _ , ipnet , err := net .ParseCIDR (* controlPlaneSubnet .AddressPrefix )
136+ if err != nil {
137+ return nil , fmt .Errorf ("failed to get translate azure control plane subnet address prefix: %w" , err )
138+ }
139+ subnetList = append (subnetList , ipnet )
140+ }
141+ lbip = getIPWithinCIDR (subnetList , lbip )
142+ }
143+
144+ apiServerLB .FrontendIPs = []capz.FrontendIP {{
145+ Name : fmt .Sprintf ("%s-internal-frontEnd" , clusterID .InfraID ),
146+ FrontendIPClass : capz.FrontendIPClass {
147+ PrivateIPAddress : lbip ,
148+ },
149+ }}
107150 if installConfig .Config .Azure .VirtualNetwork != "" {
108151 client , err := installConfig .Azure .Client ()
109152 if err != nil {
@@ -117,16 +160,12 @@ func GenerateClusterAssets(installConfig *installconfig.InstallConfig, clusterID
117160 if virtualNetwork != nil {
118161 virtualNetworkID = * virtualNetwork .ID
119162 }
120- lbip , err := getNextAvailableIP (ctx , installConfig )
163+ lbip , err := getNextAvailableIPForLoadBalancer (ctx , installConfig , lbip )
121164 if err != nil {
122165 return nil , err
123166 }
124- apiServerLB .FrontendIPs = []capz.FrontendIP {{
125- Name : fmt .Sprintf ("%s-internal-frontEnd" , clusterID .InfraID ),
126- FrontendIPClass : capz.FrontendIPClass {
127- PrivateIPAddress : lbip ,
128- },
129- },
167+ apiServerLB .FrontendIPs [0 ].FrontendIPClass = capz.FrontendIPClass {
168+ PrivateIPAddress : lbip ,
130169 }
131170 }
132171
@@ -255,25 +294,77 @@ func GenerateClusterAssets(installConfig *installconfig.InstallConfig, clusterID
255294 }, nil
256295}
257296
258- func getNextAvailableIP (ctx context.Context , installConfig * installconfig.InstallConfig ) (string , error ) {
259- lbip := capz .DefaultInternalLBIPAddress
260- machineCidr := installConfig .Config .MachineNetwork
297+ func getIPWithinCIDR (subnets []* net.IPNet , ip string ) string {
298+ if subnets == nil || ip == "" {
299+ return ""
300+ }
301+ // Check if default lbip is within control plane network.
302+ // If not in control plane network, assign the first non-reserved IP in the CIDR to lbip.
303+ for _ , subnet := range subnets {
304+ if subnet == nil {
305+ continue
306+ }
307+ if subnet .Contains (net .ParseIP (ip )) {
308+ return ip
309+ }
310+ }
311+ ipSubnets := make (net.IP , len (subnets [0 ].IP ))
312+ copy (ipSubnets , subnets [0 ].IP )
313+ // Since the first 4 IP of the subnets are usually reserved[1], pick the next one that's available in the CIDR.
314+ // [1] - https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/private-ip-addresses#allocation-method
315+ ipSubnets [len (ipSubnets )- 1 ] += 4
316+ return ipSubnets .String ()
317+ }
318+
319+ func getNextAvailableIPForLoadBalancer (ctx context.Context , installConfig * installconfig.InstallConfig , lbip string ) (string , error ) {
261320 client , err := installConfig .Azure .Client ()
262321 if err != nil {
263322 return "" , fmt .Errorf ("failed to get azure client: %w" , err )
264323 }
324+ networkResourceGroupName := installConfig .Config .Azure .NetworkResourceGroupName
325+ virtualNetworkName := installConfig .Config .Azure .VirtualNetwork
326+ machineCidr := installConfig .Config .MachineNetwork
327+ if cpSubnet := installConfig .Config .Azure .ControlPlaneSubnet ; cpSubnet != "" {
328+ controlPlane , err := client .GetControlPlaneSubnet (ctx , networkResourceGroupName , virtualNetworkName , cpSubnet )
329+ if err != nil {
330+ return "" , fmt .Errorf ("failed to get control plane subnet: %w" , err )
331+ }
332+ if controlPlane .AddressPrefix == nil && controlPlane .AddressPrefixes == nil {
333+ return "" , fmt .Errorf ("failed to get control plane subnet addresses: %w" , err )
334+ }
335+ prefixes := []* ipnet.IPNet {}
336+ if controlPlane .AddressPrefixes != nil {
337+ for _ , sub := range * controlPlane .AddressPrefixes {
338+ ipnet , err := ipnet .ParseCIDR (sub )
339+ if err != nil {
340+ return "" , fmt .Errorf ("failed to get translate azure control plane subnet addresses: %w" , err )
341+ }
342+ prefixes = append (prefixes , ipnet )
343+ }
344+ }
265345
266- availableIP , err := client .CheckIPAddressAvailability (ctx , installConfig .Config .Azure .NetworkResourceGroupName , installConfig .Config .Azure .VirtualNetwork , lbip )
346+ if controlPlane .AddressPrefix != nil {
347+ ipnet , err := ipnet .ParseCIDR (* controlPlane .AddressPrefix )
348+ if err != nil {
349+ return "" , fmt .Errorf ("failed to get translate azure control plane subnet address prefix: %w" , err )
350+ }
351+ prefixes = append (prefixes , ipnet )
352+ }
353+ cidrRange := []types.MachineNetworkEntry {}
354+ for _ , prefix := range prefixes {
355+ if prefix != nil {
356+ cidrRange = append (cidrRange , types.MachineNetworkEntry {CIDR : * prefix })
357+ }
358+ }
359+ machineCidr = cidrRange
360+ }
361+ availableIP , err := client .CheckIPAddressAvailability (ctx , networkResourceGroupName , virtualNetworkName , lbip )
267362 if err != nil {
268363 return "" , fmt .Errorf ("failed to get azure ip availability: %w" , err )
269364 }
270365 if * availableIP .Available {
271366 for _ , cidrRange := range machineCidr {
272- _ , ipnet , err := net .ParseCIDR (cidrRange .CIDR .String ())
273- if err != nil {
274- return "" , fmt .Errorf ("failed to get machine network CIDR: %w" , err )
275- }
276- if ipnet .Contains (net .ParseIP (lbip )) {
367+ if cidrRange .CIDR .Contains (net .ParseIP (lbip )) {
277368 return lbip , nil
278369 }
279370 }
@@ -283,11 +374,7 @@ func getNextAvailableIP(ctx context.Context, installConfig *installconfig.Instal
283374 }
284375 for _ , ip := range * availableIP .AvailableIPAddresses {
285376 for _ , cidrRange := range machineCidr {
286- _ , ipnet , err := net .ParseCIDR (cidrRange .CIDR .String ())
287- if err != nil {
288- return "" , fmt .Errorf ("failed to get machine network CIDR: %w" , err )
289- }
290- if ipnet .Contains (net .ParseIP (ip )) {
377+ if cidrRange .CIDR .Contains (net .ParseIP (lbip )) {
291378 return ip , nil
292379 }
293380 }
0 commit comments