console: RouteView carries Unit/Backing/Provisioned
RouteView now mirrors registry.Route's process-ownership fields (Unit, Backing, Provisioned), copied through in Assemble's RouteView literal. Later tasks (2, 3, 6, 9) need these to tell "no readings because nothing samples this route's process" apart from "not responding".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 files changed,
+48
−0
internal/console/view.go+12 −0internal/console/view_test.go+36 −0
diff --git a/internal/console/view.go b/internal/console/view.go| index 6b57bddcb..8a208a6a8 100644 |
| --- a/internal/console/view.go |
| +++ b/internal/console/view.go |
| @@ -137,6 +137,17 @@ type RouteView struct { |
| // can hold another tenant's rows, and a grant is the one field here that |
| // names privileged ports and box authority. |
| Caps string |
| + // Unit is the bespoke systemd unit bound to this route |
| + // (registry.Route.Unit, #110): set when an operator-run service owns the |
| + // route's process. The sweep samples stamped units (Task 5), so a stamped |
| + // route's silence is meaningful — see expectsReadings. |
| + Unit string |
| + // Backing mirrors registry.Route.Backing: "" = an exec child the |
| + // activator spawns, registry.BackingUnit = a carlos-app@<host> unit. |
| + Backing string |
| + // Provisioned mirrors registry.Route.Provisioned: minted from a bucket |
| + // instance record, so the activator runs its process by construction. |
| + Provisioned bool |
| } |
| // humanizeCaps renders a registry.Route.Caps column for a person: the |
| @@ -380,6 +391,7 @@ func Assemble(regPath string, s release.Store, pub ed25519.PublicKey, acct strin |
| Account: rtAcct, |
| Environment: rt.Environment, |
| Caps: capsFor, |
| + Unit: rt.Unit, Backing: rt.Backing, Provisioned: rt.Provisioned, |
| }) |
| domainsByApp[rt.App] = append(domainsByApp[rt.App], domainView(rt, edgeIPs)) |
| } |
diff --git a/internal/console/view_test.go b/internal/console/view_test.go| index 2d4f94e25..46d87091b 100644 |
| --- a/internal/console/view_test.go |
| +++ b/internal/console/view_test.go |
| @@ -268,6 +268,42 @@ func TestAssembleDegradesBadChannel(t *testing.T) { |
| } |
| } |
| +// TestAssembleCarriesProcessOwnership guards the copy in Assemble's |
| +// RouteView literal: Unit/Backing/Provisioned are what later tasks (2, 3, 6, |
| +// 9) use to tell "no readings because nothing samples this route's process" |
| +// apart from "not responding" — a silent drop here would make every |
| +// unit-backed route look unowned. |
| +func TestAssembleCarriesProcessOwnership(t *testing.T) { |
| + regPath, store, _, pub := buildFixtures(t) |
| + reg, err := registry.Open(regPath) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := reg.Upsert(registry.Route{Host: "unit-stamped.example.test", Kind: "instance", |
| + Status: "ready", App: "kass", Channel: "stable", |
| + Unit: "titogo@demo.service", Backing: registry.BackingUnit, Provisioned: true}); err != nil { |
| + t.Fatal(err) |
| + } |
| + views, err := Assemble(regPath, store, pub, release.OpsAccount, []string{"kass"}, nil) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + var rt RouteView |
| + found := false |
| + for _, r := range views[0].Routes { |
| + if r.Host == "unit-stamped.example.test" { |
| + rt = r |
| + found = true |
| + } |
| + } |
| + if !found { |
| + t.Fatalf("route unit-stamped.example.test not in %+v", views[0].Routes) |
| + } |
| + if rt.Unit != "titogo@demo.service" || rt.Backing != registry.BackingUnit || !rt.Provisioned { |
| + t.Fatalf("RouteView lost process ownership: %+v", rt) |
| + } |
| +} |
| + |
| func TestVersionsNewestFirst(t *testing.T) { |
| _, store, _, _ := buildFixtures(t) |
| vs, err := Versions(store, release.OpsAccount, "kass") |