Skip to content

fix(instances): skip IPv6 ExternalIP for Robot servers without a subnet - #1337

Merged
lukasmetzner merged 2 commits into
hetznercloud:mainfrom
Jakob3xD:fix/robot-empty-ipv6-net
Aug 28, 2026
Merged

fix(instances): skip IPv6 ExternalIP for Robot servers without a subnet#1337
lukasmetzner merged 2 commits into
hetznercloud:mainfrom
Jakob3xD:fix/robot-empty-ipv6-net

Conversation

@Jakob3xD

Copy link
Copy Markdown
Contributor

Problem

robotNodeAddresses builds the IPv6 ExternalIP of a Robot server by appending 1 to server.ServerIPv6Net (hcloud/instances.go):

if ipv6 {
    // For a given IPv6 network of 2a01:f48:111:4221::, the instance address is 2a01:f48:111:4221::1
    hostAddress := server.ServerIPv6Net + "1"
    addresses = append(addresses, corev1.NodeAddress{Type: corev1.NodeExternalIP, Address: hostAddress})
}

Robot servers do not necessarily have an IPv6 subnet assigned. In that case the Robot API reports an empty server_ipv6_net, the concatenation yields the literal string 1, and that ends up on the Node object:

status:
  addresses:
    - address: "1"
      type: ExternalIP

The same applies to any value that does not yield a valid address after the concatenation — a subnet reported with a prefix length, for example, produces 2001:db8:1234::/641.

This affects HCLOUD_INSTANCES_ADDRESS_FAMILY=ipv6 and dualstack. The default ipv4 never enters this branch.

The equivalent Cloud code path is already guarded (ipv4 && !server.PublicNet.IPv4.IsUnspecified() / ipv6 && !server.PublicNet.IPv6.IsUnspecified()), because it works with real net.IP values instead of string concatenation. The Robot path has no such check.

Impact

The invalid entry is written to status.addresses on every reconciliation and breaks consumers that parse node ExternalIPs. Found on a hybrid cluster whose Robot servers have no IPv6 subnet recorded in Robot.

Fix

  • Skip the IPv6 ExternalIP when ServerIPv6Net is empty.
  • Validate the concatenated address with net.ParseIP before adding it, and emit an InvalidIPv6Net warning event when the reported subnet does not yield a valid address.

Tests

Three cases added to TestNodeAddressesRobotServer, covering ipv6-only and dual-stack without a subnet, and a malformed subnet. Without the fix they fail as:

--- FAIL: TestNodeAddressesRobotServer/public_ipv6_without_IPv6_subnet
    expected addresses [{Type:Hostname Address:foobar}]
         but got       [{Type:Hostname Address:foobar} {Type:ExternalIP Address:1}]

--- FAIL: TestNodeAddressesRobotServer/public_dual_stack_without_IPv6_subnet
    expected addresses [{Type:Hostname Address:foobar} {Type:ExternalIP Address:203.0.113.7}]
         but got       [{Type:Hostname Address:foobar} {Type:ExternalIP Address:1} {Type:ExternalIP Address:203.0.113.7}]

--- FAIL: TestNodeAddressesRobotServer/public_ipv6_with_malformed_IPv6_subnet
    expected addresses [{Type:Hostname Address:foobar}]
         but got       [{Type:Hostname Address:foobar} {Type:ExternalIP Address:2001:db8:1234::/641}]

@Jakob3xD
Jakob3xD requested a review from a team as a code owner August 27, 2026 10:29
@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.60656% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.69%. Comparing base (ec8fd02) to head (9528caf).

Files with missing lines Patch % Lines
hcloud/instances.go 83.60% 9 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1337      +/-   ##
==========================================
- Coverage   70.11%   66.69%   -3.43%     
==========================================
  Files          29       29              
  Lines        2794     2816      +22     
==========================================
- Hits         1959     1878      -81     
- Misses        643      753     +110     
+ Partials      192      185       -7     
Flag Coverage Δ
e2e ?
unit 66.69% <83.60%> (+0.19%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Robot servers do not necessarily have an IPv6 subnet assigned. In that
case the Robot API reports an empty `server_ipv6_net`, and appending "1"
to it added the literal address "1" as an ExternalIP to the Node object.

Guard the concatenation with an emptiness check and validate the result
before using it, emitting a warning event when the reported subnet does
not yield a valid address.

Co-authored-by: Claude <noreply@anthropic.com>
@lukasmetzner
lukasmetzner merged commit 3ec2945 into hetznercloud:main Aug 28, 2026
4 of 9 checks passed
@Jakob3xD
Jakob3xD deleted the fix/robot-empty-ipv6-net branch August 28, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants