package host import ( "context" "github.com/carlosframework/platform/internal/awsinv" "github.com/carlosframework/platform/internal/hostactors" "github.com/carlosframework/platform/internal/hostfence" "github.com/carlosframework/platform/internal/hostfloor" "github.com/carlosframework/platform/internal/release" "log" "os" "strings" "time" ) func runHostFencePass(ctx context.Context) { if strings.TrimSpace(os.Getenv("CARLOS_HOST_CLAIM")) == "" || os.Getenv("CARLOS_FLEET") != "" { return } runHostFenceLoop(ctx, 10*time.Minute, hostFenceOnce) } func runHostFenceLoop(ctx context.Context, interval time.Duration, once func(context.Context) error) { ticker := time.NewTicker(interval) defer ticker.Stop() for { if ctx.Err() != nil { return } pass, cancel := context.WithTimeout(ctx, 2*time.Minute) err := once(pass) cancel() if err != nil { log.Printf("host fence pass: %v", err) } select { case <-ctx.Done(): return case <-ticker.C: } } } func hostFenceOnce(ctx context.Context) error { fences, err := hostfence.OpenRootFenceStore(ctx, os.Getenv("CARLOS_DEPLOYMENT_BUCKET")) if err != nil { return err } store, pub, err := openSystemStore(ctx) if err != nil { return err } enrollment, err := hostfloor.ReadEnrollment("/etc/carlos/host-actor.json") if err != nil { return err } d := hostactors.Directory{Store: store, PublicKey: pub, Bucket: os.Getenv("CARLOS_DEPLOYMENT_BUCKET")} worker := hostfence.TerminationWorker{Fences: fences, Enabled: true, Directory: d, Self: hostfence.Worker{Box: enrollment.Box, Enrollment: enrollment.Enrollment}, Reader: awsinv.NewEC2Reader, Now: time.Now} floor, err := hostfloor.Read(ctx, store, pub, d.Bucket) if err == nil { local, loadErr := floorDisk(release.OptDir()) if loadErr != nil { err = loadErr } else { _, armed, e := local.Load() if e != nil { err = e } else if armed.Digest != floor.Digest { err = hostfloor.ErrFloor } } } if err == nil { roster, e := d.Read(ctx) err = e if e == nil { self := roster.Roster.Boxes[enrollment.Box] for ref, box := range roster.Roster.Boxes { if ref == enrollment.Box || box.Region != self.Region || box.State == "retired" { continue } if _, fenceErr := worker.Describe(ctx, ref); fenceErr != nil { log.Printf("host fence %s: awaiting verified termination: %v", ref, fenceErr) } } } } return err }