Skip to content

Commit 65a4089

Browse files
committed
loadbalancer: resolve ControlPlaneEndpoint.Host when needed
`ControlPlaneEndpoint.Host` is not guaranteed to be an IP address, it can also be an hostname. Now we'll try to lookup the hostname if it's not an IP and set that for the LB VipAddress.
1 parent ca25160 commit 65a4089

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

pkg/cloud/services/loadbalancer/loadbalancer.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package loadbalancer
1919
import (
2020
"errors"
2121
"fmt"
22+
"net"
2223
"reflect"
2324
"time"
2425

@@ -27,7 +28,7 @@ import (
2728
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/monitors"
2829
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/pools"
2930
"k8s.io/apimachinery/pkg/util/wait"
30-
"k8s.io/utils/net"
31+
utilsnet "k8s.io/utils/net"
3132
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
3233
"sigs.k8s.io/cluster-api/util"
3334

@@ -42,20 +43,37 @@ import (
4243
const (
4344
networkPrefix string = "k8s-clusterapi"
4445
kubeapiLBSuffix string = "kubeapi"
46+
resolvedMsg string = "ControlPlaneEndpoint.Host is not an IP address, using the first resolved IP address"
4547
)
4648

4749
const loadBalancerProvisioningStatusActive = "ACTIVE"
4850

51+
// We wrap the net.LookupHost function in a variable to allow overriding it in unit tests.
52+
//
53+
//nolint:gocritic
54+
var lookupHost = func(host string) ([]string, error) {
55+
return net.LookupHost(host)
56+
}
57+
4958
func (s *Service) ReconcileLoadBalancer(openStackCluster *infrav1.OpenStackCluster, clusterName string, apiServerPort int) (bool, error) {
5059
loadBalancerName := getLoadBalancerName(clusterName)
5160
s.scope.Logger().Info("Reconciling load balancer", "name", loadBalancerName)
5261

5362
var fixedIPAddress string
63+
var err error
64+
5465
switch {
5566
case openStackCluster.Spec.APIServerFixedIP != "":
5667
fixedIPAddress = openStackCluster.Spec.APIServerFixedIP
5768
case openStackCluster.Spec.DisableAPIServerFloatingIP && openStackCluster.Spec.ControlPlaneEndpoint.IsValid():
58-
fixedIPAddress = openStackCluster.Spec.ControlPlaneEndpoint.Host
69+
ips, err := lookupHost(openStackCluster.Spec.ControlPlaneEndpoint.Host)
70+
if err != nil {
71+
return false, fmt.Errorf("lookup host: %w", err)
72+
}
73+
fixedIPAddress = ips[0]
74+
if net.ParseIP(fixedIPAddress) == nil {
75+
s.scope.Logger().Info(resolvedMsg, "host", openStackCluster.Spec.ControlPlaneEndpoint.Host, "ip", fixedIPAddress)
76+
}
5977
}
6078

6179
providers, err := s.loadbalancerClient.ListLoadBalancerProviders()
@@ -93,7 +111,14 @@ func (s *Service) ReconcileLoadBalancer(openStackCluster *infrav1.OpenStackClust
93111
case openStackCluster.Spec.APIServerFloatingIP != "":
94112
floatingIPAddress = openStackCluster.Spec.APIServerFloatingIP
95113
case openStackCluster.Spec.ControlPlaneEndpoint.IsValid():
96-
floatingIPAddress = openStackCluster.Spec.ControlPlaneEndpoint.Host
114+
ips, err := lookupHost(openStackCluster.Spec.ControlPlaneEndpoint.Host)
115+
if err != nil {
116+
return false, fmt.Errorf("lookup host: %w", err)
117+
}
118+
floatingIPAddress = ips[0]
119+
if net.ParseIP(floatingIPAddress) == nil {
120+
s.scope.Logger().Info(resolvedMsg, "host", openStackCluster.Spec.ControlPlaneEndpoint.Host, "ip", floatingIPAddress)
121+
}
97122
}
98123
fp, err := s.networkingService.GetOrCreateFloatingIP(openStackCluster, openStackCluster, clusterName, floatingIPAddress)
99124
if err != nil {
@@ -294,9 +319,9 @@ func validateIPs(openStackCluster *infrav1.OpenStackCluster, definedCIDRs []stri
294319

295320
for _, v := range definedCIDRs {
296321
switch {
297-
case net.IsIPv4String(v):
322+
case utilsnet.IsIPv4String(v):
298323
marshaledCIDRs = append(marshaledCIDRs, v+"/32")
299-
case net.IsIPv4CIDRString(v):
324+
case utilsnet.IsIPv4CIDRString(v):
300325
marshaledCIDRs = append(marshaledCIDRs, v)
301326
default:
302327
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/v1alpha7"
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 []string{host}, nil
48+
} else if host == "api.test-cluster.test" {
49+
ips := []string{"192.168.100.10"}
50+
return ips, nil
51+
}
52+
return nil, 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)