Skip to content

v6: DNS-based cluster discovery — derive cluster from the location's CNAME #53

Description

@Pandys

Summary

Make cluster= optional on the Clappform constructor. When omitted, discover the cluster extension from the DNS CNAME of the location's subdomain, so Clappform(location="noord-brabant", api_key=...) just works.

Design: §3.1.1 Cluster discovery from DNS

How it works

Every client environment is a CNAME to its cluster's BigIP, and the BigIP name carries the same extension as that cluster's service hosts:

gelderland.clappform.com     CNAME  bigip.clappform.com           → cluster ""
noord-brabant.clappform.com  CNAME  bigip-prod-lts.clappform.com  → cluster "prod-lts"

So a plain forward lookup already contains the cluster identifier — no reverse/PTR search, no registry, no extra dependency:

>>> socket.gethostbyname_ex("noord-brabant.clappform.com")
('bigip-prod-lts.clappform.com', ['noord-brabant.clappform.com'], ['20.101.178.47'])

Resolution order:

  1. Explicit cluster= — used as-is, no DNS performed (CI / air-gapped / split-DNS stays deterministic).
  2. Discovery — resolve {location}.clappform.com via socket.gethostbyname_ex (stdlib, follows the CNAME chain) and match the canonical name against ^bigip(?:-(?P<ext>.+))?\.clappform\.com$; the ext group (empty for main) is the cluster extension.
  3. Fail loudly — lookup failure or non-matching canonical name raises ConfigurationError with a "pass cluster= explicitly" hint. Never guess.

Discovery runs once at construction, is cached on the instance, and the discovered value is included in error reports next to cluster/location so a wrong discovery is immediately visible. It only picks endpoints — the location metadata header is still sent per call for tenancy, unchanged.

Acceptance criteria

  • cluster parameter is str | None = None; explicit value skips DNS entirely
  • Discovery parses the canonical name per the regex above; empty extension maps to the main cluster hosts
  • DNS failure / unexpected canonical name raises ConfigurationError naming the location and suggesting explicit cluster=
  • Result cached per instance; with_location() clones re-discover only if their location differs
  • Discovered cluster appears in error report context (§5.2)
  • Unit tests stub the resolver (no live DNS in CI): main cluster, suffixed cluster, NXDOMAIN, non-bigip canonical name (musl-style echo of the input)
  • Docs: quickstart leads with location-only construction; explicit cluster= documented as the override

Notes / constraints

  • The CNAME convention ({location}.clappform.com → bigip{-ext}.clappform.com, ext matching service hosts) becomes an API contract — needs a line in the infra runbook; converting an environment to a direct A record breaks discovery for it.
  • musl-based systems (Alpine containers) may not return canonical names from getaddrinfo; there discovery falls into the step-3 error path rather than misbehaving.
  • Related: v6: confirm cluster endpoint details (gRPC port + extension list) #43 (cluster endpoint details — port + extension list).
  • Implement after the v6 base (transport + constructor) is in place.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestpriority: mediumNeeded for release, not blocking corev6v6 rewrite (Major/6)

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions