A provider is a (node, module) pair (design 23), and the pin — the one way a consumer names its provider — named only the node. Two modules on one node can both answer a provision (public-acme and step-ca both offer acme-ca on novox), and then the resolver, given a pin naming that node, took the last provider listed: a coin flip. The same ambiguity beside the consumer was settled by a map walk — random per plan — which is how novox's own route-proxy got its issuer (novox/hq #258). - `pin <node> <provision> <from-node> <module>`: both halves, always. The console gains `pin` and `unpin`. The provider may be on the consumer's own node, since two modules beside it can both answer. - The resolver refuses ambiguity instead of picking, across machines and beside the consumer alike, naming every candidate as node/module and the form of the pin that settles it. A plain capability that grants nothing and serves nothing (three shells beside an editor) is not a choice to put to anybody and stays as it was. - provision_pin gains a nullable module (0050); records made before are completed where the node they name answers once, and left for a person where it answers twice (0051). - The provider of something already satisfied is looked for among what was assigned, not only what the walk has reached — a consumer reached before the provider beside it no longer loses its binding. - The start-time check that every declared verb is runnable samples each verb's required arguments from its schema instead of three guessed keys. Live consequence: a node that has two providers of one bound provision assigned (novox: acme-ca) resolves only once pinned — `pin novox acme-ca novox public-acme`.
101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"sort"
|
|
)
|
|
|
|
// Chosen is the provider somebody named for a provision: the module, and the node it runs on. Both,
|
|
// always (novox/hq #258) — a provision comes from a module, and the same module on two machines is
|
|
// two answers, so neither half alone says which. Module is empty only on a record made before this
|
|
// was asked, and such a record is honoured exactly as long as it is unambiguous.
|
|
type Chosen struct {
|
|
Node string
|
|
Module string
|
|
}
|
|
|
|
func (c Chosen) String() string {
|
|
if c.Module == "" {
|
|
return c.Node
|
|
}
|
|
return c.Node + "/" + c.Module
|
|
}
|
|
|
|
// matches is whether this provider is the one chosen.
|
|
func (c Chosen) matches(p Provider) bool {
|
|
return p.Node == c.Node && (c.Module == "" || p.Module == c.Module)
|
|
}
|
|
|
|
// among is every offered provider the choice names — one, when the choice is whole.
|
|
func (c Chosen) among(where []Provider) []Provider {
|
|
var out []Provider
|
|
for _, p := range where {
|
|
if c.matches(p) {
|
|
out = append(out, p)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// nameOf is how a refusal names a provider: the node and the module on it.
|
|
func nameOf(p Provider) string {
|
|
return Chosen{Node: p.Node, Module: p.Module}.String()
|
|
}
|
|
|
|
// providerNames is every provider named, sorted, for a refusal to list.
|
|
func providerNames(where []Provider) []string {
|
|
out := make([]string, 0, len(where))
|
|
for _, p := range where {
|
|
out = append(out, nameOf(p))
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|
|
|
|
// providersHere is which modules in this node's own set offer a provision, sorted.
|
|
func providersHere(catalogue map[string]Manifest, here func(string) bool, want string) []string {
|
|
var out []string
|
|
for name, m := range catalogue {
|
|
if !here(name) {
|
|
continue
|
|
}
|
|
for _, o := range m.Offers() {
|
|
if o == want {
|
|
out = append(out, name)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|
|
|
|
// servedByOne is what one provider beside the consumer says a consumer needs to know, or nothing.
|
|
//
|
|
// Serving is *whether* a need is created at all when the provider is on this same machine (novox/hq
|
|
// 04-ISSUES/038's sibling): a need never created is a binding the consumer never gets. The manifest
|
|
// alone answers that; the values are settled later, with the node's settings.
|
|
func servedByOne(m Manifest, want string) map[string]any {
|
|
if _, ok := m.Serves[want]; ok {
|
|
return ServedOn(m, want, nil)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// sharedByOne is the own secret that provider names as its credential (ADR 0158), or "" when it
|
|
// gives each consumer its own.
|
|
func sharedByOne(m Manifest, want string) string {
|
|
if own, shared := m.SharedCredentialOf(want); shared {
|
|
return own
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func oneOf(list []string, s string) bool {
|
|
for _, x := range list {
|
|
if x == s {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|