diff --git a/cmd/mesh-controller/adoption.go b/cmd/mesh-controller/adoption.go index ddad0cbe..96390916 100644 --- a/cmd/mesh-controller/adoption.go +++ b/cmd/mesh-controller/adoption.go @@ -13,6 +13,7 @@ import ( "time" "git.novox.be/novox/mesh-sdk/go/catalogue" + "git.novox.be/novox/mesh-sdk/go/compose" "git.novox.be/novox/mesh-sdk/go/overlay" "github.com/novox/mesh-controller/internal/inventory" ) @@ -243,7 +244,7 @@ func take(ctx context.Context, open *stores, node, module string, opts takeOptio return "", err } if !slices.Contains(assigned, module) { - if plan, _, err := planFor(ctx, open, node); err == nil { + if plan, _, err := resolveNode(ctx, open, node); err == nil { if why, runs := plan.Because[module]; runs { return "", fmt.Errorf("%w: %s runs on %s because %s — assign it to %s to take it", inventory.ErrNotAssigned, module, node, why, node) @@ -649,7 +650,7 @@ func converge(ctx context.Context, open *stores, node string, yes bool, digest s if err != nil { return "", err } - plan, settings, err := planFor(ctx, open, node) + plan, _, err := resolveNode(ctx, open, node) if err != nil { return "", err } @@ -706,14 +707,19 @@ func converge(ctx context.Context, open *stores, node string, yes bool, digest s filter) } - gens, err := generators(ctx, open) + // What the filter is derived from: the rendering of this machine as a question reads it, with the private network. + input, err := inputFor(ctx, open) if err != nil { return "", err } - with, _, err := renderingFor(ctx, open, node, plan, settings, gens, Reading) + rendered, err := compose.Render(input.Input, node, compose.Reading) if err != nil { return "", err } + with := rendered.Rendering + if with.Generators, err = compose.Generators(input.Input); err != nil { + return "", err + } rules, err := plan.Rules(with) if err != nil { return "", err @@ -776,7 +782,7 @@ func converge(ctx context.Context, open *stores, node string, yes bool, digest s if _, err := inv.Assign(ctx, node, filter); err != nil { return "", err } - if _, _, err := planFor(ctx, open, node); err != nil { + if _, _, err := resolveNode(ctx, open, node); err != nil { _ = inv.Unassign(ctx, node, filter) return "", fmt.Errorf("%s cannot run %s, so it was not converged: %w", node, filter, err) } diff --git a/cmd/mesh-controller/build_source.go b/cmd/mesh-controller/build_source.go index 1f54422f..9dc1dc05 100644 --- a/cmd/mesh-controller/build_source.go +++ b/cmd/mesh-controller/build_source.go @@ -88,7 +88,7 @@ func newSourceForms(ctx context.Context, inv *inventory.Inventory) *sourceForms if world == nil { w := catalogue.World{} if shelf, err := inv.Catalogue(ctx); err == nil { - if read, err := theRestOfTheMesh(ctx, inv, shelf, ""); err == nil { + if read, err := restOfTheMeshOf(ctx, inv, shelf, ""); err == nil { w = read } } diff --git a/cmd/mesh-controller/checks.go b/cmd/mesh-controller/checks.go index 500fe76c..7f47ae09 100644 --- a/cmd/mesh-controller/checks.go +++ b/cmd/mesh-controller/checks.go @@ -281,7 +281,7 @@ func checkRequestFor(ctx context.Context, open *stores, p link.PullUpdated, scop for _, e := range entries { shelf[e.Manifest.Module] = e.Manifest } - world, err := theRestOfTheMesh(ctx, open.inventory, shelf, "") + world, err := restOfTheMesh(ctx, open, shelf, "") if err != nil { return link.BuildRequest{}, err } diff --git a/cmd/mesh-controller/compose_callers_test.go b/cmd/mesh-controller/compose_callers_test.go new file mode 100644 index 00000000..4cd076c7 --- /dev/null +++ b/cmd/mesh-controller/compose_callers_test.go @@ -0,0 +1,63 @@ +package main + +import ( + "go/ast" + "go/parser" + "go/token" + "path/filepath" + "sort" + "strings" + "testing" +) + +// 1388: no caller composes through the controller's own composition any more. The only functions left that call it are the +// composition's own, which issue 1389 deletes with it; this fails the moment any other function reaches for it again. +func TestNoCallerComposesThroughTheControllersOwnComposition(t *testing.T) { + legacy := map[string]bool{"planFor": true, "declarationWith": true, "composedAndValidated": true, "generators": true, + "renderingFor": true, "theRestOfTheMesh": true, "whoResolves": true} + // The composition's own pairs, until 1389: "file: caller calls callee". + allowed := map[string]bool{ + "facts.go: composedAndValidated calls declarationWith": true, + "facts.go: composedAndValidated calls planFor": true, + "network.go: generators calls whoResolves": true, + "network.go: whoResolves calls planFor": true, + "plan.go: declarationWith calls renderingFor": true, + "plan.go: grantsFor calls planFor": true, + "plan.go: planFor calls theRestOfTheMesh": true, + } + files, err := filepath.Glob("*.go") + if err != nil { + t.Fatal(err) + } + fset := token.NewFileSet() + var found []string + for _, f := range files { + if strings.HasSuffix(f, "_test.go") { + continue + } + file, err := parser.ParseFile(fset, f, nil, 0) + if err != nil { + t.Fatal(err) + } + for _, d := range file.Decls { + fn, ok := d.(*ast.FuncDecl) + if !ok || fn.Body == nil { + continue + } + ast.Inspect(fn.Body, func(n ast.Node) bool { + if c, ok := n.(*ast.CallExpr); ok { + if id, ok := c.Fun.(*ast.Ident); ok && legacy[id.Name] { + found = append(found, f+": "+fn.Name.Name+" calls "+id.Name) + } + } + return true + }) + } + } + sort.Strings(found) + for _, pair := range found { + if !allowed[pair] { + t.Errorf("%s: it composes through the controller's own composition, not mesh-sdk's", pair) + } + } +} diff --git a/cmd/mesh-controller/delivery.go b/cmd/mesh-controller/delivery.go index 9014ce1e..e8d35fd8 100644 --- a/cmd/mesh-controller/delivery.go +++ b/cmd/mesh-controller/delivery.go @@ -1179,7 +1179,7 @@ func askGroupCheck(ctx context.Context, open *stores, group string, members []or request.Check.Group = group // A group's check is queued as ready when any member's pull request is marked ready. request.Check.Ready = slices.ContainsFunc(members, func(m orderMember) bool { return m.Ready }) - world, err := theRestOfTheMesh(ctx, open.inventory, shelfOf(entries), "") + world, err := restOfTheMesh(ctx, open, shelfOf(entries), "") if err != nil { return "", err } diff --git a/cmd/mesh-controller/holdings.go b/cmd/mesh-controller/holdings.go index 4de860ac..d4893725 100644 --- a/cmd/mesh-controller/holdings.go +++ b/cmd/mesh-controller/holdings.go @@ -36,7 +36,7 @@ func recordDerivedHolders(ctx context.Context, open *stores) ([]string, error) { return nil, err } // exclude nobody: every node's claims, resolved with the holdings on record. - world, err := theRestOfTheMesh(ctx, inv, shelf, "") + world, err := restOfTheMesh(ctx, open, shelf, "") if err != nil { return nil, err } diff --git a/cmd/mesh-controller/network.go b/cmd/mesh-controller/network.go index 7308a464..2137473e 100644 --- a/cmd/mesh-controller/network.go +++ b/cmd/mesh-controller/network.go @@ -12,6 +12,7 @@ import ( "time" "git.novox.be/novox/mesh-sdk/go/catalogue" + "git.novox.be/novox/mesh-sdk/go/compose" "git.novox.be/novox/mesh-sdk/go/overlay" "github.com/novox/mesh-controller/internal/inventory" ) @@ -308,16 +309,11 @@ func network(ctx context.Context, inv *inventory.Inventory, on map[string]bool, // graph is the whole mesh's network, for showing it. func graph(ctx context.Context, open *stores) ([]overlay.Node, overlay.Graph, error) { - inv := open.inventory - on, refused, err := whoResolves(ctx, open, overlay.Requirement) + in, err := inputFor(ctx, open) if err != nil { return nil, nil, err } - g, err := network(ctx, inv, on, refused) - if err != nil { - return nil, nil, err - } - return g.Nodes(), g.Graph(), nil + return compose.Graph(in.Input) } // whoResolves is the machines whose resolution answers a requirement, and why the others did not. diff --git a/cmd/mesh-controller/plan_backups.go b/cmd/mesh-controller/plan_backups.go index f258d7a6..024b2fdc 100644 --- a/cmd/mesh-controller/plan_backups.go +++ b/cmd/mesh-controller/plan_backups.go @@ -124,7 +124,7 @@ func loadBackupFacts(ctx context.Context, inv *inventory.Inventory) (backupFacts if err != nil { return nil, err } - world, err := theRestOfTheMesh(ctx, inv, shelf, "") + world, err := restOfTheMeshOf(ctx, inv, shelf, "") if err != nil { return nil, err } diff --git a/cmd/mesh-controller/seats.go b/cmd/mesh-controller/seats.go index 439a05d3..c5da96b6 100644 --- a/cmd/mesh-controller/seats.go +++ b/cmd/mesh-controller/seats.go @@ -252,7 +252,7 @@ func seatsCommand(ctx context.Context, args []string) error { return err } // Every node, none excluded: the same view of what each machine holds that planning uses. - world, err := theRestOfTheMesh(ctx, inv, shelf, "") + world, err := restOfTheMesh(ctx, open, shelf, "") if err != nil { return err } diff --git a/cmd/mesh-controller/source.go b/cmd/mesh-controller/source.go index ea9cd701..b54a6678 100644 --- a/cmd/mesh-controller/source.go +++ b/cmd/mesh-controller/source.go @@ -68,7 +68,7 @@ func cloneFrom(ctx context.Context, source buildSource) (string, error) { if err != nil { return "", err } - world, err := theRestOfTheMesh(ctx, open.inventory, shelf, "") + world, err := restOfTheMesh(ctx, open, shelf, "") if err != nil { return "", err } @@ -154,7 +154,7 @@ func seatBases(ctx context.Context) map[string]string { if err != nil { return unread("the catalogue", err) } - world, err := theRestOfTheMesh(ctx, open.inventory, shelf, "") + world, err := restOfTheMesh(ctx, open, shelf, "") if err != nil { return unread("who holds which seat", err) }