mesh/delivery closed: the pull request closed unmerged
mesh/check pass 96a37f58ca76 on 030f9ee4e780 | unit 1173 run, 3272 kept, 13 skipped | integration 1212 run, 3274 kept, 22 skipped | over bound: unit, …
The controller's declared-config mirror never held de-spiegel's keys, and Resolve skipped an assigned module it held no declarations of, silently: de-spiegel stayed held on novox with its values set. Declarations now come from the indexer's trunk manifest with the wanted build's laid over it per node; which module runs where from the seat mesh-placement alone. A placed module with no readable manifest is listed as unresolved with why, logged, and keeps its last resolved values.
159 lines
4.9 KiB
Go
159 lines
4.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// Listing the values and reading their history, narrowed by module and node (ADR 0348 §1).
|
|
|
|
// Listed is what a listing answers.
|
|
type Listed struct {
|
|
// Resolved is each module's value on each node the call narrows to, with where it came from.
|
|
Resolved []Resolved `json:"resolved"`
|
|
// Set is every value set at a level the call reaches, with who set it and why.
|
|
Set []SetValue `json:"set"`
|
|
// Predefined is the published list of predefined keys, for a call that names no module.
|
|
Predefined map[string]Published `json:"predefined,omitempty"`
|
|
// Withheld is why the newest list of predefined keys is not published, when it is not.
|
|
Withheld string `json:"withheld,omitempty"`
|
|
// Unresolved is each placed module the call narrows to whose declarations cannot be read, with why (issue 1953).
|
|
Unresolved []Unresolved `json:"unresolved,omitempty"`
|
|
// Held is the approved values held for open pull requests, not yet set (novox/hq ADR 0502).
|
|
Held []HeldValue `json:"held,omitempty"`
|
|
}
|
|
|
|
// SetValue is one value set, at its level.
|
|
type SetValue struct {
|
|
Level Level `json:"level"`
|
|
Key string `json:"key"`
|
|
Value
|
|
}
|
|
|
|
// List answers the resolved values and the values set, narrowed by module, node and key.
|
|
func (c *Config) List(call Call) (*Listed, error) {
|
|
for _, name := range []string{call.Node, call.Module} {
|
|
if name != "" && !nodeOrModule.MatchString(name) {
|
|
return nil, fmt.Errorf("%q is not a node's or a module's name", name)
|
|
}
|
|
}
|
|
c.mu.Lock()
|
|
withheld := c.withheld
|
|
c.mu.Unlock()
|
|
s, err := c.sources()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := &Listed{Resolved: []Resolved{}, Set: []SetValue{}, Withheld: withheld}
|
|
for _, u := range s.Unresolved {
|
|
if (call.Module == "" || u.Module == call.Module) && (call.Node == "" || u.Node == call.Node) {
|
|
out.Unresolved = append(out.Unresolved, u)
|
|
}
|
|
}
|
|
if call.Module != "" {
|
|
if _, ok := s.Declared[call.Module]; !ok && len(out.Unresolved) == 0 {
|
|
return nil, fmt.Errorf("%s is placed on no node with a manifest the indexer holds, so it declares no "+
|
|
"config", call.Module)
|
|
}
|
|
}
|
|
resolved := Resolve(s)
|
|
for _, k := range sortedKeys(resolved) {
|
|
r := resolved[k]
|
|
if (call.Module == "" || r.Module == call.Module) && (call.Node == "" || r.Node == call.Node) &&
|
|
(call.Key == "" || r.Key == call.Key || r.Predefined == call.Key) {
|
|
out.Resolved = append(out.Resolved, r)
|
|
}
|
|
}
|
|
// The predefined keys the narrowed modules fall back to: their mesh and node values are listed too.
|
|
fallsBack := map[string]bool{}
|
|
for _, r := range out.Resolved {
|
|
if r.Predefined != "" {
|
|
fallsBack[r.Predefined] = true
|
|
}
|
|
}
|
|
for _, k := range sortedKeys(s.Values) {
|
|
level, key, ok := parseValueKey(k)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if call.Key != "" && key != call.Key {
|
|
continue
|
|
}
|
|
reached := false
|
|
switch level.Kind {
|
|
case LevelMesh:
|
|
reached = call.Module == "" || fallsBack[key]
|
|
case LevelNode:
|
|
reached = (call.Node == "" || level.Node == call.Node) && (call.Module == "" || fallsBack[key])
|
|
case LevelModule:
|
|
reached = (call.Node == "" || level.Node == call.Node) && (call.Module == "" || level.Module == call.Module)
|
|
}
|
|
if reached {
|
|
out.Set = append(out.Set, SetValue{Level: level, Key: key, Value: s.Values[k]})
|
|
}
|
|
}
|
|
if call.Module == "" {
|
|
out.Predefined = s.Predefined
|
|
}
|
|
out.Held = heldListed(s, call)
|
|
if len(out.Held) == 0 {
|
|
out.Held = nil
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// HistoryEntry is one change as the history keeps it.
|
|
type HistoryEntry struct {
|
|
Key string `json:"key"`
|
|
Change
|
|
}
|
|
|
|
// History is the changes the call narrows to, newest last, at most its limit (100 when it gives none).
|
|
func (c *Config) History(call Call) ([]HistoryEntry, error) {
|
|
entries, err := c.Store.Read(HistoryLog)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("the history cannot be read: %w", err)
|
|
}
|
|
limit := call.Limit
|
|
if limit <= 0 {
|
|
limit = 100
|
|
}
|
|
out := []HistoryEntry{}
|
|
for _, e := range entries {
|
|
var ch Change
|
|
if err := json.Unmarshal(e.Value, &ch); err != nil {
|
|
continue
|
|
}
|
|
if !reaches(call, e.Key, ch) {
|
|
continue
|
|
}
|
|
out = append(out, HistoryEntry{Key: e.Key, Change: ch})
|
|
}
|
|
if len(out) > limit {
|
|
out = out[len(out)-limit:]
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// reaches is whether a change concerns what the call narrows to: its level, or a value it moved.
|
|
func reaches(call Call, key string, ch Change) bool {
|
|
if call.Module == "" && call.Node == "" && call.Key == "" {
|
|
return true
|
|
}
|
|
if level, k, ok := parseValueKey(key); ok {
|
|
if (call.Key == "" || k == call.Key) && (call.Node == "" || level.Node == call.Node) &&
|
|
(call.Module == "" || level.Module == call.Module) {
|
|
return true
|
|
}
|
|
}
|
|
// A change at another level reaches the call through what it moved there: mesh config moving a module's
|
|
// value on the node named.
|
|
for _, m := range ch.Moved {
|
|
if (call.Module == "" || m.Module == call.Module) && (call.Node == "" || m.Node == call.Node) &&
|
|
(call.Key == "" || m.Key == call.Key || ch.Key == call.Key) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|