Skip to content

Commit

Permalink
Add option to disable IPv6 for load balancers
Browse files Browse the repository at this point in the history
Enabling IPv6 by default in #137 broke clusters using external-dns. This
commit adds an option to disable IPv6 by setting the

    load-balancer.hetzner.cloud/ipv6-disabled

annotation to true.

Closes #191
  • Loading branch information
fhofherr committed May 6, 2021
1 parent 13cac63 commit b54847b
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 15 deletions.
35 changes: 23 additions & 12 deletions hcloud/load_balancers.go
Expand Up @@ -59,14 +59,23 @@ func (l *loadBalancers) GetLoadBalancer(
}, true, nil
}

return &v1.LoadBalancerStatus{Ingress: []v1.LoadBalancerIngress{
ingresses := []v1.LoadBalancerIngress{
{
IP: lb.PublicNet.IPv4.IP.String(),
},
{
}

disableIPV6, err := annotation.LBIPv6Disabled.BoolFromService(service)
if err != nil && !errors.Is(err, annotation.ErrNotSet) {
return nil, false, fmt.Errorf("%s: %v", op, err)
}
if !disableIPV6 {
ingresses = append(ingresses, v1.LoadBalancerIngress{
IP: lb.PublicNet.IPv6.IP.String(),
},
}}, true, nil
})
}

return &v1.LoadBalancerStatus{Ingress: ingresses}, true, nil
}

func (l *loadBalancers) GetLoadBalancerName(ctx context.Context, clusterName string, service *v1.Service) string {
Expand Down Expand Up @@ -165,15 +174,17 @@ func (l *loadBalancers) EnsureLoadBalancer(
if err != nil && !errors.Is(err, annotation.ErrNotSet) {
return nil, fmt.Errorf("%s: %w", op, err)
}

if !disablePubNet {
ingress = append(ingress,
v1.LoadBalancerIngress{
IP: lb.PublicNet.IPv4.IP.String(),
},
v1.LoadBalancerIngress{
IP: lb.PublicNet.IPv6.IP.String(),
},
)
ingress = append(ingress, v1.LoadBalancerIngress{IP: lb.PublicNet.IPv4.IP.String()})

disableIPV6, err := annotation.LBIPv6Disabled.BoolFromService(svc)
if err != nil && !errors.Is(err, annotation.ErrNotSet) {
return nil, fmt.Errorf("%s: %v", op, err)
}
if !disableIPV6 {
ingress = append(ingress, v1.LoadBalancerIngress{IP: lb.PublicNet.IPv6.IP.String()})
}
}

disablePrivIngress, err := l.getDisablePrivateIngress(svc)
Expand Down
66 changes: 63 additions & 3 deletions hcloud/load_balancers_test.go
Expand Up @@ -14,6 +14,35 @@ import (

func TestLoadBalancers_GetLoadBalancer(t *testing.T) {
tests := []LoadBalancerTestCase{
{
Name: "get load balancer without host name IPv6 disabled",
ServiceUID: "1",
ServiceAnnotations: map[annotation.Name]interface{}{
annotation.LBIPv6Disabled: true,
},
LB: &hcloud.LoadBalancer{
ID: 1,
Name: "no-host-name",
PublicNet: hcloud.LoadBalancerPublicNet{
IPv4: hcloud.LoadBalancerPublicNetIPv4{IP: net.ParseIP("1.2.3.4")},
},
},
Mock: func(t *testing.T, tt *LoadBalancerTestCase) {
tt.LBOps.
On("GetByK8SServiceUID", tt.Ctx, tt.Service).
Return(tt.LB, nil)
},
Perform: func(t *testing.T, tt *LoadBalancerTestCase) {
status, exists, err := tt.LoadBalancers.GetLoadBalancer(tt.Ctx, tt.ClusterName, tt.Service)
assert.NoError(t, err)
assert.True(t, exists)

if !assert.Len(t, status.Ingress, 1) {
return
}
assert.Equal(t, tt.LB.PublicNet.IPv4.IP.String(), status.Ingress[0].IP)
},
},
{
Name: "get load balancer without host name",
ServiceUID: "1",
Expand Down Expand Up @@ -132,6 +161,37 @@ func TestLoadBalancers_EnsureLoadBalancer_CreateLoadBalancer(t *testing.T) {
assert.EqualError(t, err, "hcloud/loadBalancers.EnsureLoadBalancer: test error")
},
},
{
Name: "public network only no ipv6",
ServiceUID: "2",
ServiceAnnotations: map[annotation.Name]interface{}{
annotation.LBName: "pub-net-only-no-ipv6",
annotation.LBIPv6Disabled: true,
},
LB: &hcloud.LoadBalancer{
ID: 1,
Name: "pub-net-only-no-ipv6",
LoadBalancerType: &hcloud.LoadBalancerType{Name: "lb11"},
Location: &hcloud.Location{Name: "nbg1", NetworkZone: hcloud.NetworkZoneEUCentral},
PublicNet: hcloud.LoadBalancerPublicNet{
Enabled: true,
IPv4: hcloud.LoadBalancerPublicNetIPv4{IP: net.ParseIP("1.2.3.4")},
},
},
Mock: func(t *testing.T, tt *LoadBalancerTestCase) {
setupSuccessMocks(tt, "pub-net-only-no-ipv6")
},
Perform: func(t *testing.T, tt *LoadBalancerTestCase) {
expected := &v1.LoadBalancerStatus{
Ingress: []v1.LoadBalancerIngress{
{IP: tt.LB.PublicNet.IPv4.IP.String()},
},
}
lbStat, err := tt.LoadBalancers.EnsureLoadBalancer(tt.Ctx, tt.ClusterName, tt.Service, tt.Nodes)
assert.NoError(t, err)
assert.Equal(t, expected, lbStat)
},
},
{
Name: "public network only",
ServiceUID: "2",
Expand Down Expand Up @@ -223,7 +283,7 @@ func TestLoadBalancers_EnsureLoadBalancer_CreateLoadBalancer(t *testing.T) {
PublicNet: hcloud.LoadBalancerPublicNet{
Enabled: true,
IPv4: hcloud.LoadBalancerPublicNetIPv4{IP: net.ParseIP("1.2.3.4")},
// IPv6: hcloud.LoadBalancerPublicNetIPv6{IP: net.ParseIP("fe80::1")},
IPv6: hcloud.LoadBalancerPublicNetIPv6{IP: net.ParseIP("fe80::1")},
},
PrivateNet: []hcloud.LoadBalancerPrivateNet{
{
Expand Down Expand Up @@ -256,7 +316,7 @@ func TestLoadBalancers_EnsureLoadBalancer_CreateLoadBalancer(t *testing.T) {
ServiceUID: "5",
ServiceAnnotations: map[annotation.Name]interface{}{
annotation.LBName: "with-priv-net-no-priv-ingress",
annotation.LBDisablePrivateIngress: "true",
annotation.LBDisablePrivateIngress: true,
},
LB: &hcloud.LoadBalancer{
ID: 1,
Expand All @@ -266,7 +326,7 @@ func TestLoadBalancers_EnsureLoadBalancer_CreateLoadBalancer(t *testing.T) {
PublicNet: hcloud.LoadBalancerPublicNet{
Enabled: true,
IPv4: hcloud.LoadBalancerPublicNetIPv4{IP: net.ParseIP("1.2.3.4")},
// IPv6: hcloud.LoadBalancerPublicNetIPv6{IP: net.ParseIP("fe80::1")},
IPv6: hcloud.LoadBalancerPublicNetIPv6{IP: net.ParseIP("fe80::1")},
},
PrivateNet: []hcloud.LoadBalancerPrivateNet{
{
Expand Down
7 changes: 7 additions & 0 deletions internal/annotation/load_balancer.go
Expand Up @@ -20,6 +20,13 @@ const (
// the backend. Read-only.
LBPublicIPv6 Name = "load-balancer.hetzner.cloud/ipv6"

// LBIPv6Disabled disables the use of IPv6 for the Load Balancer.
//
// Set this annotation if you use external-dns.
//
// Default: false
LBIPv6Disabled Name = "load-balancer.hetzner.cloud/ipv6-disabled"

// LBName is the name of the Load Balancer. The name will be visible in
// the Hetzner Cloud API console.
LBName Name = "load-balancer.hetzner.cloud/name"
Expand Down

0 comments on commit b54847b

Please sign in to comment.