Skip to content

Commit 82b3122

Browse files
authored
Merge pull request #1738 from shiftstack/issue_1714
🐛 loadbalancer: resolve ControlPlaneEndpoint.Host when needed
2 parents 5b2cc5b + b319893 commit 82b3122

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

pkg/cloud/services/loadbalancer/loadbalancer.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ limitations under the License.
1717
package loadbalancer
1818

1919
import (
20+
"context"
2021
"errors"
2122
"fmt"
23+
"net"
2224
"slices"
2325
"time"
2426

@@ -27,7 +29,7 @@ import (
2729
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/monitors"
2830
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/pools"
2931
"k8s.io/apimachinery/pkg/util/wait"
30-
"k8s.io/utils/net"
32+
utilsnet "k8s.io/utils/net"
3133
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
3234
"sigs.k8s.io/cluster-api/util"
3335

@@ -42,10 +44,28 @@ import (
4244
const (
4345
networkPrefix string = "k8s-clusterapi"
4446
kubeapiLBSuffix string = "kubeapi"
47+
resolvedMsg string = "ControlPlaneEndpoint.Host is not an IP address, using the first resolved IP address"
4548
)
4649

4750
const loadBalancerProvisioningStatusActive = "ACTIVE"
4851

52+
// We wrap the LookupHost function in a variable to allow overriding it in unit tests.
53+
//
54+
//nolint:gocritic
55+
var lookupHost = func(host string) (string, error) {
56+
ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second)
57+
defer cancel()
58+
ips, err := net.DefaultResolver.LookupHost(ctx, host)
59+
if err != nil {
60+
return "", err
61+
}
62+
if ip := net.ParseIP(ips[0]); ip == nil {
63+
return "", fmt.Errorf("failed to resolve IP address for host %s", host)
64+
}
65+
return ips[0], nil
66+
}
67+
68+
// ReconcileLoadBalancer reconciles the load balancer for the given cluster.
4969
func (s *Service) ReconcileLoadBalancer(openStackCluster *infrav1.OpenStackCluster, clusterName string, apiServerPort int) (bool, error) {
5070
loadBalancerName := getLoadBalancerName(clusterName)
5171
s.scope.Logger().Info("Reconciling load balancer", "name", loadBalancerName)
@@ -57,13 +77,18 @@ func (s *Service) ReconcileLoadBalancer(openStackCluster *infrav1.OpenStackClust
5777
}
5878

5979
var fixedIPAddress string
80+
var err error
81+
6082
switch {
6183
case lbStatus.InternalIP != "":
6284
fixedIPAddress = lbStatus.InternalIP
6385
case openStackCluster.Spec.APIServerFixedIP != "":
6486
fixedIPAddress = openStackCluster.Spec.APIServerFixedIP
6587
case openStackCluster.Spec.DisableAPIServerFloatingIP && openStackCluster.Spec.ControlPlaneEndpoint.IsValid():
66-
fixedIPAddress = openStackCluster.Spec.ControlPlaneEndpoint.Host
88+
fixedIPAddress, err = lookupHost(openStackCluster.Spec.ControlPlaneEndpoint.Host)
89+
if err != nil {
90+
return false, fmt.Errorf("lookup host: %w", err)
91+
}
6792
}
6893

6994
providers, err := s.loadbalancerClient.ListLoadBalancerProviders()
@@ -108,7 +133,10 @@ func (s *Service) ReconcileLoadBalancer(openStackCluster *infrav1.OpenStackClust
108133
case openStackCluster.Spec.APIServerFloatingIP != "":
109134
floatingIPAddress = openStackCluster.Spec.APIServerFloatingIP
110135
case openStackCluster.Spec.ControlPlaneEndpoint.IsValid():
111-
floatingIPAddress = openStackCluster.Spec.ControlPlaneEndpoint.Host
136+
floatingIPAddress, err = lookupHost(openStackCluster.Spec.ControlPlaneEndpoint.Host)
137+
if err != nil {
138+
return false, fmt.Errorf("lookup host: %w", err)
139+
}
112140
}
113141
fp, err := s.networkingService.GetOrCreateFloatingIP(openStackCluster, openStackCluster, clusterName, floatingIPAddress)
114142
if err != nil {
@@ -308,9 +336,9 @@ func validateIPs(openStackCluster *infrav1.OpenStackCluster, definedCIDRs []stri
308336

309337
for _, v := range definedCIDRs {
310338
switch {
311-
case net.IsIPv4String(v):
339+
case utilsnet.IsIPv4String(v):
312340
marshaledCIDRs = append(marshaledCIDRs, v+"/32")
313-
case net.IsIPv4CIDRString(v):
341+
case utilsnet.IsIPv4CIDRString(v):
314342
marshaledCIDRs = append(marshaledCIDRs, v)
315343
default:
316344
record.Warnf(openStackCluster, "FailedIPAddressValidation", "%s is not a valid IPv4 nor CIDR address and will not get applied to allowed_cidrs", v)

pkg/cloud/services/loadbalancer/loadbalancer_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package loadbalancer
1818

1919
import (
20+
"errors"
21+
"net"
2022
"testing"
2123

2224
"github.com/go-logr/logr"
@@ -28,6 +30,7 @@ import (
2830
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/pools"
2931
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/providers"
3032
. "github.com/onsi/gomega"
33+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
3134

3235
infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8"
3336
"sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock"
@@ -38,9 +41,24 @@ func Test_ReconcileLoadBalancer(t *testing.T) {
3841
mockCtrl := gomock.NewController(t)
3942
defer mockCtrl.Finish()
4043

44+
// Stub the call to net.LookupHost
45+
lookupHost = func(host string) (addrs string, err error) {
46+
if net.ParseIP(host) != nil {
47+
return host, nil
48+
} else if host == "api.test-cluster.test" {
49+
ips := []string{"192.168.100.10"}
50+
return ips[0], nil
51+
}
52+
return "", errors.New("Unknown Host " + host)
53+
}
54+
4155
openStackCluster := &infrav1.OpenStackCluster{
4256
Spec: infrav1.OpenStackClusterSpec{
4357
DisableAPIServerFloatingIP: true,
58+
ControlPlaneEndpoint: clusterv1.APIEndpoint{
59+
Host: "api.test-cluster.test",
60+
Port: 6443,
61+
},
4462
},
4563
Status: infrav1.OpenStackClusterStatus{
4664
ExternalNetwork: &infrav1.NetworkStatus{

0 commit comments

Comments
 (0)