Take the catalogue's composition rules into the node-engine
ADR 0593 §7: the composer with its refusals leaves mesh-sdk, so mesh-sdk carries no composition rule. The catalogue functions only the node-engine's composition reaches (Resolve, Resolution's Compose, Declaration, DataItems, LeftOut, Rules and the rest, the settings, placeholder and template refusals, the rendering helpers) are copied with their tests into internal/compose/resolution; a method of a mesh-sdk shape becomes a function taking it first. The composition calls its own copies, and the captured catalogue its tests read lives here now, shared by mesh-compose's tests. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package resolution
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
)
|
||||
|
||||
// resolverVerbs is the contract every holder of node-resolver serves (novox/hq ADR 0247): what is routed
|
||||
// where, route a set of domains, and take a route away. The same verbs are served on the machine itself to
|
||||
// the modules there, so what a VPN pushed never crosses the bus to be routed; on the mesh they are the
|
||||
// operator's way to read and correct the same.
|
||||
func resolverVerbs() []mcat.Verb {
|
||||
return []mcat.Verb{
|
||||
{Name: "routes", Description: "What this machine's own resolver sends where: the mesh's resolvers, " +
|
||||
"which answer every name not routed elsewhere, and each link given servers of its own with the " +
|
||||
"domains routed to them. Also the resolver file's outside writes it kept, newest first: when, who " +
|
||||
"wrote it as far as the file says, whether a module took it, and when the resolver's own file was " +
|
||||
"put back.",
|
||||
Input: schema(map[string]string{}, nil),
|
||||
Replaces: []string{"resolvectl status", "resolvectl dns", "resolvectl domain"}},
|
||||
{Name: "route", Description: "Send these domains, and every name under them, to these servers over " +
|
||||
"this link — and only them: the link is never the machine's default route for names, and the " +
|
||||
"mesh's own domain is refused. Replaces whatever the link was given before. A link that goes away " +
|
||||
"takes its route with it.",
|
||||
Input: schema(map[string]string{
|
||||
"link": "the network link the servers are reached over, by name (a VPN's tunnel interface)",
|
||||
"domains": "the domains to route there, separated by spaces or commas",
|
||||
"servers": "the servers' addresses, separated by spaces or commas",
|
||||
}, []string{"link", "domains", "servers"}),
|
||||
Replaces: []string{"resolvectl dns", "resolvectl domain", "resolvectl default-route"}},
|
||||
{Name: "unroute", Description: "Take one link's route away: its domains go back to the mesh's " +
|
||||
"resolvers. Nothing changes when the link has none.",
|
||||
Input: schema(map[string]string{"link": "the network link, by name"}, []string{"link"}),
|
||||
Replaces: []string{"resolvectl revert"}},
|
||||
}
|
||||
}
|
||||
|
||||
// holdsSeat says whether a module claims a seat, by its current name.
|
||||
func holdsSeat(m mcat.Manifest, seat string) bool {
|
||||
for _, c := range m.Claims {
|
||||
if canonicalSeat(c.Name) == seat {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// stepsBack is the module as it composes among the modules of one machine (novox/hq ADR 0287,
|
||||
// ADR 0247):
|
||||
// **where it holds a seat that names a path stepping back for another seat, and that other seat's holder
|
||||
// is on the machine and declares the path, its own rendering of the path is left out**, and nothing else
|
||||
// of it changes. Only a file the mesh renders for it steps back, as before: a resource on the path is
|
||||
// composed as declared (the declaration copies a module's resources whole), so an uplink holder declaring
|
||||
// the resolver file as a resource beside the resolver's holder is two owners of one path, and refused. The stepping back is the seat's definition — node-uplink stepping back from the resolver
|
||||
// file for node-resolver — so any other module declaring the path beside the owner's is still two owners
|
||||
// of one path, and is refused as before.
|
||||
func stepsBack(m mcat.Manifest, modules []mcat.Manifest) mcat.Manifest {
|
||||
drop := map[string]bool{}
|
||||
for _, c := range m.Claims {
|
||||
seat, known := mcat.SeatNamed(c.Name)
|
||||
if !known {
|
||||
continue
|
||||
}
|
||||
for _, p := range seat.Paths {
|
||||
if p.StepsBackFor == "" {
|
||||
continue
|
||||
}
|
||||
for _, o := range modules {
|
||||
if o.Module != m.Module && holdsSeat(o, p.StepsBackFor) && declaresPath(o, p.Path) {
|
||||
drop[p.Path] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(drop) == 0 {
|
||||
return m
|
||||
}
|
||||
facts := make(map[string]mcat.RosterFile, len(m.Facts))
|
||||
for name, f := range m.Facts {
|
||||
if !f.Home && drop[path.Clean(f.Path)] {
|
||||
continue
|
||||
}
|
||||
facts[name] = f
|
||||
}
|
||||
m.Facts = facts
|
||||
return m
|
||||
}
|
||||
|
||||
// steppedBack is every module of one machine as it composes there (stepsBack, each).
|
||||
func steppedBack(modules []mcat.Manifest) []mcat.Manifest {
|
||||
out := make([]mcat.Manifest, len(modules))
|
||||
for i, m := range modules {
|
||||
out[i] = stepsBack(m, modules)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user