package host import ( "log" "sync" "github.com/carlosframework/platform/internal/release" "github.com/carlosframework/platform/internal/rollout" ) // updatesPassOption arms the instance update settings on an adoption pass // (settings spec §4). root is set on carlos-adopt's pass only: root resolves // install requests and writes the consumed file; the agent's passes apply // the same decisions and write nothing. // // The failure book is the zero-downtime plans' (§4.3: failure records // outrank every rule), read from dd's swap-failures.json at the start of // every pass, never once per process: the fast loop's options are built once // per agent run. A build is failed for a host when the book blocks it // (Blocks: a record the host has not served or been retried past) or holds // the host down on it (HeldDown: a hold attempt onto it failed there). An // unreadable book holds every route with settings and every managed route // (rollout.Managed), as refuseManaged does; a default unmanaged route keeps // today's adoption, which never read the book. // // The pass prints the unreadable-book line on root's pass only. The agent's // opener logs it here once per distinct error, since the fast loop runs a // pass every few seconds with options built once. func updatesPassOption(dd string, root bool, providers ...release.RootUpdateOpener) release.PassOption { var ( mu sync.Mutex lastErr string ) open := func() (release.FailedBuild, error) { book, err := rollout.OpenFailureBook(dd) mu.Lock() said := "" if err != nil { said = err.Error() } if !root && err != nil && said != lastErr { log.Printf("agent: failure book unreadable (%v): routes with update settings and managed routes install nothing", err) } lastErr = said mu.Unlock() if err != nil { return nil, err } return func(acct, app, build, host string, served bool) bool { return book.Blocks(acct, app, build, host, served) || book.HeldDown(acct, app, build, host) }, nil } legacy := release.WithUpdateSettings(open, rollout.Managed, root) if !root { return legacy } provider := productionRootUpdates(dd) if len(providers) == 1 { provider = providers[0] } return release.CombinePassOptions(legacy, release.WithRootUpdateInputs(provider)) }