Skip to content

Commit

Permalink
loadbalancer: resolve ControlPlaneEndpoint.Host when needed
Browse files Browse the repository at this point in the history
`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.
  • Loading branch information
EmilienM committed Nov 2, 2023
1 parent 5968640 commit 1c44a80
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 5 deletions.
34 changes: 29 additions & 5 deletions pkg/cloud/services/loadbalancer/loadbalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package loadbalancer
import (
"errors"
"fmt"
"net"
"reflect"
"time"

Expand All @@ -27,7 +28,7 @@ import (
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/monitors"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/pools"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/utils/net"
utilsnet "k8s.io/utils/net"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util"

Expand All @@ -46,16 +47,32 @@ const (

const loadBalancerProvisioningStatusActive = "ACTIVE"

// We wrap the net.LookupHost function in a variable to allow overriding it in unit tests.
//
//nolint:gocritic
var lookupHost = func(host string) ([]string, error) {
return net.LookupHost(host)
}

func (s *Service) ReconcileLoadBalancer(openStackCluster *infrav1.OpenStackCluster, clusterName string, apiServerPort int) (bool, error) {
loadBalancerName := getLoadBalancerName(clusterName)
s.scope.Logger().Info("Reconciling load balancer", "name", loadBalancerName)

var fixedIPAddress string
var err error

switch {
case openStackCluster.Spec.APIServerFixedIP != "":
fixedIPAddress = openStackCluster.Spec.APIServerFixedIP
case openStackCluster.Spec.DisableAPIServerFloatingIP && openStackCluster.Spec.ControlPlaneEndpoint.IsValid():
fixedIPAddress = openStackCluster.Spec.ControlPlaneEndpoint.Host
ips, err := lookupHost(openStackCluster.Spec.ControlPlaneEndpoint.Host)
if err != nil {
return false, fmt.Errorf("lookup host: %w", err)
}
fixedIPAddress = ips[0]
if net.ParseIP(fixedIPAddress) == nil {
s.scope.Logger().Info("ControlPlaneEndpoint.Host is not an IP address, using the first resolved IP address", "host", openStackCluster.Spec.ControlPlaneEndpoint.Host, "ip", fixedIPAddress)
}
}

providers, err := s.loadbalancerClient.ListLoadBalancerProviders()
Expand Down Expand Up @@ -93,7 +110,14 @@ func (s *Service) ReconcileLoadBalancer(openStackCluster *infrav1.OpenStackClust
case openStackCluster.Spec.APIServerFloatingIP != "":
floatingIPAddress = openStackCluster.Spec.APIServerFloatingIP
case openStackCluster.Spec.ControlPlaneEndpoint.IsValid():
floatingIPAddress = openStackCluster.Spec.ControlPlaneEndpoint.Host
ips, err := lookupHost(openStackCluster.Spec.ControlPlaneEndpoint.Host)
if err != nil {
return false, fmt.Errorf("lookup host: %w", err)
}
floatingIPAddress = ips[0]
if net.ParseIP(floatingIPAddress) == nil {
s.scope.Logger().Info("ControlPlaneEndpoint.Host is not an IP address, using the first resolved IP address", "host", openStackCluster.Spec.ControlPlaneEndpoint.Host, "ip", floatingIPAddress)
}
}
fp, err := s.networkingService.GetOrCreateFloatingIP(openStackCluster, openStackCluster, clusterName, floatingIPAddress)
if err != nil {
Expand Down Expand Up @@ -294,9 +318,9 @@ func validateIPs(openStackCluster *infrav1.OpenStackCluster, definedCIDRs []stri

for _, v := range definedCIDRs {
switch {
case net.IsIPv4String(v):
case utilsnet.IsIPv4String(v):
marshaledCIDRs = append(marshaledCIDRs, v+"/32")
case net.IsIPv4CIDRString(v):
case utilsnet.IsIPv4CIDRString(v):
marshaledCIDRs = append(marshaledCIDRs, v)
default:
record.Warnf(openStackCluster, "FailedIPAddressValidation", "%s is not a valid IPv4 nor CIDR address and will not get applied to allowed_cidrs", v)
Expand Down
18 changes: 18 additions & 0 deletions pkg/cloud/services/loadbalancer/loadbalancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
package loadbalancer

import (
"errors"
"net"
"testing"

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

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

// Stub the call to net.LookupHost
lookupHost = func(host string) (addrs []string, err error) {
if net.ParseIP(host) != nil {
return []string{host}, nil
} else if host == "api.test-cluster.test" {
ips := []string{"192.168.100.10"}
return ips, nil
}
return nil, errors.New("Unknown Host " + host)
}

openStackCluster := &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{
DisableAPIServerFloatingIP: true,
ControlPlaneEndpoint: clusterv1.APIEndpoint{
Host: "api.test-cluster.test",
Port: 6443,
},
},
Status: infrav1.OpenStackClusterStatus{
ExternalNetwork: &infrav1.NetworkStatus{
Expand Down

0 comments on commit 1c44a80

Please sign in to comment.