| index 4dd9ef44a..6e8d98bfa 100644 |
| --- a/internal/status/snapshot.go |
| +++ b/internal/status/snapshot.go |
| @@ -57,11 +57,19 @@ type Probes struct { |
| // or "" for hardware no cloud owns. It is the console architecture |
| // page's join key โ see BoxMetrics.InstanceID. |
| InstanceID string |
| - Region string // operator-set, coarse; "" omits the field |
| - MemFrac *float64 // 0..1 memory utilization |
| - DiskFrac *float64 // 0..1 proximity to the disk floor |
| - Listening func(sock string) *bool // kernel socket table read; nil fn = unknown |
| - LagSecs *int64 // seconds since litestream last progressed |
| + // BoxID is the box id this box's edges file publishes (the edges |
| + // writer's value), Lanes the staging buckets CARLOS_MOVE_LANES names, and |
| + // Hosts the per-host facts a self-serve move's door reads (self-serve |
| + // moves plan 2 Task 6). All three land in BoxMetrics only, never in the |
| + // public feed. "" and nil are unknown and publish nothing. |
| + BoxID string |
| + Lanes []string |
| + Hosts map[string]HostFacts |
| + Region string // operator-set, coarse; "" omits the field |
| + MemFrac *float64 // 0..1 memory utilization |
| + DiskFrac *float64 // 0..1 proximity to the disk floor |
| + Listening func(sock string) *bool // kernel socket table read; nil fn = unknown |
| + LagSecs *int64 // seconds since litestream last progressed |
| // AdoptRunning is whether release adoption is actually armed on this box |
| // โ the carlos-adopt.timer being ACTIVE, not merely enabled. nil is |
| // "never asked / couldn't tell", and like every other nil here it must |
| @@ -512,7 +520,21 @@ type BoxMetrics struct { |
| // asking the metadata service which machine it is cannot drift from a |
| // naming convention, because it is not using one. |
| InstanceID string `json:"instance_id,omitempty"` |
| - Tunnel string `json:"tunnel,omitempty"` // ""|"connected"|"reconnecting" |
| + // BoxID is the box id this box's edges file publishes. A self-serve |
| + // move pins its participants by it and by InstanceID, and every gate |
| + // checks a pinned participant is still the box that reports under its |
| + // label (moves.ParticipantStillPresent). Private like InstanceID. |
| + BoxID string `json:"box_id,omitempty"` |
| + // Lanes are the staging buckets this box has a lane to |
| + // (CARLOS_MOVE_LANES): the self-serve door refuses a move whose target |
| + // bucket the source box does not name. Omitted when none is set. |
| + Lanes []string `json:"lanes,omitempty"` |
| + // Hosts is, per instance this box hosts, what a self-serve move's door |
| + // reads before it offers a move: the row's lifetime, the replica's size |
| + // and the files' size as the archive would count them (HostFacts). |
| + // Hostname-keyed, so private like RouteVersions. Omitted when empty. |
| + Hosts map[string]HostFacts `json:"hosts,omitempty"` |
| + Tunnel string `json:"tunnel,omitempty"` // ""|"connected"|"reconnecting" |
| // GeoIP is present on every box running a GeoIP-aware binary (geoip |
| // spec ยง5.5); its absence is how the rollout verdict tells an older |
| // binary, which does not strip forged geo headers. |
| @@ -1045,7 +1067,8 @@ func CollectBox(routes []registry.Route, p Probes, now time.Time) Box { |
| len(routeVersions) > 0 || len(routeServing) > 0 || len(aliasReadings) > 0 || len(p.Upstreams) > 0 || |
| len(routeDBBytes) > 0 || p.Layout != nil || len(p.ConfigRefusals) > 0 || len(p.ReleaseRefusals) > 0 || len(p.ProofWaits) > 0 || p.Rollout != nil || p.ConfigGuard != "" || |
| p.Alerts != nil || p.GeoIP != nil || len(p.BuildStates) > 0 || p.BuildStatesErr != "" || |
| - p.UpdateSettings != 0 || len(p.Updates) > 0 { |
| + p.UpdateSettings != 0 || len(p.Updates) > 0 || |
| + p.BoxID != "" || len(p.Lanes) > 0 || len(p.Hosts) > 0 { |
| box.Metrics = &BoxMetrics{ |
| ConsoleProcesses: p.ConsoleProcesses, |
| ActivationID: p.ActivationID, ActivationComplete: p.ActivationComplete, |
| @@ -1063,7 +1086,11 @@ func CollectBox(routes []registry.Route, p Probes, now time.Time) Box { |
| Load1: p.Load1, DiskFreeBytes: p.DiskFreeBytes, |
| Release: p.Release, Tunnel: p.Tunnel, GeoIP: p.GeoIP, |
| Platform: p.Platform, SystemChannel: p.SystemChannel, System: p.System, |
| - InstanceID: p.InstanceID, |
| + InstanceID: p.InstanceID, |
| + BoxID: p.BoxID, |
| + Lanes: append([]string(nil), p.Lanes...), |
| + // The caller builds a fresh map every tick. |
| + Hosts: p.Hosts, |
| Alerts: p.Alerts, |
| RouteVersions: routeVersions, |
| RouteServing: routeServing, |
| @@ -1155,3 +1182,30 @@ type GeoIPState struct { |
| Type string `json:"type,omitempty"` |
| Error string `json:"error,omitempty"` |
| } |
| + |
| +// HostFacts is one instance's facts on the box that hosts it, collected by |
| +// the agent's status tick for the self-serve move's door (self-serve moves |
| +// plan 2 Task 6). Times are Unix seconds. CollectedAt is when the facts were |
| +// collected, ReplicaCollectedAt when the replica listing they count was |
| +// taken (the listing is taken once per tick for every host). Incarnation is |
| +// the row's lifetime. FilesBytes and FilesEntries count the files the |
| +// offline move's archive would carry, by the archive's own rules, without |
| +// stopping at its cap: OverCap says the count passed the cap, Truncated |
| +// that the walk stopped at its time budget or at twice the cap before it |
| +// finished. Strays are the entries the instance keeps beside its files |
| +// directory. Known is true only when every part was collected; Err says |
| +// what was not. |
| +type HostFacts struct { |
| + CollectedAt int64 `json:"collected_at"` |
| + Known bool `json:"known"` |
| + Err string `json:"err,omitempty"` |
| + Incarnation uint64 `json:"incarnation"` |
| + ReplicaBytes int64 `json:"replica_bytes"` |
| + ReplicaObjects int `json:"replica_objects"` |
| + ReplicaCollectedAt int64 `json:"replica_collected_at"` |
| + FilesBytes int64 `json:"files_bytes"` |
| + FilesEntries int `json:"files_entries"` |
| + OverCap bool `json:"over_cap,omitempty"` |
| + Truncated bool `json:"truncated,omitempty"` |
| + Strays []string `json:"strays,omitempty"` |
| +} |