diff --git a/cmd/mesh-controller/adopting_test.go b/cmd/mesh-controller/adopting_test.go index 3157e46..b10b202 100644 --- a/cmd/mesh-controller/adopting_test.go +++ b/cmd/mesh-controller/adopting_test.go @@ -168,7 +168,7 @@ func TestConvergingPreviewsThenChangesAndAdoptingKeepsWhatWasTaken(t *testing.T) // The anchor faces inward and is on the private network: the derived filter admits ssh // from the mesh only. "WILL CLOSE to everything outside the private network — ssh stays open from the mesh", - "notes\n replacing the found file /etc/notes.conf (original kept at", + "notes\n replacing the found file /etc/notes.conf (notes.conf), original kept at", "assigns nftables", "the found firewall (ufw) is disabled, never flushed", // What it routes is not a listener: said not to be previewed, and to be dropped. @@ -431,3 +431,45 @@ func TestTheFlipHoldsTheNodeWhileItSends(t *testing.T) { } release() } + +// novox/hq ADR 0103: the preview names every kind of thing a module the flip takes holds as found, +// not only its files, and the digest changes when any of them does. +func TestThePreviewNamesEveryHeldKind(t *testing.T) { + open, _ := anAdoptedAnchor(t) + ctx := t.Context() + if _, err := take(ctx, open, "anchor", "hello-web"); err != nil { + t.Fatal(err) + } + since := time.Now() + held := []link.Held{heldFile, + {ID: "notes.data", Module: "notes", Kind: "directory", Target: "/var/lib/notes", Since: since}, + {ID: "notes.daemon", Module: "notes", Kind: "service", Target: "notes.service", Since: since}, + {ID: "notes.seed", Module: "notes", Kind: "archive", Target: "/srv/notes", Since: since}, + {ID: "notes.worker", Module: "notes", Kind: "process", Target: "notes-worker", Since: since}, + {ID: "notes.account", Module: "notes", Kind: "user", Target: "notes", Since: since}, + } + reportsHolding(t, open, held...) + preview, err := converge(ctx, open, "anchor", false, "", "") + if err != nil { + t.Fatal(err) + } + for _, want := range []string{ + "replacing the found directory /var/lib/notes (notes.data)", + "replacing the found service notes.service (notes.daemon)", + "replacing the found archive /srv/notes (notes.seed)", + "replacing the found process notes-worker (notes.worker)", + "replacing the found user notes (notes.account)", + } { + if !strings.Contains(preview, want) { + t.Errorf("the preview does not say %q:\n%s", want, preview) + } + } + reportsHolding(t, open, held[:len(held)-1]...) + fewer, err := converge(ctx, open, "anchor", false, "", "") + if err != nil { + t.Fatal(err) + } + if digestIn(t, fewer) == digestIn(t, preview) { + t.Fatal("the digest does not change with what is held") + } +} diff --git a/cmd/mesh-controller/adoption.go b/cmd/mesh-controller/adoption.go index ed89c3d..de93a6c 100644 --- a/cmd/mesh-controller/adoption.go +++ b/cmd/mesh-controller/adoption.go @@ -119,7 +119,7 @@ func take(ctx context.Context, open *stores, node, module string) (string, error var replaces []string for _, h := range reported.Held { if h.Module == module { - replaces = append(replaces, fmt.Sprintf(" %s %s (%s)", h.Kind, h.Target, h.ID)) + replaces = append(replaces, " "+heldLine(h)) } } if len(replaces) > 0 { @@ -347,14 +347,18 @@ func previewOf(node string, reported inventory.Adoption, derived derivedFilter, for _, m := range takes { fmt.Fprintf(&b, " %s\n", m) said = append(said, "take "+m) + // Every kind it holds — a directory, a service, an archive, a process, a user as well as a + // file (novox/hq ADR 0103) — each said, and each part of what the flip is asked to act on. for _, h := range reported.Held { - if h.Module == m && h.Kind == "file" { - fmt.Fprintf(&b, " replacing the found file %s", h.Target) - if h.Kept != "" { - fmt.Fprintf(&b, " (original kept at %s)", h.Kept) - } - b.WriteString("\n") + if h.Module != m { + continue } + fmt.Fprintf(&b, " replacing the found %s", heldLine(h)) + if h.Kept != "" { + fmt.Fprintf(&b, ", original kept at %s", h.Kept) + } + b.WriteString("\n") + said = append(said, "replace "+m+" "+heldLine(h)+" "+h.Kept) } } if !filterAssigned { @@ -427,6 +431,11 @@ func (d derivedFilter) fate(r inventory.Reach) string { return "WILL CLOSE — no module assigned here declares it" } +// heldLine is one thing a node holds as found, as take and the converge preview both say it. +func heldLine(h inventory.Held) string { + return fmt.Sprintf("%s %s (%s)", h.Kind, h.Target, h.ID) +} + // loopback is an address nothing off the machine reaches. func loopback(address string) bool { a := strings.Trim(address, "[]")