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 }