| 1 | package host |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "crypto/sha256" |
| 6 | "encoding/hex" |
| 7 | "fmt" |
| 8 | "slices" |
| 9 | |
| 10 | "github.com/carlosframework/platform/internal/hostbox" |
| 11 | "github.com/carlosframework/platform/internal/hostclaim" |
| 12 | "github.com/carlosframework/platform/internal/hostguard" |
| 13 | "github.com/carlosframework/platform/internal/park" |
| 14 | "github.com/carlosframework/platform/internal/provision" |
| 15 | "github.com/carlosframework/platform/internal/registry" |
| 16 | ) |
| 17 | |
| 18 | func rootFirstInstallation(c *hostclaim.Claim, actor hostbox.Actor) error { |
| 19 | switch c.Op.Kind { |
| 20 | case hostclaim.KindServing: |
| 21 | if c.Holder.WriterBox != actor.Box && (c.Holder.WriterBox != "" || c.Holder.Session != 0) { |
| 22 | return hostbox.ErrChanged |
| 23 | } |
| 24 | return hostbox.Serving(c, hostbox.Selection{Box: actor.Box}) |
| 25 | case hostclaim.KindRelocating: |
| 26 | if c.Holder.Family != "instance" || c.Op.Intent["target_box"] != actor.Box || (c.Op.Intent["target_enrollment"] != "" && c.Op.Intent["target_enrollment"] != actor.Enrollment) { |
| 27 | return hostbox.ErrChanged |
| 28 | } |
| 29 | if c.Op.Journal["local_install"] != "" { |
| 30 | return hostbox.ErrChanged |
| 31 | } |
| 32 | return relocationInstallAuthority(c, c.Op.ID, actor.Box, hostclaim.PhaseInstalling, hostclaim.PhaseInstalled) |
| 33 | case hostclaim.KindLanding: |
| 34 | if c.Op.Phase != provision.LandChecking { |
| 35 | return hostbox.ErrChanged |
| 36 | } |
| 37 | return rootLandingIdentity(c, actor) |
| 38 | default: |
| 39 | return hostbox.ErrChanged |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | func rootLandingIdentity(c *hostclaim.Claim, actor hostbox.Actor) error { |
| 44 | if c.Holder.Family != "instance" || c.Op.Exec != actor.Box || (c.Op.Intent["target_enrollment"] != "" && c.Op.Intent["target_enrollment"] != actor.Enrollment) || c.Op.Intent["target"] != actor.Box || c.Op.Intent["source"] == actor.Box || len(c.Op.Participants) != 2 || c.Op.Participants[1] != actor.Box || slices.Contains(c.Lost, actor.Box) || !park.SameRegion(actor.HomeRegion, c.Op.Intent["to"], actor.Region) { |
| 45 | return hostbox.ErrChanged |
| 46 | } |
| 47 | return nil |
| 48 | } |
| 49 | |
| 50 | func rootLandingEntry(q hostbox.JournalRequest, c *hostclaim.Claim, actor hostbox.Actor) hostbox.StopInventoryEntry { |
| 51 | sum := sha256.Sum256([]byte(fmt.Sprintf("%s\x00%s\x00%d\x00%s", c.Host, c.Holder.Incarnation, c.Holder.Stamp, actor.Box))) |
| 52 | owner := hex.EncodeToString(sum[:]) |
| 53 | sum = sha256.Sum256([]byte(fmt.Sprintf("%s\x00landing\x00%s\x00%d\x00%s", owner, c.Op.ID, c.Holder.Session, q.ID))) |
| 54 | id := hex.EncodeToString(sum[:]) |
| 55 | return hostbox.StopInventoryEntry{Kind: "route", ArtifactID: id, ManagedRoot: "registry", RelativePath: c.Host, RowIdentity: id, Ownership: owner, Materialization: "materialized"} |
| 56 | } |
| 57 | |
| 58 | func (h ClaimRootHTTP) rootLandingRoute(ctx context.Context, c *hostclaim.Claim, actor hostbox.Actor) (registry.Route, error) { |
| 59 | if err := rootLandingIdentity(c, actor); err != nil { |
| 60 | return registry.Route{}, err |
| 61 | } |
| 62 | rec, _, err := provision.FindRecordByHost(ctx, h.Stop.Coordinator.Evidence, c.Host) |
| 63 | if err != nil { |
| 64 | return registry.Route{}, err |
| 65 | } |
| 66 | m := rec.Move |
| 67 | if m == nil || m.ID != c.Op.ID || m.Incarnation != c.Holder.Incarnation || m.State != provision.MoveLanding || m.Reason != "" || m.LandingPhase != c.Op.Phase || !park.SameRegion(actor.HomeRegion, m.To, actor.Region) || !park.SameRegion(actor.HomeRegion, rec.Region, actor.Region) { |
| 68 | return registry.Route{}, hostbox.ErrChanged |
| 69 | } |
| 70 | policy, err := relocationUpdatePolicy(ctx, h.Stop.Coordinator.Evidence, *rec) |
| 71 | if err != nil { |
| 72 | return registry.Route{}, err |
| 73 | } |
| 74 | rt := provision.RouteFor(*rec, h.Roots["data"], "", false, policy) |
| 75 | rt.Status, rt.HoldOp = "landing", c.Op.ID |
| 76 | return rt, nil |
| 77 | } |
| 78 | |
| 79 | func landingRegistrationMatches(in hostguard.RootInstallation, c *hostclaim.Claim, row *registry.Route) bool { |
| 80 | r := in.Registration |
| 81 | return r.Kind == hostclaim.KindLanding && r.Op == c.Op.ID && r.Phase == provision.LandChecking && (r.Session == c.Holder.Session || hostclaim.SessionPhase(c.Op.Kind, c.Op.Phase)) && r.RowID != "" && row != nil && row.ClaimRowID == r.RowID && row.HoldOp == r.Op && registry.IsHold(row.Status) |
| 82 | } |
| 83 | |