Skip to content

Commit fc674e0

Browse files
Merge pull request #9144 from rna-afk/fix_lbip_defaulting
OCPBUGS-43724: Fix Load balancer IP setup
2 parents 7f928a3 + 71713ba commit fc674e0

File tree

1 file changed

+108
-21
lines changed

1 file changed

+108
-21
lines changed

pkg/asset/manifests/azure/cluster.go

Lines changed: 108 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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,15 +294,71 @@ 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
}
@@ -273,11 +368,7 @@ func getNextAvailableIP(ctx context.Context, installConfig *installconfig.Instal
273368
ipAvail := *availableIP
274369
if ipAvail.Available != nil && *ipAvail.Available {
275370
for _, cidrRange := range machineCidr {
276-
_, ipnet, err := net.ParseCIDR(cidrRange.CIDR.String())
277-
if err != nil {
278-
return "", fmt.Errorf("failed to get machine network CIDR: %w", err)
279-
}
280-
if ipnet.Contains(net.ParseIP(lbip)) {
371+
if cidrRange.CIDR.Contains(net.ParseIP(lbip)) {
281372
return lbip, nil
282373
}
283374
}
@@ -287,11 +378,7 @@ func getNextAvailableIP(ctx context.Context, installConfig *installconfig.Instal
287378
}
288379
for _, ip := range *ipAvail.AvailableIPAddresses {
289380
for _, cidrRange := range machineCidr {
290-
_, ipnet, err := net.ParseCIDR(cidrRange.CIDR.String())
291-
if err != nil {
292-
return "", fmt.Errorf("failed to get machine network CIDR: %w", err)
293-
}
294-
if ipnet.Contains(net.ParseIP(ip)) {
381+
if cidrRange.CIDR.Contains(net.ParseIP(lbip)) {
295382
return ip, nil
296383
}
297384
}

0 commit comments

Comments
 (0)