Serve config as a seat verb, and say each value's source as one of the four (hq issue 630)
The listings named a node's own value "the node", which now could be node config; they say "<module> on <node>" for the module's own value instead.
This commit is contained in:
@@ -571,18 +571,14 @@ func settingsCommand(ctx context.Context, args []string) error {
|
||||
return err
|
||||
}
|
||||
m, ok := known[positionals[0]]
|
||||
if !ok || len(m.Settings) == 0 {
|
||||
if !ok || len(catalogue.PreferencesOf(m)) == 0 {
|
||||
return nil
|
||||
}
|
||||
var layers []catalogue.Layer
|
||||
if *node != "" {
|
||||
if mesh, has, err := inv.Layer(ctx, "", positionals[0]); err != nil {
|
||||
// Every source on the node: mesh config, node config, then the module's own (novox/hq issue 630).
|
||||
if layers, err = inv.SettingsFor(ctx, *node, positionals[0]); err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
layers = append(layers, catalogue.Layer{From: catalogue.MeshWideLayer, Values: mesh})
|
||||
}
|
||||
if has {
|
||||
layers = append(layers, catalogue.Layer{From: *node, Values: values})
|
||||
}
|
||||
} else if has {
|
||||
layers = append(layers, catalogue.Layer{From: catalogue.MeshWideLayer, Values: values})
|
||||
@@ -612,7 +608,7 @@ func settingsCommand(ctx context.Context, args []string) error {
|
||||
var listed []preferencesOf
|
||||
for _, e := range entries {
|
||||
m := e.Manifest
|
||||
if len(m.Settings) == 0 || (only != "" && m.Module != only) {
|
||||
if len(catalogue.PreferencesOf(m)) == 0 || (only != "" && m.Module != only) {
|
||||
continue
|
||||
}
|
||||
if *node != "" && !containsString(e.On, *node) {
|
||||
@@ -682,7 +678,11 @@ func describeEffective(module, where string, values []catalogue.SettingSource) s
|
||||
fmt.Fprintf(&b, "%s on %s, every value and where it comes from:\n", module, where)
|
||||
for _, v := range values {
|
||||
value, _ := json.Marshal(v.Value)
|
||||
fmt.Fprintf(&b, " %s = %s (%s", v.Key, value, v.From)
|
||||
from := v.From
|
||||
if v.From == where && where != "the whole mesh" {
|
||||
from = valueSource(module, where, v)
|
||||
}
|
||||
fmt.Fprintf(&b, " %s = %s (%s", v.Key, value, from)
|
||||
if v.HasDefault && !v.FromDefault {
|
||||
d, _ := json.Marshal(v.Default)
|
||||
fmt.Fprintf(&b, "; the default is %s", d)
|
||||
@@ -723,28 +723,27 @@ func describePreferences(modules []preferencesOf) string {
|
||||
on = "on " + strings.Join(p.Nodes, ", ")
|
||||
}
|
||||
fmt.Fprintf(&b, "%s (%s)\n", p.Manifest.Module, on)
|
||||
keys := make([]string, 0, len(p.Manifest.Settings))
|
||||
for k := range p.Manifest.Settings {
|
||||
declared := catalogue.PreferencesOf(p.Manifest)
|
||||
keys := make([]string, 0, len(declared))
|
||||
for k := range declared {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
d := p.Manifest.Settings[k]
|
||||
d := declared[k]
|
||||
def, _ := json.Marshal(d.Default)
|
||||
fmt.Fprintf(&b, " %s, default %s: %s\n", k, def, d.Why)
|
||||
falls := ""
|
||||
if d.Predefined != "" {
|
||||
falls = ", falls back to the predefined key " + d.Predefined
|
||||
}
|
||||
fmt.Fprintf(&b, " %s, default %s%s: %s\n", k, def, falls, d.Why)
|
||||
for _, n := range p.Nodes {
|
||||
for _, s := range p.On[n] {
|
||||
if s.Key != k {
|
||||
continue
|
||||
}
|
||||
v, _ := json.Marshal(s.Value)
|
||||
from := s.From
|
||||
if s.FromDefault {
|
||||
from = catalogue.DefaultLayer
|
||||
} else if s.From != catalogue.MeshWideLayer {
|
||||
from = "the node"
|
||||
}
|
||||
fmt.Fprintf(&b, " %s: %s (%s)\n", n, v, from)
|
||||
fmt.Fprintf(&b, " %s: %s (%s)\n", n, v, valueSource(p.Manifest.Module, n, s))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -752,6 +751,18 @@ func describePreferences(modules []preferencesOf) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// valueSource is where a value on a node comes from, as the four sources are said (novox/hq issue 630):
|
||||
// "default", "mesh config", "node config (<node>)", or "<module> on <node>" for the module's own value.
|
||||
func valueSource(module, node string, s catalogue.SettingSource) string {
|
||||
switch {
|
||||
case s.FromDefault:
|
||||
return catalogue.DefaultLayer
|
||||
case s.From == catalogue.MeshConfigLayer, s.From == catalogue.NodeConfigLayer(node), s.From == catalogue.MeshWideLayer:
|
||||
return s.From
|
||||
}
|
||||
return module + " on " + node
|
||||
}
|
||||
|
||||
// nodeFlag is ` --node <node>` for a machine's layer, nothing for the whole mesh's.
|
||||
func nodeFlag(node string) string {
|
||||
if node == "" {
|
||||
|
||||
@@ -88,7 +88,7 @@ func checkWait(module, machine string, w inventory.Wait, f operatorWaitFacts) er
|
||||
case w.Provision != "":
|
||||
return checkProvisionWait(module, machine, w, m, f)
|
||||
case w.Setting != "":
|
||||
if _, declared := m.Settings[w.Setting]; !declared {
|
||||
if !catalogue.DeclaresPreference(m, w.Setting) {
|
||||
return fmt.Errorf("says it waits for the setting %s, which %s does not declare", w.Setting, module)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -211,7 +211,7 @@ func (r *rootReader) executeServed(ctx context.Context, machine string) (bool, s
|
||||
}
|
||||
holders++
|
||||
var setting *any
|
||||
if _, declared := e.Manifest.Settings[loginShellVerb]; declared {
|
||||
if catalogue.DeclaresPreference(e.Manifest, loginShellVerb) {
|
||||
layers, err := r.settings(ctx, machine, e.Manifest.Module)
|
||||
if err != nil {
|
||||
served = true
|
||||
|
||||
@@ -542,6 +542,11 @@ const (
|
||||
|
||||
// proposeCommand is `settings propose`, on this controller's stores and bus.
|
||||
func proposeCommand(ctx context.Context, module, node, valuesArg string, clear, replace bool) error {
|
||||
if node == "" && !clear {
|
||||
// There is no module layer for the whole mesh (novox/hq issue 630); clearing one left over still works.
|
||||
return fmt.Errorf("%s: there is no module layer for the whole mesh — an assignment is one module on one "+
|
||||
"node (novox/hq issue 630). Propose it for one node with --node. Nothing was proposed", module)
|
||||
}
|
||||
var values map[string]any
|
||||
if !clear {
|
||||
if valuesArg == "" {
|
||||
|
||||
@@ -881,6 +881,48 @@ func (a *verbArguments) commandLine() ([]string, error) {
|
||||
argv = append(argv, "--adopted")
|
||||
}
|
||||
return argv, nil
|
||||
case "config":
|
||||
// Config values from four sources (novox/hq issue 630): mesh config and node config for a predefined
|
||||
// key, and a module's own value on one node. A listing without key; a set or clear says why.
|
||||
key := str("key")
|
||||
if str("module") != "" && str("node") == "" && (key != "" || on("clear")) {
|
||||
return nil, errors.New("config: there is no module layer for the whole mesh — an assignment is one module " +
|
||||
"on one node (novox/hq issue 630); give node, or leave module out to set mesh config for a predefined key")
|
||||
}
|
||||
place := func(argv []string) []string {
|
||||
if n := str("node"); n != "" {
|
||||
argv = append(argv, "--node", n)
|
||||
}
|
||||
if m := str("module"); m != "" {
|
||||
argv = append(argv, "--module", m)
|
||||
}
|
||||
return argv
|
||||
}
|
||||
switch {
|
||||
case key == "":
|
||||
if str("value") != "" || on("clear") || on("history") || str("why") != "" {
|
||||
return nil, errors.New("config: a set, a clear or a history names its key")
|
||||
}
|
||||
return place([]string{"config", "list"}), nil
|
||||
case on("history"):
|
||||
if str("value") != "" || on("clear") || str("module") != "" || str("why") != "" {
|
||||
return nil, errors.New("config: history reads a key's mesh or node config, and takes only node")
|
||||
}
|
||||
return place([]string{"config", "history", key}), nil
|
||||
case on("clear") && str("value") != "":
|
||||
return nil, errors.New("config: a value or clear, not both")
|
||||
case on("clear"):
|
||||
if err := need("why"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(place([]string{"config", "clear", key}), "--why", str("why")), nil
|
||||
case str("value") != "":
|
||||
if err := need("why"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(place([]string{"config", "set", key, str("value")}), "--why", str("why")), nil
|
||||
}
|
||||
return nil, errors.New("config: with key, give value, clear or history")
|
||||
case "settings":
|
||||
// Every module's preferences, their defaults and each machine's value (novox/hq ADR 0262):
|
||||
// the one interface for them, so no module builds a settings tool of its own. Asked for by
|
||||
@@ -1614,6 +1656,7 @@ var commandReadForms = map[string]func(rest []string) bool{
|
||||
"node": func(r []string) bool { return subIn(r, "list", "show") },
|
||||
"module": func(r []string) bool { return subIn(r, "list") },
|
||||
"settings": func(r []string) bool { return subIn(r, "show", "preferences", "proposals") },
|
||||
"config": func(r []string) bool { return flagsOnly(r) || subIn(r, "list", "history") },
|
||||
"retire": func(r []string) bool { return subIn(r, "list") },
|
||||
"cleanup": func(r []string) bool { return subIn(r, "list") },
|
||||
"delivery": func(r []string) bool { return subIn(r, "plan", "walks") },
|
||||
|
||||
Reference in New Issue
Block a user