From: Redouane Kachach Date: Wed, 25 Feb 2026 14:09:11 +0000 (+0100) Subject: cephadm: fix EndPoint to handle bracketed IPv6 addresses X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=3f6a702d2851466d1de818ea239eea671a491545;p=ceph.git cephadm: fix EndPoint to handle bracketed IPv6 addresses EndPoint ctr fails to correctly handle IPv6 addresses passed with surrounding brackets. In this case, ipaddress.ip_network() raises a ValueError, which is silently swallowed by the except block, leaving is_ipv4 = True. This causes __str__/__repr__ method to return a malformed address like fd19:8:5::11:3300 instead of [fd19:8:5::11]:3300. Normalize the self.ip field by stripping brackets on construction so we always save and use the bare ip. repr/str methods take care of appending the [] when needed. Fixes: https://tracker.ceph.com/issues/75165 (original ticket) Fixes: https://tracker.ceph.com/issues/75567 (backport ticket) Signed-off-by: Redouane Kachach (cherry picked from commit 25319e985ade01f566f00cf0fd6a550c6f1c9764) --- diff --git a/src/cephadm/cephadmlib/net_utils.py b/src/cephadm/cephadmlib/net_utils.py index bfa61d933ef..7fe48c0b36a 100644 --- a/src/cephadm/cephadmlib/net_utils.py +++ b/src/cephadm/cephadmlib/net_utils.py @@ -22,11 +22,11 @@ class EndPoint: """EndPoint representing an ip:port format""" def __init__(self, ip: str, port: int) -> None: - self.ip = ip + self.ip = ip.strip('[]') # normalize: always store bare IP self.port = port self.is_ipv4 = True try: - if ip and ipaddress.ip_network(ip).version == 6: + if self.ip and ipaddress.ip_network(self.ip).version == 6: self.is_ipv4 = False except Exception: logger.exception('Failed to check ip address version') diff --git a/src/cephadm/tests/test_networks.py b/src/cephadm/tests/test_networks.py index 83b908c1457..f97dcb6a2d5 100644 --- a/src/cephadm/tests/test_networks.py +++ b/src/cephadm/tests/test_networks.py @@ -8,10 +8,45 @@ from tests.fixtures import with_cephadm_ctx, cephadm_fs, import_cephadm from cephadmlib.host_facts import _parse_ipv4_route, _parse_ipv6_route from cephadmlib.net_utils import get_ipv6_address +from cephadmlib.net_utils import EndPoint _cephadm = import_cephadm() +class TestEndPoint: + @pytest.mark.parametrize("ip, port, expected_str, expected_is_ipv4", [ + # Normal IPv4 + ('192.168.1.1', 3300, '192.168.1.1:3300', True), + # Normal IPv6 (bare) + ('fd19:8:5::11', 3300, '[fd19:8:5::11]:3300', False), + # Bracketed IPv6 + ('[fd19:8:5::11]', 3300, '[fd19:8:5::11]:3300', False), + # Bracketed IPv6 should normalize stored ip to bare + ('[::1]', 6789, '[::1]:6789', False), + ]) + def test_endpoint_init(self, ip, port, expected_str, expected_is_ipv4): + ep = EndPoint(ip, port) + assert str(ep) == expected_str + assert ep.is_ipv4 == expected_is_ipv4 + # stored ip should always be bare (no brackets) + assert '[' not in ep.ip + assert ']' not in ep.ip + + def test_endpoint_ipv4(self): + ep = EndPoint('10.0.0.1', 6789) + assert ep.is_ipv4 is True + assert repr(ep) == '10.0.0.1:6789' + + def test_endpoint_ipv6(self): + ep = EndPoint('[fd19:8:5::11]', 6789) + assert ep.is_ipv4 is False + assert repr(ep) == '[fd19:8:5::11]:6789' + + def test_endpoint_bracketed_ipv6_normalizes_stored_ip(self): + ep = EndPoint('[fd19:8:5::11]', 3300) + assert ep.ip == 'fd19:8:5::11' # bare ipv6, no brackets + + class TestCommandListNetworks: @pytest.mark.parametrize("test_input, expected", [ (