package host import ( "context" "crypto/sha256" "encoding/hex" "fmt" "slices" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/hostguard" "github.com/carlosframework/platform/internal/park" "github.com/carlosframework/platform/internal/provision" "github.com/carlosframework/platform/internal/registry" ) func rootFirstInstallation(c *hostclaim.Claim, actor hostbox.Actor) error { switch c.Op.Kind { case hostclaim.KindServing: if c.Holder.WriterBox != actor.Box && (c.Holder.WriterBox != "" || c.Holder.Session != 0) { return hostbox.ErrChanged } return hostbox.Serving(c, hostbox.Selection{Box: actor.Box}) case hostclaim.KindRelocating: if c.Holder.Family != "instance" || c.Op.Intent["target_box"] != actor.Box || (c.Op.Intent["target_enrollment"] != "" && c.Op.Intent["target_enrollment"] != actor.Enrollment) { return hostbox.ErrChanged } if c.Op.Journal["local_install"] != "" { return hostbox.ErrChanged } return relocationInstallAuthority(c, c.Op.ID, actor.Box, hostclaim.PhaseInstalling, hostclaim.PhaseInstalled) case hostclaim.KindLanding: if c.Op.Phase != provision.LandChecking { return hostbox.ErrChanged } return rootLandingIdentity(c, actor) default: return hostbox.ErrChanged } } func rootLandingIdentity(c *hostclaim.Claim, actor hostbox.Actor) error { 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) { return hostbox.ErrChanged } return nil } func rootLandingEntry(q hostbox.JournalRequest, c *hostclaim.Claim, actor hostbox.Actor) hostbox.StopInventoryEntry { sum := sha256.Sum256([]byte(fmt.Sprintf("%s\x00%s\x00%d\x00%s", c.Host, c.Holder.Incarnation, c.Holder.Stamp, actor.Box))) owner := hex.EncodeToString(sum[:]) sum = sha256.Sum256([]byte(fmt.Sprintf("%s\x00landing\x00%s\x00%d\x00%s", owner, c.Op.ID, c.Holder.Session, q.ID))) id := hex.EncodeToString(sum[:]) return hostbox.StopInventoryEntry{Kind: "route", ArtifactID: id, ManagedRoot: "registry", RelativePath: c.Host, RowIdentity: id, Ownership: owner, Materialization: "materialized"} } func (h ClaimRootHTTP) rootLandingRoute(ctx context.Context, c *hostclaim.Claim, actor hostbox.Actor) (registry.Route, error) { if err := rootLandingIdentity(c, actor); err != nil { return registry.Route{}, err } rec, _, err := provision.FindRecordByHost(ctx, h.Stop.Coordinator.Evidence, c.Host) if err != nil { return registry.Route{}, err } m := rec.Move 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) { return registry.Route{}, hostbox.ErrChanged } policy, err := relocationUpdatePolicy(ctx, h.Stop.Coordinator.Evidence, *rec) if err != nil { return registry.Route{}, err } rt := provision.RouteFor(*rec, h.Roots["data"], "", false, policy) rt.Status, rt.HoldOp = "landing", c.Op.ID return rt, nil } func landingRegistrationMatches(in hostguard.RootInstallation, c *hostclaim.Claim, row *registry.Route) bool { r := in.Registration 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) }