carlos / platform Public

#162: the domains pass derives a replica's alias from replica_of

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 4fb82f27b1bfcdc2d7e0dee5c29df2639f34d256 parent cf91993
2 files changed, +156 −1
  • internal/domains/aliases.go +45 −1
  • internal/domains/aliases_test.go +111 −0
diff --git a/internal/domains/aliases.go b/internal/domains/aliases.go
index c1b238590..489de53ae 100644
--- a/internal/domains/aliases.go
+++ b/internal/domains/aliases.go
@@ -75,8 +75,12 @@ func ReconcileAliases(ctx context.Context, s release.Store, reg *registry.Regist
return err
}
byHost := make(map[string]registry.Route, len(routes))
+ byReplicaOf := make(map[string]registry.Route, len(routes))
for _, rt := range routes {
byHost[rt.Host] = rt
+ if rt.ReplicaOf != "" {
+ byReplicaOf[rt.ReplicaOf] = rt
+ }
}
existing, err := reg.ListAliases()
if err != nil {
@@ -86,6 +90,32 @@ func ReconcileAliases(ctx context.Context, s release.Store, reg *registry.Regist
desiredWild := map[string]registry.WildcardDomain{}
desiredPaths := map[string]registry.RoutePath{} // key: host + "\x00" + prefix
wildCount := 0
+
+ // Replica placements (#162): a route carrying ReplicaOf is an account's
+ // replica on this box, and the account's public host must resolve to it
+ // HERE while every other box goes on backhauling that host home.
+ // Derived from the route row because this pass cannot read records —
+ // internal/provision imports this package, so the reverse is a cycle.
+ for _, rt := range routes {
+ if rt.ReplicaOf == "" {
+ continue
+ }
+ if _, taken := byHost[rt.ReplicaOf]; taken {
+ // A real local route owns that name: the home landed on this
+ // box. Routes beat aliases in the edge's fold anyway
+ // (edge.go:747-749), so this row would never win.
+ log.Printf("domains: replica alias %s skipped: a real route owns that host", rt.ReplicaOf)
+ continue
+ }
+ desired[rt.ReplicaOf] = true
+ if err := reg.UpsertAlias(registry.RouteAlias{
+ Alias: rt.ReplicaOf, Host: rt.Host, Account: release.RouteAccount(rt), App: rt.App,
+ CreatedAt: now().Unix(),
+ }); err != nil {
+ log.Printf("domains: upsert replica alias %s: %v", rt.ReplicaOf, err)
+ }
+ }
+
for _, c := range claims {
// Plain alias derivation (#164): a routeless (first-route) claim is
// not an alias — that skip is scoped to THIS half only, so a
@@ -93,6 +123,20 @@ func ReconcileAliases(ctx context.Context, s release.Store, reg *registry.Regist
// derivation below.
if c.Route != "" {
rt, ok := byHost[c.Route]
+ // aliasTarget is ordinarily the claim's own primary host. A
+ // custom-domain claim whose Route names a REPLICA's home
+ // (#162, spec §3, §5a) has no local route under that name at
+ // all — the replica's route is the local one, and it carries
+ // the home's host as ReplicaOf, not as its own Host. Same
+ // desired set, same sweep, same tenancy checks below, run
+ // against the replica's own route instead.
+ aliasTarget := c.Route
+ if !ok {
+ if rrt, ok2 := byReplicaOf[c.Route]; ok2 {
+ rt, ok = rrt, true
+ aliasTarget = rrt.Host
+ }
+ }
if strings.HasSuffix(c.Route, sidecarSuffix) || strings.HasSuffix(c.Host, sidecarSuffix) {
// Refused on EITHER end: a reserved-suffix primary must
// never be given a routable name, and an alias whose OWN
@@ -131,7 +175,7 @@ func ReconcileAliases(ctx context.Context, s release.Store, reg *registry.Regist
} else {
desired[c.Host] = true
if err := reg.UpsertAlias(registry.RouteAlias{
- Alias: c.Host, Host: c.Route, Account: c.Account, App: c.App,
+ Alias: c.Host, Host: aliasTarget, Account: c.Account, App: c.App,
CreatedAt: now().Unix(),
}); err != nil {
log.Printf("domains: upsert alias %s: %v", c.Host, err)
diff --git a/internal/domains/aliases_test.go b/internal/domains/aliases_test.go
index 9a19a5bf3..34a4f66e8 100644
--- a/internal/domains/aliases_test.go
+++ b/internal/domains/aliases_test.go
@@ -701,3 +701,114 @@ func TestReconcileAliasesStillDerivesTheCatchAllForAFirstRouteClaim(t *testing.T
"instead of \"*.\"+host, refusing every first-route wildcard claim", aliases)
}
}
+
+// TestReconcileAliasesDerivesReplicaAlias covers the account-host half of
+// #162 (spec §3): a local route carrying ReplicaOf derives an alias from
+// the home's host to the replica's own host, with no claim involved at all.
+func TestReconcileAliasesDerivesReplicaAlias(t *testing.T) {
+ s := release.NewDirStore(t.TempDir())
+ reg := aliasRegWith(t, registry.Route{
+ Host: "r7x2k9m4qa.go.tito.io", App: "tito", Account: "bab", Kind: "instance",
+ Status: "ready", ReplicaOf: "acme.go.tito.io",
+ })
+ for i := 0; i < 2; i++ { // twice: the second pass is the sweep's chance to eat it
+ if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil {
+ t.Fatal(err)
+ }
+ }
+ aliases, err := reg.ListAliases()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(aliases) != 1 {
+ t.Fatalf("got %d aliases, want 1: %+v", len(aliases), aliases)
+ }
+ if a := aliases[0]; a.Alias != "acme.go.tito.io" || a.Host != "r7x2k9m4qa.go.tito.io" ||
+ a.Account != "bab" || a.App != "tito" {
+ t.Fatalf("replica alias row mismatch: %+v", a)
+ }
+}
+
+// TestReconcileAliasesSweepsAReplicaAliasWhoseRouteIsGone covers the removal
+// half: when the replica's route disappears (its record went, the instance
+// pass retired the route), the alias derived from it must not outlive it —
+// no new retirement code, the ordinary sweep at the bottom of the pass.
+func TestReconcileAliasesSweepsAReplicaAliasWhoseRouteIsGone(t *testing.T) {
+ s := release.NewDirStore(t.TempDir())
+ reg := aliasRegWith(t, registry.Route{
+ Host: "r7x2k9m4qa.go.tito.io", App: "tito", Account: "bab", Kind: "instance",
+ Status: "ready", ReplicaOf: "acme.go.tito.io",
+ })
+ if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil {
+ t.Fatal(err)
+ }
+ if err := reg.Delete("r7x2k9m4qa.go.tito.io"); err != nil {
+ t.Fatal(err)
+ }
+ if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil {
+ t.Fatal(err)
+ }
+ if aliases, err := reg.ListAliases(); err != nil {
+ t.Fatal(err)
+ } else if len(aliases) != 0 {
+ t.Fatalf("the replica alias outlived its route: %+v", aliases)
+ }
+}
+
+// TestReconcileAliasesReplicaAliasLosesToARealRoute covers the collision
+// rule: if the home ever lands on the same box as its replica, the real
+// local route for the account host must win — no alias derived over it.
+func TestReconcileAliasesReplicaAliasLosesToARealRoute(t *testing.T) {
+ s := release.NewDirStore(t.TempDir())
+ reg := aliasRegWith(t,
+ registry.Route{Host: "acme.go.tito.io", App: "tito", Account: "bab", Kind: "instance", Status: "ready"},
+ registry.Route{Host: "r7x2k9m4qa.go.tito.io", App: "tito", Account: "bab", Kind: "instance",
+ Status: "ready", ReplicaOf: "acme.go.tito.io"},
+ )
+ if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil {
+ t.Fatal(err)
+ }
+ if aliases, err := reg.ListAliases(); err != nil {
+ t.Fatal(err)
+ } else if len(aliases) != 0 {
+ t.Fatalf("an alias was derived over a real local route: %+v", aliases)
+ }
+}
+
+// TestReconcileAliasesDerivesReplicaCustomDomainAlias covers the half that
+// carries titogo's real checkout traffic (spec §5a, revision 3): a claim
+// whose Route names the HOME host, with no local route of its own, derives
+// an alias to the REPLICA's host — the claim's own primary lookup misses
+// locally, but a local route's ReplicaOf names the same home. Survives a
+// second pass, same as the account-host alias above.
+func TestReconcileAliasesDerivesReplicaCustomDomainAlias(t *testing.T) {
+ s := release.NewDirStore(t.TempDir())
+ reg := aliasRegWith(t, registry.Route{
+ Host: "r7x2k9m4qa.go.tito.io", App: "tito", Account: "bab", Kind: "instance",
+ Status: "ready", ReplicaOf: "acme.go.tito.io",
+ })
+ putClaim(t, s, Claim{
+ Host: "tickets.example.com", Account: "bab", App: "tito", Route: "acme.go.tito.io",
+ })
+ for i := 0; i < 2; i++ {
+ if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil {
+ t.Fatal(err)
+ }
+ }
+ aliases, err := reg.ListAliases()
+ if err != nil {
+ t.Fatal(err)
+ }
+ var found *registry.RouteAlias
+ for i := range aliases {
+ if aliases[i].Alias == "tickets.example.com" {
+ found = &aliases[i]
+ }
+ }
+ if found == nil {
+ t.Fatalf("custom-domain replica alias missing: %+v", aliases)
+ }
+ if found.Host != "r7x2k9m4qa.go.tito.io" || found.Account != "bab" || found.App != "tito" {
+ t.Fatalf("custom-domain replica alias row mismatch: %+v", *found)
+ }
+}