Leave out a module whose stored manifest has an unknown field, and raise it (hq ADR 0262 review)
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
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.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/catalogue"
|
||||
"github.com/novox/mesh-controller/internal/conditions"
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
)
|
||||
|
||||
// A stored manifest with a key this controller does not know (novox/hq ADR 0262). The module is left out
|
||||
// of every machine's declaration by name; this is the loud half: a condition per module until the
|
||||
// controller is updated, or the module is registered again in a shape this controller reads.
|
||||
|
||||
const (
|
||||
sourceUnknownFields = "the catalogue"
|
||||
kindUnknownField = "unknown-field"
|
||||
)
|
||||
|
||||
// unknownFieldObservations is one condition for each module of the catalogue whose stored manifest has
|
||||
// a key this controller does not know.
|
||||
func unknownFieldObservations(known map[string]catalogue.Manifest) []conditions.Observation {
|
||||
names := make([]string, 0, len(known))
|
||||
for name, m := range known {
|
||||
if m.UnknownField() != "" {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
sort.Strings(names)
|
||||
var out []conditions.Observation
|
||||
for _, name := range names {
|
||||
m := known[name]
|
||||
out = append(out, conditions.Observation{
|
||||
Scope: conditions.ScopeMesh, ID: name, Kind: kindUnknownField, Severity: conditions.Warning,
|
||||
Resolver: conditions.ResolverOperator, Source: sourceUnknownFields,
|
||||
Summary: catalogue.UnknownFieldReason(m),
|
||||
Said: m.UnknownField(),
|
||||
Headline: name + " is left out until the controller is updated",
|
||||
Explanation: name + " uses a field this controller does not know, so it is left out of every machine it is on, and nothing of it changes there until the controller is updated.",
|
||||
Needs: "update the controller, or register " + name + " again at a version this controller knows.",
|
||||
Resolved: "the controller reads " + name + " again",
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// raiseUnknownFields raises those conditions and clears the ones no longer true, on the controller's
|
||||
// tick. A catalogue that could not be read raises and clears nothing: "none" is not said for "could not
|
||||
// tell" (ADR 0227 rule 4).
|
||||
func raiseUnknownFields(ctx context.Context, inv *inventory.Inventory) []string {
|
||||
if conditionsFrom == nil {
|
||||
return nil
|
||||
}
|
||||
known, err := inv.Catalogue(ctx)
|
||||
if err != nil {
|
||||
return []string{fmt.Sprintf("the catalogue could not be read to say which modules it cannot read: %v", err)}
|
||||
}
|
||||
if err := conditionsFrom.Reconcile(ctx, sourceUnknownFields, unknownFieldObservations(known)); err != nil {
|
||||
return []string{fmt.Sprintf("the modules with a field this controller does not know could not be kept as conditions: %v", err)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user