Skip to content

Commit

Permalink
resolve hairpinning (#268)
Browse files Browse the repository at this point in the history
* resolve hairpinning

* added docs

* fix lint

* fix lint

* remove ip from ingress

* removed ip from ingress

* lint fix
  • Loading branch information
happytreees authored Aug 19, 2024
1 parent 7a6fc66 commit f180da4
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 7 deletions.
4 changes: 4 additions & 0 deletions docs/load-balancers.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ The annotations are listed below. Please note that all annotations listed below
| `node-count` | int | 1 | Number of LoadBalancer nodes to have. Only odd numbers are supported. |
| `create` | `true` or `false` | `true` | This is used to determine whether or not to create a Vultr loadbalancer |
| `label` | string | | Custom label for the Vultr Loadbalancer rather than the default generated name |
| `hostname` | string | | Custom domain to be used for the load balancer. Ex: `example.vultr.com`



2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/vultr/vultr-cloud-controller-manager
go 1.21

require (
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
github.com/spf13/pflag v1.0.5
github.com/vultr/govultr/v3 v3.8.1
github.com/vultr/metadata v1.1.0
Expand All @@ -21,7 +22,6 @@ require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
Expand Down
47 changes: 41 additions & 6 deletions vultr/loadbalancers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strconv"
"strings"

"github.com/asaskevich/govalidator"
"github.com/vultr/govultr/v3"
"github.com/vultr/metadata"
v1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -51,6 +52,9 @@ const (
// annoVultrLBBackendProtocol backend protocol
annoVultrLBBackendProtocol = "service.beta.kubernetes.io/vultr-loadbalancer-backend-protocol"

// annoVultrHostname is the hostname used for VLB to prevent hairpinning
annoVultrHostname = "service.beta.kubernetes.io/vultr-loadbalancer-hostname"

annoVultrHealthCheckPath = "service.beta.kubernetes.io/vultr-loadbalancer-healthcheck-path"
annoVultrHealthCheckProtocol = "service.beta.kubernetes.io/vultr-loadbalancer-healthcheck-protocol"
annoVultrHealthCheckPort = "service.beta.kubernetes.io/vultr-loadbalancer-healthcheck-port"
Expand Down Expand Up @@ -116,11 +120,25 @@ func (l *loadbalancers) GetLoadBalancer(ctx context.Context, _ string, service *

enabledIPv6 := checkEnabledIPv6(service)
var ingress []v1.LoadBalancerIngress
hostname := lb.Label //nolint

ingress = append(ingress, v1.LoadBalancerIngress{Hostname: lb.Label, IP: lb.IPV4})
// Check if hostname annotation is blank and set if not
if _, ok := service.Annotations[annoVultrHostname]; ok {
if service.Annotations[annoVultrHostname] != "" {
if govalidator.IsDNSName(service.Annotations[annoVultrHostname]) {
hostname = service.Annotations[annoVultrHostname]
} else {
return nil, true, fmt.Errorf("hostname %s is not a valid DNS name", service.Annotations[annoVultrHostname])
}
klog.Infof("setting hostname for loadbalancer to: %s", hostname)
ingress = append(ingress, v1.LoadBalancerIngress{Hostname: hostname})
}
} else {
ingress = append(ingress, v1.LoadBalancerIngress{Hostname: hostname, IP: lb.IPV4})

if enabledIPv6 {
ingress = append(ingress, v1.LoadBalancerIngress{Hostname: lb.Label, IP: lb.IPV6})
if enabledIPv6 {
ingress = append(ingress, v1.LoadBalancerIngress{Hostname: hostname, IP: lb.IPV6})
}
}

return &v1.LoadBalancerStatus{
Expand Down Expand Up @@ -194,10 +212,24 @@ func (l *loadbalancers) EnsureLoadBalancer(ctx context.Context, clusterName stri
enabledIPv6 := checkEnabledIPv6(service)
var ingress []v1.LoadBalancerIngress

ingress = append(ingress, v1.LoadBalancerIngress{Hostname: lb2.Label, IP: lb2.IPV4})
hostname := lb2.Label //nolint
// Check if hostname annotation is blank and set if not
if _, ok := service.Annotations[annoVultrHostname]; ok {
if service.Annotations[annoVultrHostname] != "" {
if govalidator.IsDNSName(service.Annotations[annoVultrHostname]) {
hostname = service.Annotations[annoVultrHostname]
} else {
return nil, fmt.Errorf("hostname %s is not a valid DNS name", service.Annotations[annoVultrHostname])
}
klog.Infof("setting hostname for loadbalancer to: %s", hostname)
ingress = append(ingress, v1.LoadBalancerIngress{Hostname: hostname})
}
} else {
ingress = append(ingress, v1.LoadBalancerIngress{IP: lb2.IPV4})

if enabledIPv6 {
ingress = append(ingress, v1.LoadBalancerIngress{Hostname: lb2.Label, IP: lb2.IPV6})
if enabledIPv6 {
ingress = append(ingress, v1.LoadBalancerIngress{IP: lb2.IPV6})
}
}

return &v1.LoadBalancerStatus{
Expand All @@ -220,6 +252,9 @@ func (l *loadbalancers) EnsureLoadBalancer(ctx context.Context, clusterName stri

// Set the Vultr VLB ID annotation
if _, ok := service.Annotations[annoVultrLoadBalancerID]; !ok {
if service.Annotations == nil {
service.Annotations = make(map[string]string)
}
service.Annotations[annoVultrLoadBalancerID] = lb.ID
if err = l.GetKubeClient(); err != nil {
return nil, fmt.Errorf("failed to get kubeclient to update service: %s", err)
Expand Down

0 comments on commit f180da4

Please sign in to comment.