package hostops import ( "context" "github.com/carlosframework/platform/internal/hostclaim" ) // CompletePurgeFences releases every held purge fence, records that in the // journal while the purging operation still owns admission, closes the // incarnation with the typed CompletePurge (the only writer of last_purge), // and finally removes the journal. Each step replays. func (c Controller) CompletePurgeFences(ctx context.Context, h *OperationHandle) error { if c.Control == nil || h == nil || h.Kind() != OpPurging { return ErrContract } account, app, id, appID := h.Account(), h.App(), h.ID(), h.AppID() j, _, err := ReadPurgeJournal(ctx, c.Store, account, app, id, appID) if err != nil { return err } if j.Phase != "done" { return ErrPending } if !j.Cleanup.Fences { for host, ph := range j.Hosts { if ph.FenceState != "held" { continue } obs, err := hostclaim.Read(ctx, c.Store, host) if err != nil { return err } if obs.Absent { return ErrPending } if obs.Claim.Holder == nil && obs.Claim.Op.Kind == hostclaim.KindPurging && obs.Claim.Op.ID == id { if _, err = hostclaim.Update(ctx, c.Store, obs, ReleasePurgeFence(id)); err != nil { return err } } else if obs.Claim.Gen <= ph.FenceGen { return ErrPending } // A changed successor cannot have been admitted before this fence // was released. Do not touch it; keep the old generation as proof. fresh, tag, err := ReadPurgeJournal(ctx, c.Store, account, app, id, appID) if err != nil { return err } saved := fresh.Hosts[host] saved.FenceState = "released" fresh.Hosts[host] = saved if _, err = c.Control.SavePurgeJournal(ctx, fresh, tag); err != nil { return err } } fresh, tag, err := ReadPurgeJournal(ctx, c.Store, account, app, id, appID) if err != nil { return err } fresh.Cleanup.Fences = true if _, err = c.Control.SavePurgeJournal(ctx, fresh, tag); err != nil { return err } } if err = h.CompletePurge(ctx); err != nil { return err } return c.Control.RemovePurgeJournal(ctx, account, app, id) }