carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package hostbox
2
3import (
4 "slices"
5
6 "github.com/carlosframework/platform/internal/hostclaim"
7)
8
9// RowCase is what reconcile does with one relocatable host's registry row
10// on this box (region HA spec 1 §5.3, claim C4 as amended by L12).
11type RowCase int
12
13const (
14 // RowNone: mint nothing, and there is no row to keep.
15 RowNone RowCase = iota
16 // RowReady: mint the row, or keep it, ready.
17 RowReady
18 // RowHeld: mint the row, or keep it, held with HoldOp.
19 RowHeld
20 // RowRetiring: keep an existing row held; mint none. A park-local chore
21 // this box owes retires it under the host guard (claim P6-D2).
22 RowRetiring
23 // RowUnexplained: the claim gives this box no role, yet a row exists.
24 // Keep it held, never serve it, and alert. Never delete it by hostname.
25 RowUnexplained
26)
27
28// RowDecision is RelocationRow's answer.
29type RowDecision struct {
30 Case RowCase
31 HoldOp string
32}
33
34// RelocationRow decides one row from a fresh claim read. box is this box's
35// reference; exists says whether the registry holds a row for the host;
36// fenceClosed says whether this box's local admission fence for the host is
37// closed (the source's release has begun, §5.8's release sequence step 1).
38//
39// op.exec, serving (Serving's own rule) ready
40// relocating source in starting, or releasing
41// until its admission fence closes ready
42// any other participant of a running operation held, hold_op = op id
43// owner of an open park-local chore for the host retiring (held, no mint)
44// none of these none; an existing row is unexplained
45//
46// A box on the claim's lost list is never ready. A nil or holderless claim
47// (an error is the caller's: claim C6, keep rows and mint none) gives none.
48func RelocationRow(c *hostclaim.Claim, box string, exists, fenceClosed bool) RowDecision {
49 if c == nil || c.Holder == nil || box == "" {
50 return unexplained(exists)
51 }
52 lost := slices.Contains(c.Lost, box)
53 switch {
54 case lost:
55 case Serving(c, Selection{Box: box}) == nil:
56 return RowDecision{Case: RowReady}
57 case c.Op.Kind == hostclaim.KindRelocating && c.Op.Exec == box && c.Op.Intent["source_box"] == box &&
58 (c.Op.Phase == hostclaim.PhaseStarting || (c.Op.Phase == hostclaim.PhaseReleasing && !fenceClosed)):
59 return RowDecision{Case: RowReady}
60 case c.Op.Kind != hostclaim.KindServing && c.Op.ID != "" && slices.Contains(c.Op.Participants, box):
61 return RowDecision{Case: RowHeld, HoldOp: c.Op.ID}
62 }
63 for _, o := range c.Obligations {
64 if o.Kind == "park-local" && o.Box == box {
65 if !exists {
66 return RowDecision{Case: RowNone}
67 }
68 return RowDecision{Case: RowRetiring, HoldOp: o.Op}
69 }
70 }
71 return unexplained(exists)
72}
73
74func unexplained(exists bool) RowDecision {
75 if exists {
76 return RowDecision{Case: RowUnexplained}
77 }
78 return RowDecision{Case: RowNone}
79}
80