Skip to content

Commit af7c48c

Browse files
authored
Fix ipMode being set without an IP when using the hostname annotation (#78)
When using the `load-balancer.hetzner.cloud/hostname` annotation, the CCM was incorrectly setting `ipMode` in the LoadBalancer status without an accompanying IP address. This violates Kubernetes validation rules, which require `ipMode` to be set only when `ip` is also present. This caused continuous sync failures with the error: "status.loadBalancer.ingress[0].ipMode: Forbidden: may not be specified when `ip` is not set" The fix aligns with the upstream hcloud-cloud-controller-manager behavior by returning only the hostname without `ipMode` when the hostname annotation is used.
1 parent 95e6338 commit af7c48c

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

hcloud/load_balancers.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,7 @@ func (l *loadBalancers) getLBStatus(lb *hcloud.LoadBalancer, service *corev1.Ser
200200
// See: https://github.com/kubernetes/kubernetes/issues/66607
201201
if v, ok := annotation.LBHostname.StringFromService(service); ok {
202202
return &corev1.LoadBalancerStatus{
203-
Ingress: []corev1.LoadBalancerIngress{{
204-
Hostname: v,
205-
IPMode: &ipMode,
206-
}},
203+
Ingress: []corev1.LoadBalancerIngress{{Hostname: v}},
207204
}, nil
208205
}
209206

hcloud/load_balancers_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,35 @@ func TestLoadBalancers_GetLoadBalancer(t *testing.T) {
146146
assert.Equal(t, "hostname", status.Ingress[0].Hostname)
147147
},
148148
},
149+
{
150+
Name: "get load balancer with hostname does not set ipMode",
151+
ServiceUID: "2-hostname-no-ipmode",
152+
LB: &hcloud.LoadBalancer{
153+
ID: 11,
154+
Name: "hostname-lb",
155+
PublicNet: hcloud.LoadBalancerPublicNet{
156+
IPv4: hcloud.LoadBalancerPublicNetIPv4{IP: net.ParseIP("1.2.3.4")},
157+
IPv6: hcloud.LoadBalancerPublicNetIPv6{IP: net.ParseIP("fe80::1")},
158+
},
159+
},
160+
Mock: func(_ *testing.T, tt *LoadBalancerTestCase) {
161+
tt.LBOps.
162+
On("GetByK8SServiceUID", tt.Ctx, tt.Service).
163+
Return(tt.LB, nil)
164+
},
165+
ServiceAnnotations: map[annotation.Name]interface{}{
166+
annotation.LBHostname: "lb.example.com",
167+
},
168+
Perform: func(t *testing.T, tt *LoadBalancerTestCase) {
169+
status, exists, err := tt.LoadBalancers.GetLoadBalancer(tt.Ctx, tt.ClusterName, tt.Service)
170+
require.NoError(t, err)
171+
require.True(t, exists)
172+
require.Len(t, status.Ingress, 1)
173+
assert.Equal(t, "lb.example.com", status.Ingress[0].Hostname)
174+
assert.Empty(t, status.Ingress[0].IP, "IP should not be set when using hostname")
175+
assert.Nil(t, status.Ingress[0].IPMode, "ipMode must be nil when using hostname (no IP)")
176+
},
177+
},
149178
{
150179
Name: "load balancer not found",
151180
ServiceUID: "3",
@@ -406,6 +435,36 @@ func TestLoadBalancers_EnsureLoadBalancer_CreateLoadBalancer(t *testing.T) {
406435
assert.Equal(t, expected, lbStat)
407436
},
408437
},
438+
{
439+
Name: "hostname annotation does not set ipMode",
440+
ServiceUID: "7",
441+
ServiceAnnotations: map[annotation.Name]interface{}{
442+
annotation.LBName: "hostname-lb",
443+
annotation.LBHostname: "lb.example.com",
444+
},
445+
LB: &hcloud.LoadBalancer{
446+
ID: 7,
447+
Name: "hostname-lb",
448+
LoadBalancerType: &hcloud.LoadBalancerType{Name: "lb11"},
449+
Location: &hcloud.Location{Name: "nbg1", NetworkZone: hcloud.NetworkZoneEUCentral},
450+
PublicNet: hcloud.LoadBalancerPublicNet{
451+
Enabled: true,
452+
IPv4: hcloud.LoadBalancerPublicNetIPv4{IP: net.ParseIP("1.2.3.4")},
453+
IPv6: hcloud.LoadBalancerPublicNetIPv6{IP: net.ParseIP("fe80::1")},
454+
},
455+
},
456+
Mock: func(_ *testing.T, tt *LoadBalancerTestCase) {
457+
setupSuccessMocks(tt, "hostname-lb")
458+
},
459+
Perform: func(t *testing.T, tt *LoadBalancerTestCase) {
460+
lbStat, err := tt.LoadBalancers.EnsureLoadBalancer(tt.Ctx, tt.ClusterName, tt.Service, tt.Nodes)
461+
require.NoError(t, err)
462+
require.Len(t, lbStat.Ingress, 1)
463+
assert.Equal(t, "lb.example.com", lbStat.Ingress[0].Hostname)
464+
assert.Empty(t, lbStat.Ingress[0].IP, "IP should not be set when using hostname")
465+
assert.Nil(t, lbStat.Ingress[0].IPMode, "ipMode must be nil when using hostname (no IP)")
466+
},
467+
},
409468
{
410469
Name: "attach Load Balancer to private network only",
411470
NetworkID: 4711,

0 commit comments

Comments
 (0)