Skip to content

control-connection: restore local Host.listen_address during topology refresh #1008

Description

@dkropachev

Problem

Since a0cde2e019, control-connection topology refresh no longer assigns system.local.listen_address to the local Host.

The attribute remains part of the public Host contract:

listen_address = None
"""
listen address configured for the node, *if available*:
'system.local.listen_address'
This is only available in the ``system.local`` table for newer versions of Cassandra. It is also not
queried if :attr:`~.Cluster.token_metadata_enabled` is ``False``. Usually the same as ``broadcast_address``
unless configured differently in cassandra.yaml.
"""
listen_port = None
"""
listen port configured for the node, *if available*:
'system.local.listen_port'
This is only available in the ``system.local`` table for newer versions of Cassandra. It is also not
queried if :attr:`~.Cluster.token_metadata_enabled` is ``False``.

Current refresh copies broadcast fields but omits local listen metadata:

host.host_id = host_id
host.broadcast_address = _NodeInfo.get_broadcast_address(row)
host.broadcast_port = _NodeInfo.get_broadcast_port(row)
host.broadcast_rpc_address = _NodeInfo.get_broadcast_rpc_address(row)
host.broadcast_rpc_port = _NodeInfo.get_broadcast_rpc_port(row)
host.release_version = row.get("release_version")
host.dse_version = row.get("dse_version")
host.dse_workload = row.get("workload")
host.dse_workloads = row.get("workloads")
if row is local_row:
connection._control_connection_host_id = host_id
tokens = row.get("tokens", None)
if partitioner and tokens and self._token_meta_enabled:
token_map[host] = tokens
self._cluster.metadata.update_host(host, old_endpoint=endpoint)

Code before the regression populated it:

host = self._cluster.metadata.get_host(connection.original_endpoint)
if host:
datacenter = local_row.get("data_center")
rack = local_row.get("rack")
self._update_location_info(host, datacenter, rack)
# support the use case of connecting only with public address
if isinstance(self._cluster.endpoint_factory, SniEndPointFactory):
new_endpoint = self._cluster.endpoint_factory.create(local_row)
if new_endpoint.address:
host.endpoint = new_endpoint
host.host_id = local_row.get("host_id")
found_host_ids.add(host.host_id)
found_endpoints.add(host.endpoint)
host.listen_address = local_row.get("listen_address")
host.listen_port = local_row.get("listen_port")
host.broadcast_address = _NodeInfo.get_broadcast_address(local_row)
host.broadcast_port = _NodeInfo.get_broadcast_port(local_row)
host.broadcast_rpc_address = _NodeInfo.get_broadcast_rpc_address(local_row)
host.broadcast_rpc_port = _NodeInfo.get_broadcast_rpc_port(local_row)

Regression commit:

a0cde2e

Impact

When CQL RPC address changes but REST/listen address stays unchanged, Host.listen_address remains None. Consumers fall back to the relocated RPC endpoint and contact the wrong REST address.

Tested with ScyllaDB 2026.2.6 (c06236b53803b96e7d2d21b4fad144a9eef2c3ba) and python-driver PR #944 (83bdd4605468f73bfcee80588aa8f1be5f87d9ef). Driver 3.29.7 passes; PR #944 fails.

Related test from testpy

https://github.com/scylladb/scylladb/blob/c06236b53803b96e7d2d21b4fad144a9eef2c3ba/test/cluster/test_change_rpc_address.py#L40-L89

The test changes only the CQL RPC address, then obtains the REST address from Host.listen_address:

https://github.com/scylladb/scylladb/blob/c06236b53803b96e7d2d21b4fad144a9eef2c3ba/test/pylib/rest_client.py#L775-L781

Actual: Host.listen_address is None; REST request targets the relocated RPC IP and fails with ConnectionRefusedError.

Expected: local Host.listen_address matches system.local.listen_address after topology refresh.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

release-blockerMust be resolved before the next release.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions