package deploy import ( "context" "evobgp/internal/logging" "fmt" "log" "os" "strings" "time" "evobgp/internal/broker" "evobgp/internal/config" "evobgp/internal/store" ) // Deps enables deploy-side drift logging between published and last-applied revision per speaker. type Deps struct { Store store.Backend } // Run blocks until ctx is cancelled. func Run(ctx context.Context, deps *Deps) { cfg := config.Load() broker.LogConnect(ctx, cfg.BrokerURL) if d := strings.TrimSpace(os.Getenv("EVOBGP_BIRD_ACTIVE_DIR")); d != "" { logging.Default().Info(fmt.Sprintf("evobgp-deploy: EVOBGP_BIRD_ACTIVE_DIR=%q (apply via API jobs when API has same env)", d)) } if deps == nil || deps.Store == nil { log.Fatalf("evobgp-deploy: missing store (pass deploy.Deps from BootstrapWorkers or evobgp-all)") } t := time.NewTicker(90 * time.Second) defer t.Stop() logging.Default().Info(fmt.Sprintf("evobgp-deploy: active (speaker published vs applied drift log)")) for { select { case <-ctx.Done(): logging.Default().Info(fmt.Sprintf("evobgp-deploy: stopped")) return case <-t.C: logDrift(context.Background(), deps.Store) } } } func logDrift(ctx context.Context, st store.Backend) { _ = ctx tenants, err := st.ListTenantIDs() if err != nil { logging.Default().Info(fmt.Sprintf("evobgp-deploy: list tenants: %v", err)) return } for _, tid := range tenants { for _, sp := range st.ListSpeakersForTenant(tid) { pub, _, err := st.LatestPublishedRevision(sp.ID) if err != nil { continue } applied := "" if sp.LastAppliedRevisionID != nil { applied = *sp.LastAppliedRevisionID } if applied != "" && applied != pub { logging.Default().Info(fmt.Sprintf("evobgp-deploy: drift speaker=%s applied=%s published=%s", sp.ID, applied, pub)) } } } }