mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group feat/setting-defaults failed: a member failed
A key dropped silently ran a module without what its manifest says, and a key inside a block still failed the whole catalogue. Judge a key by what it is about, and narrow the listing to one machine.
59 lines
2.2 KiB
Go
59 lines
2.2 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"errors"
|
|
"regexp"
|
|
)
|
|
|
|
// A key this controller does not know, in a manifest (novox/hq ADR 0262).
|
|
//
|
|
// Registration refuses it, as it always has. A manifest the store already holds was registered by a newer
|
|
// controller, and is read by this one after a rollback: refusing it there failed the whole catalogue, and
|
|
// with it every plan and every send. Dropping the key silently would be worse — a module running without
|
|
// something its manifest says. So the manifest is read, the module is left out of every machine's
|
|
// declaration by name, and the controller raises a condition until it is updated.
|
|
|
|
// UnknownFieldError is a key a manifest has that this controller does not know, wherever it is: at the
|
|
// top of the manifest or inside a block (a state, an offer, a data item's backup, an own secret, a verb).
|
|
// Typed, because the blocks' decoders wrap the decoder's words in their own.
|
|
type UnknownFieldError struct {
|
|
Field string
|
|
err error
|
|
}
|
|
|
|
func (e *UnknownFieldError) Error() string { return e.err.Error() }
|
|
func (e *UnknownFieldError) Unwrap() error { return e.err }
|
|
|
|
// unknownFieldText is how the JSON decoder words a key its target does not have.
|
|
var unknownFieldText = regexp.MustCompile(`^json: unknown field "([^"]*)"$`)
|
|
|
|
// typedUnknown is err as an UnknownFieldError when it is the decoder refusing an unknown key, else err.
|
|
func typedUnknown(err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
if m := unknownFieldText.FindStringSubmatch(err.Error()); m != nil {
|
|
return &UnknownFieldError{Field: m[1], err: err}
|
|
}
|
|
return err
|
|
}
|
|
|
|
// asUnknownField is the unknown key err is about, at any depth, or nil.
|
|
func asUnknownField(err error) *UnknownFieldError {
|
|
var u *UnknownFieldError
|
|
if errors.As(typedUnknown(err), &u) {
|
|
return u
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UnknownFieldReason is why a module whose stored manifest has a key this controller does not know is
|
|
// left out of a machine's declaration, or "" when it has none.
|
|
func UnknownFieldReason(m Manifest) string {
|
|
if m.unknown == "" {
|
|
return ""
|
|
}
|
|
return m.Module + " uses a field this controller does not know (" + m.unknown + "); it is left out " +
|
|
"until the controller is updated (novox/hq ADR 0262)"
|
|
}
|