package main import ( "context" "fmt" "time" "github.com/novox/mesh-control/internal/identity" "github.com/novox/mesh-control/internal/inventory" "github.com/novox/mesh-control/internal/licences" "github.com/novox/mesh-control/internal/store" ) // reaching each context's store, which no other context may touch. // // Split out of main.go, which had reached 2,769 lines because appending was always the // cheapest next step. That is how novox/hq ADR 0001 records `hal/sdk` reaching 34,636: // nothing in it was wrong, and no one edit was the one that should have been a new file. // migrate brings every held context's schema up to date. // // Reported per context and per migration, because this runs during a bootstrap on a machine with // nothing else on it — the output is the only account of what happened, and "migrated" is not one. func migrate(ctx context.Context) error { for _, c := range held { migrations, err := c.migrations() if err != nil { return err } s, err := store.Open(ctx, c.name) if err != nil { return err } defer s.Close() // The bootstrap raises PostgreSQL moments before this runs, and a container that is // running is not a database that will answer — a distinction this project has already // paid for once, when a crash-looping database reported itself as up between restarts. if err := s.Ready(ctx, 60*time.Second); err != nil { return err } done, err := s.Migrate(ctx, migrations) for _, m := range done { fmt.Printf("%s: applied %04d-%s\n", c.name, m.Number, m.Name) } if err != nil { return err } if len(done) == 0 { applied, err := s.AppliedMigrations(ctx) if err != nil { return err } fmt.Printf("%s: already up to date — %d migration(s)\n", c.name, len(applied)) } } // The modules the control plane ships with itself. Recorded here rather than by hand, because // a mesh whose own private network is missing from the catalogue would have nothing to assign // and no way to say why. inv, err := openInventory(ctx) if err != nil { return err } defer inv.Close() for _, m := range provided { if err := inv.Provide(ctx, m); err != nil { return err } fmt.Printf("provided %s\n", m.Module) } return nil } // openInventory connects and waits, the way every command that touches it needs to. func openInventory(ctx context.Context) (*inventory.Inventory, error) { inv, err := inventory.Open(ctx) if err != nil { return nil, err } if err := inv.Ready(ctx, 30*time.Second); err != nil { inv.Close() return nil, err } return inv, nil } func openIdentity(ctx context.Context) (*identity.Identity, error) { ident, err := identity.Open(ctx) if err != nil { return nil, err } if err := ident.Ready(ctx, 30*time.Second); err != nil { ident.Close() return nil, err } return ident, nil } // openLicences connects to the context that holds which model access exists and who may use it. func openLicences(ctx context.Context) (*licences.Licences, error) { held, err := licences.Open(ctx) if err != nil { return nil, err } if err := held.Ready(ctx, 30*time.Second); err != nil { held.Close() return nil, err } return held, nil }