Scope schema discovery to target host's cluster in multi-cluster CHI#1965
Conversation
HostCreateTables used api.ClickHouseInstallation{} as the scope for
Names(NameFQDNs, ...) when building the endpoint list passed to
QueryUnzip2Columns/QueryAny. In a CHI that defines multiple clusters,
this walked hosts from every cluster and allowed QueryAny to pick a
source node outside the target cluster. The SQL filters by cluster name
via clusterAllReplicas, but sqlCreateTableReplicated joins against the
executing node's local system.databases, so the returned set of CREATE
statements depends on which cluster's node answered first — leading to
missing or wrong schemas on newly added replicas.
Use api.Cluster{} scope in getReplicatedObjectsSQLs and
getDistributedObjectsSQLs so schema-discovery endpoints are restricted
to the target host's own cluster, matching the scoping already used by
shouldCreateReplicatedObjects / shouldCreateDistributedObjects.
Fixes Altinity#1964
Signed-off-by: Lukas Pfannschmidt <lukas.pfannschmidt@traderepublic.com>
sunsingerus
left a comment
There was a problem hiding this comment.
LGTM after a 3-angle review (correctness / security / code quality).
What this fixes: schema discovery in multi-cluster CHIs was using CHI-wide endpoint scope (api.ClickHouseInstallation{}) but the surrounding gating (shouldCreateReplicatedObjects / shouldCreateDistributedObjects at replicated.go:28-29 and distributed.go:28) already used cluster scope. With LOCAL JOIN system.databases semantics introduced in d49187d and trailing-dot FQDNs in 6d625de, an off-cluster host could respond to QueryAny and surface a different cluster's database catalog — leaking schemas across cluster boundaries inside the same CHI.
Why it's safe to merge as-is:
- Six mechanical replacements in two files. Type-switch in
createFQDNs(pkg/model/chi/namer/name.go:279) already handles theapi.Clusterscope path. - Single-cluster CHIs unaffected — cluster-scoped FQDNs equal CHI-scoped FQDNs in that case.
- Aligns discovery scope with the gating that was already cluster-scoped — closes an inconsistency, doesn't introduce one.
Optional follow-up (non-blocking): unit test asserting the scope argument passed to s.Names(interfaces.NameFQDNs, ...) is api.Cluster{} for both getReplicatedObjectsSQLs and getDistributedObjectsSQLs. The schemer package currently has no tests, so this would establish the pattern.
Summary
Fixes #1964.
HostCreateTablesusedapi.ClickHouseInstallation{}as the scope forNames(NameFQDNs, ...)when building the endpoint list passed toQueryUnzip2Columns/QueryAny. In a CHI that defines multipleclusters, this walked hosts from every cluster and allowedQueryAnyto pick a source node outside the target cluster.The SQL does filter by cluster name via
clusterAllReplicas('<target>', system.tables), butsqlCreateTableReplicatedjoins against the executing node's localsystem.databases:So the returned set of CREATE statements depends on which cluster's node answered first — resulting in missing or incorrect schemas on newly added replicas in multi-cluster CHIs.
Timeline (for context)
CreatePodFQDNsOfCHI(host.GetCHI())pre-2021 and was preserved through the 2021 unification (6b946799d) and the 2024 schemer refactor (b64a6241d).LOCAL JOIN system.databasesform landed ind49187d0b(first inrelease-0.23.6), which made the executing-node dependency stricter.6d625de69added a trailing dot topatternNamespaceDomain(%s.svc.cluster.local.). That fixed slow/failing DNS resolution underndots:5, but it also removed an accidental failure-mode that had been masking the scoping bug: before 0.26, cross-cluster endpoints in the CHI-wide list could fail DNS quickly andQueryAnywould fall through to a same-cluster endpoint. After 0.26, every CHI endpoint resolves reliably, soQueryAnyreturns from whichever is first in the slice — which, with CHI-wide scoping, can be a node from a different cluster.The 0.26 DNS change didn't cause this bug — it exposed it. The root cause is the schema-discovery endpoint scope.
Change
Use
api.Cluster{}scope ingetReplicatedObjectsSQLsandgetDistributedObjectsSQLs, so schema-discovery endpoints are restricted to the target host's own cluster. This matches the scoping already used byshouldCreateReplicatedObjects/shouldCreateDistributedObjectsfor the related gating logic.Six call sites updated:
pkg/model/chi/schemer/replicated.go(databases, tables, functions)pkg/model/chi/schemer/distributed.go(databases, tables, functions)Test plan
go build ./...Single-cluster CHIs are unaffected: cluster-scoped FQDNs equal CHI-scoped FQDNs in that case.