164 lines
5.6 KiB
Go
164 lines
5.6 KiB
Go
package main
|
|
|
|
// Where modules stand, from the placement (novox/hq ADR 0549 §3, §5; ADR 0561; issue 774), the seat mesh-placement's
|
|
// state held by the assigner (ADR 0567). The controller's assignments mirror goes with its lease, so the vault reads which
|
|
// module stands on which node from the seat's placement first, and the assignments beside it while both stand: a module either names stands. The provisioner's plan,
|
|
// which only an assignment's value carries, is read from the assignments still: its home after the lease is a subtask of
|
|
// its own (issue 774).
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"slices"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// PlacementRead is the seat mesh-placement's placement, as the vault's manifest reads it (mesh-sdk's contract).
|
|
const PlacementRead = delivery.PlacementRead
|
|
|
|
// PlacementReader reads the seat's placement: every key, and one key's value (nil when there is none).
|
|
type PlacementReader struct {
|
|
Keys func() ([]string, error)
|
|
Read func(key string) ([]byte, error)
|
|
}
|
|
|
|
// placements is every node's placement, by node, from the state's keys in either form (delivery.PlacementsOf; research
|
|
// 072 row 37); none when the vault reads no placement. A node whose keys do not read whole is read as they stand.
|
|
func (v *Vault) placements() (map[string]delivery.Placement, error) {
|
|
out := map[string]delivery.Placement{}
|
|
if v.Placement.Keys == nil || v.Placement.Read == nil {
|
|
return out, nil
|
|
}
|
|
keys, err := v.Placement.Keys()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("the placement's keys could not be read: %w", err)
|
|
}
|
|
values := map[string][]byte{}
|
|
for _, k := range keys {
|
|
if _, _, _, err := delivery.ParsePlacementKey(k); err != nil {
|
|
continue
|
|
}
|
|
raw, err := v.Placement.Read(k)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("the placement's key %s could not be read: %w", k, err)
|
|
}
|
|
if raw != nil {
|
|
values[k] = raw
|
|
}
|
|
}
|
|
out, _ = delivery.PlacementsOf(values)
|
|
return out, nil
|
|
}
|
|
|
|
// nodePlaced is what node's own key of the placement says: the modules placed there and what a person decided of it,
|
|
// read from its node key `<node>.node` alone (which names every module placed, research 072 row 37), or, for a node not
|
|
// converted yet, from its key in the form before, `placement.<node>`. found is false when it has neither.
|
|
func (v *Vault) nodePlaced(node string) (modules []string, decided delivery.NodeDecided, found bool, err error) {
|
|
key, err := delivery.PlacementNodeKey(node)
|
|
if err != nil {
|
|
return nil, decided, false, err
|
|
}
|
|
raw, err := v.Placement.Read(key)
|
|
if err != nil {
|
|
return nil, decided, false, err
|
|
}
|
|
if raw != nil {
|
|
n, err := delivery.DecodePlacementNode(raw)
|
|
if err != nil {
|
|
return nil, decided, false, fmt.Errorf("the placement of %s is not readable: %w", node, err)
|
|
}
|
|
for _, r := range n.Modules {
|
|
modules = append(modules, r.Module)
|
|
}
|
|
return modules, n.Decided, true, nil
|
|
}
|
|
legacy, err := delivery.LegacyPlacementKey(node)
|
|
if err != nil {
|
|
return nil, decided, false, err
|
|
}
|
|
if raw, err = v.Placement.Read(legacy); err != nil || raw == nil {
|
|
return nil, decided, false, err
|
|
}
|
|
p, err := delivery.DecodePlacement(raw)
|
|
if err != nil {
|
|
return nil, decided, false, fmt.Errorf("the placement of %s is not readable: %w", node, err)
|
|
}
|
|
return p.Assigned(), p.Decided, true, nil
|
|
}
|
|
|
|
// placedOn says module is placed on node by the catalogue.
|
|
func (v *Vault) placedOn(node, module string) (bool, error) {
|
|
placed, err := v.placedModules(node)
|
|
return slices.Contains(placed, module), err
|
|
}
|
|
|
|
// placedModules is every module the catalogue places on node, read from the node's own key of the placement
|
|
// (nodePlaced); none when the vault reads no placement or the node has no key.
|
|
func (v *Vault) placedModules(node string) ([]string, error) {
|
|
if v.Placement.Read == nil {
|
|
return nil, nil
|
|
}
|
|
modules, _, _, err := v.nodePlaced(node)
|
|
return modules, err
|
|
}
|
|
|
|
// standsOn says module stands on node: placed there, or assigned there while the assignments stand. A read that fails is
|
|
// an error, never "not there".
|
|
func (v *Vault) standsOn(node, module string) (bool, error) {
|
|
placed, err := v.placedOn(node, module)
|
|
if err != nil || placed {
|
|
return placed, err
|
|
}
|
|
d, ok := v.Askers.(Declared)
|
|
if !ok || d.Read == nil {
|
|
if v.Placement.Read == nil {
|
|
return false, errors.New("the vault reads neither the placement nor the assignments")
|
|
}
|
|
return false, nil
|
|
}
|
|
raw, err := standing(d.Read)(node + "." + module)
|
|
return raw != nil, err
|
|
}
|
|
|
|
// busNode is the node running the bus's module: from the placement, and from the assignments while no placement names
|
|
// one. The vault adopts from one node alone.
|
|
func (v *Vault) busNode() (string, error) {
|
|
placed, err := v.placements()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
var nodes []string
|
|
for node, p := range placed {
|
|
if slices.Contains(p.Assigned(), BusModule) {
|
|
nodes = append(nodes, node)
|
|
}
|
|
}
|
|
from := "placed"
|
|
if len(nodes) == 0 && v.Assignments.Keys != nil {
|
|
from = "assigned"
|
|
keys, err := v.Assignments.Keys()
|
|
if err != nil {
|
|
return "", fmt.Errorf("the assignments' keys could not be read: %w", err)
|
|
}
|
|
for _, k := range keys {
|
|
if node, module, ok := strings.Cut(k, "."); ok && module == BusModule {
|
|
nodes = append(nodes, node)
|
|
}
|
|
}
|
|
} else if len(nodes) == 0 && len(placed) == 0 {
|
|
return "", errors.New("the vault reads neither the placement nor the assignments, so it cannot tell which node holds the bus")
|
|
}
|
|
sort.Strings(nodes)
|
|
switch len(nodes) {
|
|
case 1:
|
|
return nodes[0], nil
|
|
case 0:
|
|
return "", fmt.Errorf("no node is %s the bus module %s", from, BusModule)
|
|
}
|
|
return "", fmt.Errorf("%d nodes are %s the bus module %s (%s): the vault adopts from one alone", len(nodes), from,
|
|
BusModule, strings.Join(nodes, ", "))
|
|
}
|