package host import ( "context" "slices" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/hostclaim" execlease "github.com/carlosframework/platform/internal/hostexec" "github.com/carlosframework/platform/internal/hostwrite" ) type participationCleanupRead func(context.Context, string) (hostclaim.Observed, error) func (f participationCleanupRead) Read(ctx context.Context, host string) (hostclaim.Observed, error) { return f(ctx, host) } func previousParticipationRetired(o hostclaim.Observed, binding execlease.Binding) bool { if o.Absent || o.Claim == nil || o.Host != binding.Host || o.Claim.Host != binding.Host || o.Claim.Validate() != nil { return false } c := o.Claim return c.Free() || (c.Holder != nil && c.Holder.Incarnation != binding.Incarnation && slices.Contains(c.RetiredIncarnations, binding.Incarnation)) } func (p *productionClaimLocal) clearUntracked(ctx context.Context, actor hostbox.Actor, o hostclaim.Observed, state execlease.State, cfg execlease.Config) error { if p.Resources.Mode != "agent" || state.Box != actor.Box || state.Enrollment != actor.Enrollment || cfg.Binding != state.Binding { return execlease.ErrState } if o.Claim != nil && o.Claim.Holder != nil && state.Incarnation == o.Claim.Holder.Incarnation { if err := p.cleanup(ctx, o, state.Binding); err != nil { return err } return execlease.ClearStale(ctx, cfg) } if !previousParticipationRetired(o, state.Binding) { return execlease.ErrState } p.mu.Lock() a := p.assembly p.mu.Unlock() if a == nil || a.Launches == nil || a.Reconcile == nil || a.Reconcile.Census == nil || cfg.Guard.Claims == nil { return hostwrite.ErrUnavailable } p.cancelWork(o.Host) reader := cfg.Guard.Claims cfg.Guard.Claims = participationCleanupRead(func(ctx context.Context, host string) (hostclaim.Observed, error) { fresh, err := reader.Read(ctx, host) if err != nil { return fresh, err } if !previousParticipationRetired(fresh, state.Binding) { return fresh, execlease.ErrState } has, err := a.Launches.HasHost(ctx, host) if err != nil { return fresh, err } if has { return fresh, ErrClaimStopInventory } // ClearStale holds the controller lifetime lock and has durably denied // the previous state. Prove the exact old incarnation empty here; never // infer a stop target from the replacement holder or fabricate a stamp. err = a.Reconcile.Census.CheckLocal(ctx, fresh, hostbox.RecordSelection{Host: host, Incarnation: state.Incarnation}) return fresh, err }) return execlease.ClearStale(ctx, cfg) }