Merge b7q/registry into the registry milestone's mesh-delivery: provisions, overlay and findings onto their clients (issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -37,13 +37,12 @@ import (
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
mmac "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/announce"
|
||||
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
"mesh-delivery-assigner/internal/judge"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
||||
@@ -526,15 +525,15 @@ func TestWantsAreWrittenAndNoDifferenceIs(t *testing.T) {
|
||||
appDigest := b.manifest(t, "app", `{"module":"app","version":"1","requires":["database"]}`)
|
||||
toolDigest := b.manifest(t, "tool", `{"module":"tool","version":"1"}`)
|
||||
asked := func(state, why string) {
|
||||
raw, err := provisions.Encode(provisions.Provision{V: provisions.Version, Provision: "database", Consumer: provisions.End{Module: "app", Node: "ace"},
|
||||
Provider: provisions.End{Module: "db", Node: "ace"}, State: state, Why: why, At: time.Now()})
|
||||
raw, err := meshprovisionerclient.Encode(meshprovisionerclient.Provision{V: meshprovisionerclient.Version, Provision: "database", Consumer: meshprovisionerclient.End{Module: "app", Node: "ace"},
|
||||
Provider: meshprovisionerclient.End{Module: "db", Node: "ace"}, State: state, Why: why, At: time.Now()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b.putJSON(t, provisions.ProvisionsBucket, "ace.app.database", raw)
|
||||
b.putJSON(t, meshprovisionerclient.ProvisionsBucket, "ace.app.database", raw)
|
||||
}
|
||||
// The provisioner keys it from the manifests, as soon as they are known and whether the provider is placed yet or not.
|
||||
asked(provisions.Asked, "the provider's build is not done")
|
||||
asked(meshprovisionerclient.Asked, "the provider's build is not done")
|
||||
fpOf := func(c byte) string { return meshcatalogclient.SourcePrefix2 + strings.Repeat(string(c), 64) }
|
||||
toolOld := fpOf('1')
|
||||
for module, row := range map[string]struct {
|
||||
@@ -565,7 +564,7 @@ func TestWantsAreWrittenAndNoDifferenceIs(t *testing.T) {
|
||||
if e, err := b.buckets[buckets.Wants].Get(b.ctx, "want.ace.app"); err == nil {
|
||||
t.Errorf("app was wanted while its provision was asked: %s", e.Value())
|
||||
}
|
||||
asked(provisions.Provided, "")
|
||||
asked(meshprovisionerclient.Provided, "")
|
||||
if w := b.wantNow(t, "ace", "app", "the consumer's want once its provision is provided", func(w mwc.Want) bool { return w.Fp == fpOf('3') }); w.Fp != fpOf('3') {
|
||||
t.Errorf("app's want = %+v", w)
|
||||
}
|
||||
@@ -729,7 +728,7 @@ func (b *bed) conditionsSaid(t *testing.T) map[string]oc.Condition {
|
||||
c := out[e.Key()]
|
||||
c.Key, c.State = e.Key(), occ.StateCleared
|
||||
if e.Operation() == jetstream.KeyValuePut {
|
||||
f, err := health.DecodeFinding(e.Value())
|
||||
f, err := meshconditionsclient.DecodeFinding(e.Value())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@ import (
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/announce"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/enginereads"
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
@@ -64,7 +64,7 @@ var readBuckets = []string{
|
||||
buckets.Builds,
|
||||
buckets.Presence,
|
||||
buckets.Have,
|
||||
provisions.ProvisionsBucket,
|
||||
meshprovisionerclient.ProvisionsBucket,
|
||||
buckets.Source,
|
||||
buckets.Merges,
|
||||
}
|
||||
@@ -106,7 +106,7 @@ var keptStates = []announce.State{
|
||||
{Name: "differences", Readable: true},
|
||||
{Name: "puts", Readable: true},
|
||||
{Name: "wants", Readable: true},
|
||||
{Name: health.FindingsState, Readable: true},
|
||||
{Name: mcc.FindingsState, Readable: true},
|
||||
{Name: buckets.PoliciesState, Readable: true},
|
||||
{Name: mma.StateSeatHolders, Readable: true},
|
||||
{Name: views.MarksState, Readable: true}, // what its views family said each state up to (views.go)
|
||||
@@ -140,7 +140,7 @@ func open(ctx context.Context, js process.BucketOpener, logf func(string, ...any
|
||||
logf("the bucket %s cannot be opened (%v): it is bound once the bus says it was made", name, err)
|
||||
continue
|
||||
}
|
||||
if name == provisions.ProvisionsBucket && err != nil {
|
||||
if name == meshprovisionerclient.ProvisionsBucket && err != nil {
|
||||
// The seat mesh-provisioner's state, with its own delivery (ADR 0570 §4): bound once the bus says it was made;
|
||||
// until then no want waits for a provision, as before.
|
||||
logf("the bucket %s cannot be opened (%v): it is bound once the bus says it was made", name, err)
|
||||
@@ -187,7 +187,7 @@ func open(ctx context.Context, js process.BucketOpener, logf func(string, ...any
|
||||
// states and those new with a delivery of their own, bound once made, and the two that choose the grants' source.
|
||||
func startsWithout(name string) bool {
|
||||
switch name {
|
||||
case plc.SeatHoldersBucket, provisions.ProvisionsBucket, assign.PoliciesBucket, assign.FindingsBucket,
|
||||
case plc.SeatHoldersBucket, meshprovisionerclient.ProvisionsBucket, assign.PoliciesBucket, assign.FindingsBucket,
|
||||
buckets.Puts, buckets.Source, buckets.Merges, engineReadsBucket:
|
||||
return true
|
||||
}
|
||||
@@ -282,7 +282,7 @@ var watched = []string{
|
||||
buckets.Differences,
|
||||
buckets.Wants,
|
||||
assign.PoliciesBucket,
|
||||
provisions.ProvisionsBucket,
|
||||
meshprovisionerclient.ProvisionsBucket,
|
||||
plc.SeatHoldersBucket,
|
||||
buckets.Source,
|
||||
buckets.Merges,
|
||||
@@ -428,7 +428,7 @@ func follow(ctx context.Context, js jetstream.JetStream, nc process.Subscriber,
|
||||
}
|
||||
}
|
||||
// And the two that choose where grants are read from, with the same delivery as the grants part that writes one.
|
||||
for _, name := range []string{buckets.Grants, assign.PoliciesBucket, provisions.ProvisionsBucket, plc.SeatHoldersBucket} {
|
||||
for _, name := range []string{buckets.Grants, assign.PoliciesBucket, meshprovisionerclient.ProvisionsBucket, plc.SeatHoldersBucket} {
|
||||
if kvs[name] == nil && js != nil {
|
||||
name := name
|
||||
process.AwaitBucket(ctx, js, nc, name, "until then the bucket is not read",
|
||||
|
||||
@@ -19,8 +19,8 @@ import (
|
||||
"time"
|
||||
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/enginereads"
|
||||
|
||||
@@ -940,37 +940,37 @@ func chosenOf(chosen map[string]catalogue.PersonPolicy, module string) *catalogu
|
||||
// mesh-provisioner's state; nil while the state is not read (the seat not delivered yet), so no want waits on it. A failed
|
||||
// provision is also said as the assigner's finding `provider.<key>.provision-failed` (a waiting one is the watchman's
|
||||
// needs-operator), deleted once it is no longer failed.
|
||||
func (p *passer) provisionsOf() func(module string) func(node string) map[string]provisions.Provision {
|
||||
if p.kvs[provisions.ProvisionsBucket] == nil {
|
||||
return func(string) func(string) map[string]provisions.Provision { return nil }
|
||||
func (p *passer) provisionsOf() func(module string) func(node string) map[string]meshprovisionerclient.Provision {
|
||||
if p.kvs[meshprovisionerclient.ProvisionsBucket] == nil {
|
||||
return func(string) func(string) map[string]meshprovisionerclient.Provision { return nil }
|
||||
}
|
||||
by := map[string]map[string]map[string]provisions.Provision{} // module, node, key
|
||||
failed := map[string]provisions.Provision{}
|
||||
for key, raw := range p.w.read(provisions.ProvisionsBucket) {
|
||||
pr, err := provisions.Decode(raw)
|
||||
by := map[string]map[string]map[string]meshprovisionerclient.Provision{} // module, node, key
|
||||
failed := map[string]meshprovisionerclient.Provision{}
|
||||
for key, raw := range p.w.read(meshprovisionerclient.ProvisionsBucket) {
|
||||
pr, err := meshprovisionerclient.Decode(raw)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
node, module := pr.Consumer.Node, pr.Consumer.Module
|
||||
if by[module] == nil {
|
||||
by[module] = map[string]map[string]provisions.Provision{}
|
||||
by[module] = map[string]map[string]meshprovisionerclient.Provision{}
|
||||
}
|
||||
if by[module][node] == nil {
|
||||
by[module][node] = map[string]provisions.Provision{}
|
||||
by[module][node] = map[string]meshprovisionerclient.Provision{}
|
||||
}
|
||||
by[module][node][key] = pr
|
||||
if pr.State == provisions.Failed {
|
||||
if pr.State == meshprovisionerclient.Failed {
|
||||
failed[key] = pr
|
||||
}
|
||||
}
|
||||
p.provisionFindings(failed)
|
||||
return func(module string) func(string) map[string]provisions.Provision {
|
||||
return func(node string) map[string]provisions.Provision { return by[module][node] }
|
||||
return func(module string) func(string) map[string]meshprovisionerclient.Provision {
|
||||
return func(node string) map[string]meshprovisionerclient.Provision { return by[module][node] }
|
||||
}
|
||||
}
|
||||
|
||||
// provisionFindings writes the finding of each failed provision and deletes the ones no longer failed.
|
||||
func (p *passer) provisionFindings(failed map[string]provisions.Provision) {
|
||||
func (p *passer) provisionFindings(failed map[string]meshprovisionerclient.Provision) {
|
||||
if p.findings.Put == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
mmac "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
"mesh-delivery-assigner/internal/assign"
|
||||
@@ -325,23 +325,23 @@ func TestTheSeatsVerbs(t *testing.T) {
|
||||
})
|
||||
t.Run("1954/D1: a failed provision is the assigner's finding until it is provided", func(t *testing.T) {
|
||||
findings := map[string][]byte{}
|
||||
p := &passer{w: newWorld(), logf: func(string, ...any) {}, kvs: kvSet{provisions.ProvisionsBucket: nil}, findings: assign.Findings{
|
||||
p := &passer{w: newWorld(), logf: func(string, ...any) {}, kvs: kvSet{meshprovisionerclient.ProvisionsBucket: nil}, findings: assign.Findings{
|
||||
Put: func(k string, v []byte) error { findings[k] = v; return nil },
|
||||
Delete: func(k string) error { delete(findings, k); return nil }}}
|
||||
failed, _ := provisions.Encode(provisions.Provision{Provision: "db", Consumer: provisions.End{Module: "photos", Node: "ace"},
|
||||
Provider: provisions.End{Module: "postgres", Node: "novox"}, State: provisions.Failed, Why: "the role exists already"})
|
||||
p.w.putEntry(provisions.ProvisionsBucket, "ace.photos.db", failed, 1, time.Now())
|
||||
p.kvs[provisions.ProvisionsBucket] = &memKV{}
|
||||
failed, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "db", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"},
|
||||
Provider: meshprovisionerclient.End{Module: "postgres", Node: "novox"}, State: meshprovisionerclient.Failed, Why: "the role exists already"})
|
||||
p.w.putEntry(meshprovisionerclient.ProvisionsBucket, "ace.photos.db", failed, 1, time.Now())
|
||||
p.kvs[meshprovisionerclient.ProvisionsBucket] = &memKV{}
|
||||
of := p.provisionsOf()
|
||||
if got := of("photos")("ace"); got["ace.photos.db"].State != provisions.Failed {
|
||||
if got := of("photos")("ace"); got["ace.photos.db"].State != meshprovisionerclient.Failed {
|
||||
t.Fatalf("provisions = %+v", got)
|
||||
}
|
||||
if _, ok := findings[assign.ProvisionFailedKey("ace.photos.db")]; !ok || len(findings) != 1 {
|
||||
t.Fatalf("findings = %v", findings)
|
||||
}
|
||||
provided, _ := provisions.Encode(provisions.Provision{Provision: "db", Consumer: provisions.End{Module: "photos", Node: "ace"},
|
||||
Provider: provisions.End{Module: "postgres", Node: "novox"}, State: provisions.Provided})
|
||||
p.w.putEntry(provisions.ProvisionsBucket, "ace.photos.db", provided, 2, time.Now())
|
||||
provided, _ := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "db", Consumer: meshprovisionerclient.End{Module: "photos", Node: "ace"},
|
||||
Provider: meshprovisionerclient.End{Module: "postgres", Node: "novox"}, State: meshprovisionerclient.Provided})
|
||||
p.w.putEntry(meshprovisionerclient.ProvisionsBucket, "ace.photos.db", provided, 2, time.Now())
|
||||
p.provisionsOf()
|
||||
if len(findings) != 0 {
|
||||
t.Errorf("findings after provided = %v", findings)
|
||||
@@ -458,7 +458,7 @@ func wantsVerbs(t *testing.T) {
|
||||
if n := watches[manifestsState+" by key"]; n == 0 || n > len(st[manifestsState].values) {
|
||||
t.Errorf("the manifests were read by key %d times, want each once", n)
|
||||
}
|
||||
for _, state := range []string{modulesState, haveState, health.FindingsState} {
|
||||
for _, state := range []string{modulesState, haveState, mcc.FindingsState} {
|
||||
if watches[state] != 1 {
|
||||
t.Errorf("%s was watched %d times, want once", state, watches[state])
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
|
||||
mma "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
@@ -46,7 +46,7 @@ var readTools = []viewedTool{
|
||||
{"assigner_read_placement", mma.StatePlacement, "where each module is placed, by module."},
|
||||
{"assigner_read_seat_holders", mma.StateSeatHolders, "who holds which seat on which node."},
|
||||
{"assigner_read_wants", "wants", "what each node should run: want.<node>.<module>."},
|
||||
{"assigner_read_findings", health.FindingsState, "the assigner's findings, which the condition keeper raises and clears."},
|
||||
{"assigner_read_findings", mcc.FindingsState, "the assigner's findings, which the condition keeper raises and clears."},
|
||||
{"assigner_read_asks", "asks", "the asks the assigner put to a person, and their answers."},
|
||||
{"assigner_read_differences", "differences", "every difference between a want and what a node runs."},
|
||||
}
|
||||
@@ -56,7 +56,7 @@ var viewedStates = map[string]string{
|
||||
mma.StatePlacement: plc.PlacementBucket,
|
||||
mma.StateSeatHolders: plc.SeatHoldersBucket,
|
||||
"wants": buckets.Wants,
|
||||
health.FindingsState: assign.FindingsBucket,
|
||||
mcc.FindingsState: assign.FindingsBucket,
|
||||
"asks": buckets.Asks,
|
||||
"differences": buckets.Differences,
|
||||
}
|
||||
@@ -91,7 +91,7 @@ func startViews(ctx context.Context, js jetstream.JetStream, nc process.Subscrib
|
||||
}
|
||||
process.AwaitBucket(ctx, js, nc, marksBucket, "no change is said on the views family, so every reader waits on its first view", logf).Ready(func(mk jetstream.KeyValue) {
|
||||
em := viewsEmitter(js, account, mk, findings, tooLarge, logf)
|
||||
for _, state := range []string{"asks", "differences", health.FindingsState, mma.StatePlacement, mma.StateSeatHolders, "wants"} {
|
||||
for _, state := range []string{"asks", "differences", mcc.FindingsState, mma.StatePlacement, mma.StateSeatHolders, "wants"} {
|
||||
state := state
|
||||
start := func(kv jetstream.KeyValue) {
|
||||
if err := em.Start(ctx, state, kv, errs); err != nil {
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
|
||||
"mesh-delivery-assigner/internal/assign"
|
||||
)
|
||||
@@ -171,7 +171,7 @@ func (s *wantsTools) doUpgrade(args map[string]any, by string) (any, error) {
|
||||
out["published"] = published(values)
|
||||
}
|
||||
// The assigner's findings, its said conditions as the condition keeper reads them (§15).
|
||||
if found, err := s.values(health.FindingsState); err != nil {
|
||||
if found, err := s.values(mcc.FindingsState); err != nil {
|
||||
out["findings-unread"] = err.Error()
|
||||
} else {
|
||||
keys := []string{}
|
||||
|
||||
@@ -3,6 +3,7 @@ module mesh-delivery-assigner
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient v0.0.0
|
||||
git.novox.be/novox/mesh-contracts/placement/go/seats/meshwants v0.0.0-00010101000000-000000000000
|
||||
@@ -43,6 +44,7 @@ replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds =>
|
||||
replace git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate => ../mesh-grants/grantsstate
|
||||
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshwatchdogs v0.0.0-00010101000000-000000000000
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient v0.0.0-00010101000000-000000000000
|
||||
require git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient v0.0.0-00010101000000-000000000000
|
||||
|
||||
@@ -14,9 +14,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
mcseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
|
||||
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
)
|
||||
|
||||
// 1297/B9 (the assigner's half): the ask about a held fingerprint is a valid ask of the router and of mesh-sdk's layout at
|
||||
@@ -149,9 +150,9 @@ func saidConditionsAreFindings(t *testing.T) {
|
||||
{SeatWaitsCondition([]string{"placement"}), SeatWaitsCondition(nil), "module.mesh-delivery-assigner.seat-states"},
|
||||
{BackupCondition("ace", "mail", fNew, "disk full", true), BackupCondition("ace", "mail", fNew, "", false), "module.ace.mail." + strings.TrimPrefix(fNew, meshcatalogclient.SourcePrefix2) + ".backup"},
|
||||
} {
|
||||
puts, deletes, said := map[string]health.Finding{}, []string{}, 0
|
||||
puts, deletes, said := map[string]mcseat.FindingsByKeyValue{}, []string{}, 0
|
||||
f := Findings{Put: func(k string, v []byte) error {
|
||||
got, err := health.DecodeFinding(v)
|
||||
got, err := mcc.DecodeFinding(v)
|
||||
puts[k] = got
|
||||
return err
|
||||
}, Delete: func(k string) error { deletes = append(deletes, k); return nil }, Now: func() time.Time { return at }}
|
||||
@@ -160,7 +161,7 @@ func saidConditionsAreFindings(t *testing.T) {
|
||||
t.Fatalf("%s: %v", c.key, err)
|
||||
}
|
||||
got, ok := puts[c.key]
|
||||
if !ok || got.Severity != health.Severity(c.raised.Severity) || got.Headline != c.raised.Headline || got.Observer != mmac.Module ||
|
||||
if !ok || got.Severity != c.raised.Severity || got.Headline != c.raised.Headline || got.Observer != mmac.Module ||
|
||||
got.Subject.Machine != c.raised.Subject.Machine || said != 0 {
|
||||
t.Fatalf("%s: finding %+v (written %v), said %d", c.key, got, puts, said)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
mcseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
|
||||
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
)
|
||||
|
||||
// The assigner's said conditions become findings (novox/hq ADR 0564 §2, issue 1952 WM6, note 16): every condition it says
|
||||
@@ -20,7 +21,7 @@ import (
|
||||
// assigner no longer says it straight (never both).
|
||||
|
||||
// FindingsBucket is the assigner's findings.
|
||||
var FindingsBucket = health.FindingsBucket(mmac.Module)
|
||||
var FindingsBucket = mcc.FindingsBucket(mmac.Module)
|
||||
|
||||
// FindingOf is a said condition as a finding: its key `<scope>.<id>.<kind>`, from the condition's own key
|
||||
// `mesh-delivery-assigner.<kind>.<id…>` (the subject's id when the key names none), its words unchanged. raised is false for
|
||||
@@ -36,9 +37,9 @@ func FindingOf(c oc.Condition, at time.Time) (key string, value []byte, raised b
|
||||
}
|
||||
scope := c.Subject.Scope
|
||||
if scope == "" {
|
||||
scope = health.ScopeModule
|
||||
scope = mcc.ScopeModule
|
||||
}
|
||||
key = health.FindingKey(scope, id, kind)
|
||||
key = mcc.Key(scope, id, kind)
|
||||
if c.State == occ.StateCleared {
|
||||
return key, nil, false, nil
|
||||
}
|
||||
@@ -49,14 +50,14 @@ func FindingOf(c oc.Condition, at time.Time) (key string, value []byte, raised b
|
||||
if summary == "" {
|
||||
summary = c.Headline
|
||||
}
|
||||
var actions []health.Action
|
||||
var actions []mcseat.Action
|
||||
for _, a := range c.Actions {
|
||||
actions = append(actions, health.Action{Label: a.Label, Verb: a.Verb, Machine: a.Machine, Arguments: a.Arguments, Level: string(a.Level)})
|
||||
actions = append(actions, mcseat.Action{Label: a.Label, Verb: a.Verb, Machine: a.Machine, Arguments: a.Arguments, Level: string(a.Level)})
|
||||
}
|
||||
value, err = health.EncodeFinding(health.Finding{Key: key, Kind: kind, Subject: health.Subject{Scope: scope, ID: id, Machine: c.Subject.Machine},
|
||||
Severity: health.Severity(c.Severity), Summary: summary, Headline: c.Headline, Explanation: c.Explanation, Resolved: c.Resolved,
|
||||
Needs: c.Needs, Actions: actions, Evidence: []health.Evidence{{At: at.UTC(), Said: summary}}, Source: "assigner." + kind,
|
||||
Observer: mmac.Module, At: at.UTC()})
|
||||
f := mcc.Observation{Scope: scope, ID: id, Kind: kind, Machine: c.Subject.Machine, Severity: string(c.Severity), Summary: summary,
|
||||
Headline: c.Headline, Explanation: c.Explanation, Resolved: c.Resolved, Needs: c.Needs, Actions: actions,
|
||||
Source: "assigner." + kind}.Finding(mmac.Module, "", at)
|
||||
value, err = mcc.EncodeFinding(f)
|
||||
return key, value, true, err
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
)
|
||||
|
||||
// A person's upgrade policy is the assigner's (novox/hq ADR 0565 §7, §8, issue 1953 D4, D5): kept in its state `policies`, one
|
||||
@@ -61,19 +61,22 @@ const KindProvisionFailed = "provision-failed"
|
||||
|
||||
// ProvisionFailedKey is a failed provision's finding's key, `provider.<node>.<consumer>.<provision>[.<local>].provision-failed`.
|
||||
func ProvisionFailedKey(key string) string {
|
||||
return health.FindingKey(health.ScopeProvider, key, KindProvisionFailed)
|
||||
return mcc.Key(mcc.ScopeProvider, key, KindProvisionFailed)
|
||||
}
|
||||
|
||||
// ProvisionFailedFinding is the finding of a failed provision, naming its consumer, its provider and why.
|
||||
func ProvisionFailedFinding(key string, p provisions.Provision, at time.Time) ([]byte, error) {
|
||||
func ProvisionFailedFinding(key string, p meshprovisionerclient.Provision, at time.Time) ([]byte, error) {
|
||||
summary := fmt.Sprintf("%s for %s on %s failed at %s on %s: %s, so %s is not moved there until it is provided", p.Provision,
|
||||
p.Consumer.Module, p.Consumer.Node, p.Provider.Module, p.Provider.Node, p.Why, p.Consumer.Module)
|
||||
return health.EncodeFinding(health.Finding{Key: ProvisionFailedKey(key), Kind: KindProvisionFailed,
|
||||
Subject: health.Subject{Scope: health.ScopeProvider, ID: key, Machine: p.Consumer.Node, Also: also(p.Provider.Node, p.Consumer.Node)},
|
||||
Severity: health.Warning, Summary: summary, Headline: clipHeadline(p.Consumer.Module + " waits for a provision that failed"),
|
||||
return encode(mcc.Observation{Scope: mcc.ScopeProvider, ID: key, Kind: KindProvisionFailed, Machine: p.Consumer.Node, Also: also(p.Provider.Node, p.Consumer.Node),
|
||||
Summary: summary, Said: p.Why, Headline: clipHeadline(p.Consumer.Module + " waits for a provision that failed"),
|
||||
Explanation: occ.NothingToDo + " " + summary + ". It clears once the provider provides it.",
|
||||
Resolved: p.Provision + " for " + p.Consumer.Module + " is provided", Evidence: []health.Evidence{{At: at.UTC(), Said: p.Why}},
|
||||
Source: "assigner." + KindProvisionFailed, Observer: mmac.Module, At: at.UTC()})
|
||||
Resolved: p.Provision + " for " + p.Consumer.Module + " is provided", Source: "assigner." + KindProvisionFailed}, at)
|
||||
}
|
||||
|
||||
// encode is the observation as the assigner's finding at at, in the seat's layout.
|
||||
func encode(o mcc.Observation, at time.Time) ([]byte, error) {
|
||||
return mcc.EncodeFinding(o.Finding(mmac.Module, "", at))
|
||||
}
|
||||
|
||||
func also(provider, consumer string) []string {
|
||||
@@ -88,7 +91,7 @@ const KindProvisionMissing = "provision-missing"
|
||||
|
||||
// ProvisionMissingKey is its key, `provider.<node>.<module>.<provision>.provision-missing`.
|
||||
func ProvisionMissingKey(key string) string {
|
||||
return health.FindingKey(health.ScopeProvider, key, KindProvisionMissing)
|
||||
return mcc.Key(mcc.ScopeProvider, key, KindProvisionMissing)
|
||||
}
|
||||
|
||||
// ProvisionMissingFinding is the finding of a required provision with no key past bound (key `<node>.<module>.<provision>`).
|
||||
@@ -100,12 +103,10 @@ func ProvisionMissingFinding(key string, bound time.Duration, at time.Time) ([]b
|
||||
node, module, provision := parts[0], parts[1], parts[2]
|
||||
summary := fmt.Sprintf("%s on %s requires %s and mesh-provisioner has composed no key for it in %s, so %s is not moved there: "+
|
||||
"no provider of it may be placed", module, node, provision, bound, module)
|
||||
return health.EncodeFinding(health.Finding{Key: ProvisionMissingKey(key), Kind: KindProvisionMissing,
|
||||
Subject: health.Subject{Scope: health.ScopeProvider, ID: key, Machine: node},
|
||||
Severity: health.Warning, Summary: summary, Headline: clipHeadline(module + " on " + node + " lacks " + provision),
|
||||
return encode(mcc.Observation{Scope: mcc.ScopeProvider, ID: key, Kind: KindProvisionMissing, Machine: node,
|
||||
Summary: summary, Headline: clipHeadline(module + " on " + node + " lacks " + provision),
|
||||
Explanation: occ.NothingToDo + " " + summary + ". It clears once the provision has its key.",
|
||||
Resolved: provision + " for " + module + " on " + node + " has its key", Evidence: []health.Evidence{{At: at.UTC(), Said: summary}},
|
||||
Source: "assigner." + KindProvisionMissing, Observer: mmac.Module, At: at.UTC()})
|
||||
Resolved: provision + " for " + module + " on " + node + " has its key", Source: "assigner." + KindProvisionMissing}, at)
|
||||
}
|
||||
|
||||
// KindUnplaced is, from the lease write, a node that runs but no placement names (ADR 0571 §6).
|
||||
@@ -113,19 +114,17 @@ const KindUnplaced = "unplaced"
|
||||
|
||||
// UnplacedKey is its finding's key, `machine.<node>.unplaced`.
|
||||
func UnplacedKey(node string) string {
|
||||
return health.FindingKey(health.ScopeMachine, node, KindUnplaced)
|
||||
return mcc.Key(mcc.ScopeMachine, node, KindUnplaced)
|
||||
}
|
||||
|
||||
// UnplacedFinding is the finding of a node no placement names since the lease write.
|
||||
func UnplacedFinding(node string, at time.Time) ([]byte, error) {
|
||||
summary := fmt.Sprintf("%s runs, but no placement names it: since the controller handed its lease away nothing composes it, "+
|
||||
"so the assigner writes it no want", node)
|
||||
return health.EncodeFinding(health.Finding{Key: UnplacedKey(node), Kind: KindUnplaced,
|
||||
Subject: health.Subject{Scope: health.ScopeMachine, ID: node, Machine: node}, Severity: health.Warning, Summary: summary,
|
||||
return encode(mcc.Observation{Scope: mcc.ScopeMachine, ID: node, Kind: KindUnplaced, Machine: node, Summary: summary,
|
||||
Headline: clipHeadline(node + " has no placement"), Needs: "place it with mesh-placement.propose.",
|
||||
Explanation: occ.NeedsYou + "place it with mesh-placement.propose. " + summary + ".",
|
||||
Resolved: node + " is placed", Evidence: []health.Evidence{{At: at.UTC(), Said: summary}},
|
||||
Source: "assigner." + KindUnplaced, Observer: mmac.Module, At: at.UTC()})
|
||||
Resolved: node + " is placed", Source: "assigner." + KindUnplaced}, at)
|
||||
}
|
||||
|
||||
func clipHeadline(s string) string {
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/forms"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/graph"
|
||||
@@ -40,7 +40,7 @@ type Module struct {
|
||||
Manifest catalogue.Manifest
|
||||
// Provisions is the seat mesh-provisioner's provisions this module consumes on a node, by key (ADR 0570 §4): the want
|
||||
// waits until each is provided. Nil: the seat's state is not read (not delivered yet), and nothing waits on it.
|
||||
Provisions func(node string) map[string]provisions.Provision
|
||||
Provisions func(node string) map[string]meshprovisionerclient.Provision
|
||||
// Answering is the manifests of the modules placed somewhere that provide a provision: what catalogue.Awaited
|
||||
// judges a want's provisions by (issue 774). Nil: none known, and no key is waited for that is not there.
|
||||
Answering func(provision string) []catalogue.Manifest
|
||||
@@ -242,7 +242,7 @@ func (m Module) provisionWaiting(node string) (string, bool) {
|
||||
}
|
||||
}
|
||||
for _, key := range slices.Sorted(maps.Keys(keyed)) {
|
||||
if p := keyed[key]; p.State != provisions.Provided && slices.Contains(needed, p.Provision) {
|
||||
if p := keyed[key]; p.State != meshprovisionerclient.Provided && slices.Contains(needed, p.Provision) {
|
||||
words := fmt.Sprintf("the provision %s of %s on %s is %s, not provided", key, m.Name, node, p.State)
|
||||
if p.Why != "" {
|
||||
words += ": " + p.Why
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/graph"
|
||||
)
|
||||
@@ -81,8 +81,8 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) {
|
||||
},
|
||||
// 1954/D1 (ADR 0570 §4): a provision of the module on that node still asked holds its want.
|
||||
mwc.RuleProvisions: func(m *Module, _ *Nodes) {
|
||||
m.Provisions = func(node string) map[string]provisions.Provision {
|
||||
return map[string]provisions.Provision{node + ".mail.database": {Provision: "database", State: provisions.Asked}, node + ".mail.oidc": {Provision: "oidc", State: provisions.Provided}}
|
||||
m.Provisions = func(node string) map[string]meshprovisionerclient.Provision {
|
||||
return map[string]meshprovisionerclient.Provision{node + ".mail.database": {Provision: "database", State: meshprovisionerclient.Asked}, node + ".mail.oidc": {Provision: "oidc", State: meshprovisionerclient.Provided}}
|
||||
}
|
||||
},
|
||||
} {
|
||||
@@ -103,9 +103,9 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// 1954/D1: every provision provided, the want moves; with the seat's state not read, nothing waits on it.
|
||||
for _, all := range []func(string) map[string]provisions.Provision{
|
||||
func(node string) map[string]provisions.Provision {
|
||||
return map[string]provisions.Provision{node + ".mail.database": {Provision: "database", State: provisions.Provided}}
|
||||
for _, all := range []func(string) map[string]meshprovisionerclient.Provision{
|
||||
func(node string) map[string]meshprovisionerclient.Provision {
|
||||
return map[string]meshprovisionerclient.Provision{node + ".mail.database": {Provision: "database", State: meshprovisionerclient.Provided}}
|
||||
}, nil} {
|
||||
m, n := ready()
|
||||
m.Provisions = all
|
||||
@@ -216,13 +216,13 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) {
|
||||
name string
|
||||
state, older string
|
||||
moves bool
|
||||
}{{"the replaced edge provided, the older edge retiring", provisions.Provided, provisions.Retiring, true},
|
||||
{"the replaced edge provided, the older edge asked", provisions.Provided, provisions.Asked, true},
|
||||
{"the replaced edge asked, the older edge retiring", provisions.Asked, provisions.Retiring, false}} {
|
||||
}{{"the replaced edge provided, the older edge retiring", meshprovisionerclient.Provided, meshprovisionerclient.Retiring, true},
|
||||
{"the replaced edge provided, the older edge asked", meshprovisionerclient.Provided, meshprovisionerclient.Asked, true},
|
||||
{"the replaced edge asked, the older edge retiring", meshprovisionerclient.Asked, meshprovisionerclient.Retiring, false}} {
|
||||
m, n := ready()
|
||||
m.Manifest.Requires = []string{"oidc"}
|
||||
m.Provisions = func(node string) map[string]provisions.Provision {
|
||||
return map[string]provisions.Provision{node + ".mail.oidc": {Provision: "oidc", State: c.state},
|
||||
m.Provisions = func(node string) map[string]meshprovisionerclient.Provision {
|
||||
return map[string]meshprovisionerclient.Provision{node + ".mail.oidc": {Provision: "oidc", State: c.state},
|
||||
node + ".mail.database": {Provision: "database", State: c.older, Why: "the operator's answer"}}
|
||||
}
|
||||
out := Wants(m, n, wantedOld(), nil)
|
||||
@@ -267,7 +267,9 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) {
|
||||
} {
|
||||
m, n := ready()
|
||||
m.Manifest, m.Answering = c.manifest, answering
|
||||
m.Provisions = func(string) map[string]provisions.Provision { return map[string]provisions.Provision{} }
|
||||
m.Provisions = func(string) map[string]meshprovisionerclient.Provision {
|
||||
return map[string]meshprovisionerclient.Provision{}
|
||||
}
|
||||
out := Wants(m, n, wantedOld(), nil)
|
||||
if c.missing == "" {
|
||||
if out.Wants["g14"].Fp != fNew || len(m.MissingProvisions("g14")) != 0 {
|
||||
@@ -292,7 +294,9 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) {
|
||||
m.Manifest.Requires = []string{c.requires}
|
||||
m.Answering = func(string) []catalogue.Manifest { return nil }
|
||||
m.Offered = func(p string) bool { return c.offered && p == c.requires }
|
||||
m.Provisions = func(string) map[string]provisions.Provision { return map[string]provisions.Provision{} }
|
||||
m.Provisions = func(string) map[string]meshprovisionerclient.Provision {
|
||||
return map[string]meshprovisionerclient.Provision{}
|
||||
}
|
||||
out := Wants(m, n, wantedOld(), nil)
|
||||
if got := out.Wants["g14"].Fp == fNew; got != c.offered || (!c.offered && (out.Rules["g14"].Rule != mwc.RuleProvisions ||
|
||||
!strings.Contains(out.Rules["g14"].Words, "no module offers database yet") || !strings.Contains(out.Rules["g14"].Words, "past its bound"))) {
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
|
||||
@@ -177,7 +177,7 @@ func outOfStepTool(state func(string) views.Source) stdio.Tool {
|
||||
"build of the same module), then each open pull request whose check's verdict named out-of-step files.",
|
||||
Input: map[string]any{"type": "object", "properties": map[string]any{}},
|
||||
Run: func(map[string]any) (any, error) {
|
||||
rows, err := index.OutOfStepOf(state(index.SeatDefinitionsState), state(health.FindingsState))
|
||||
rows, err := index.OutOfStepOf(state(index.SeatDefinitionsState), state(mcc.FindingsState))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -131,7 +131,9 @@ func followSeatList(bus *seatBus, say func(context.Context, index.SeatDefinition
|
||||
}
|
||||
|
||||
// bucket is a state bound when it appears (process.AwaitedBucket).
|
||||
type bucket interface{ Ready(func(jetstream.KeyValue)) }
|
||||
type bucket interface {
|
||||
Ready(func(jetstream.KeyValue))
|
||||
}
|
||||
|
||||
// readWhenBound has the reader read the list again as each of the states it is answered from is bound. The reader starts before
|
||||
// they are, its first read finds them missing and leaves it unread, and the indexer's own events (said) are the only other thing
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
|
||||
sdkfindings "git.novox.be/novox/mesh-delivery/sdk/findings"
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
// findingsBucket is the indexer's own findings, which the condition keeper raises and clears (ADR 0564 §2): a value too
|
||||
// large for its views event, and its first view of the assigner's placement unanswered past its bound.
|
||||
var findingsBucket = health.FindingsBucket(index.Module)
|
||||
var findingsBucket = mcc.FindingsBucket(index.Module)
|
||||
|
||||
// readyOf binds a state's bucket: now for one bound at the start, once it appears for one awaited.
|
||||
type readyOf func(func(jetstream.KeyValue))
|
||||
|
||||
@@ -57,3 +57,7 @@ replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein =>
|
||||
replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg => ../mesh-delivery-forge-bridge/forgemsg
|
||||
|
||||
replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds => ../mesh-delivery-builder/builds
|
||||
|
||||
require git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go v0.0.0-20261105000000-000000000000
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
|
||||
"mesh-delivery-indexer/judge"
|
||||
@@ -62,7 +62,7 @@ func (ix *Indexer) sayAccepted(ctx context.Context, a meshcatalog.ManifestAccept
|
||||
|
||||
// unsaidKey is the key of module's unsaid finding.
|
||||
func unsaidKey(module string) string {
|
||||
return health.FindingKey(health.ScopeModule, Module+".accepted."+module, UnsaidKind)
|
||||
return mcc.Key(mcc.ScopeModule, Module+".accepted."+module, UnsaidKind)
|
||||
}
|
||||
|
||||
// unsaid writes module's finding for err, or deletes it with none.
|
||||
@@ -77,14 +77,12 @@ func (ix *Indexer) unsaid(ctx context.Context, module string, err error) {
|
||||
}
|
||||
at := ix.now().UTC()
|
||||
summary := fmt.Sprintf("%s of %s was not published: %v", meshcatalog.EventManifestAccepted, module, err)
|
||||
data, ferr := health.EncodeFinding(health.Finding{Key: key, Kind: UnsaidKind,
|
||||
Subject: health.Subject{Scope: health.ScopeModule, ID: Module + ".accepted." + module}, Severity: health.Warning,
|
||||
data, ferr := mcc.EncodeFinding(mcc.Observation{Scope: mcc.ScopeModule, ID: Module + ".accepted." + module, Kind: UnsaidKind,
|
||||
Summary: summary,
|
||||
Headline: "The indexer could not tell the bus module that " + module + "'s manifest was accepted",
|
||||
Explanation: "The bus module creates and removes a module's bus state from this event. The indexer says it again at its " +
|
||||
"next judging pass and clears this once it is said; indexer_say_accepted says it now.",
|
||||
Resolved: "manifest-accepted of " + module + " was said.",
|
||||
Evidence: []health.Evidence{{At: at, Said: summary}}, Source: UnsaidKind, Observer: Module, At: at})
|
||||
Resolved: "manifest-accepted of " + module + " was said.", Source: UnsaidKind}.Finding(Module, "", at))
|
||||
return data, false, ferr
|
||||
})
|
||||
if werr != nil {
|
||||
@@ -168,7 +166,7 @@ func (ix *Indexer) SayUnsaid(ctx context.Context) {
|
||||
if err != nil || !found {
|
||||
continue
|
||||
}
|
||||
f, err := health.DecodeFinding(value)
|
||||
f, err := mcc.DecodeFinding(value)
|
||||
if err != nil || f.Kind != UnsaidKind {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg"
|
||||
sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
||||
@@ -173,7 +173,7 @@ func TestTheControlRecords(t *testing.T) {
|
||||
}
|
||||
return e, ok
|
||||
}
|
||||
unparsed := health.FindingKey(health.ScopeModule, findingID("seat-definitions", "mesh-contracts"), SeatDefinitionUnparsedKind)
|
||||
unparsed := mcc.Key(mcc.ScopeModule, findingID("seat-definitions", "mesh-contracts"), SeatDefinitionUnparsedKind)
|
||||
merged(m1)
|
||||
merged(m1) // the same digests again say nothing
|
||||
g1, ok := entry("git.trunk")
|
||||
@@ -221,7 +221,7 @@ func TestTheControlRecords(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
twice := health.FindingKey(health.ScopeModule, findingID("seat-defined-twice", "other-contracts"), SeatDefinedTwiceKind)
|
||||
twice := mcc.Key(mcc.ScopeModule, findingID("seat-defined-twice", "other-contracts"), SeatDefinedTwiceKind)
|
||||
before := len(said)
|
||||
mergedOther("o1")
|
||||
if g, _ := entry("git.trunk"); g.Repository != repo || g.Commit != m3 || len(said) != before {
|
||||
@@ -348,7 +348,7 @@ func TestTheControlRecords(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
outside := health.FindingKey(health.ScopeModule, findingID("seat-outside-its-domain", "mesh-contracts"), SeatOutsideItsDomainKind)
|
||||
outside := mcc.Key(mcc.ScopeModule, findingID("seat-outside-its-domain", "mesh-contracts"), SeatOutsideItsDomainKind)
|
||||
before = len(said)
|
||||
// mesh-contracts defines wants and vault, seats of other domains: refused with a finding naming both modules, the
|
||||
// held entries stand, and lone (Core) is taken.
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
)
|
||||
|
||||
// fakeBounds is the state hold-bounds: the end each key was armed with, a standing key keeping its end.
|
||||
@@ -50,7 +50,7 @@ func storeHoldersNewManifestWaitsForEveryCountedEngine(t *testing.T) {
|
||||
ix.Holds, ix.Findings, ix.HoldBounds, ix.Now = holds, findings, bounds, func() time.Time { return clock }
|
||||
ix.Counted = func() (map[string][]string, bool) { return stated, true }
|
||||
ix.AskEngines = func(nodes []string, _ string) { asked = append(asked, nodes...) }
|
||||
heldKey := health.FindingKey(health.ScopeModule, findingID("hold", "distribution"), HoldStandingKind)
|
||||
heldKey := mcc.Key(mcc.ScopeModule, findingID("hold", "distribution"), HoldStandingKind)
|
||||
|
||||
first := withManifests(mergedMsg(catalogueRepo, map[string]string{dir: "tree1", dockerDir: "d1"}), map[string]string{dir: old, dockerDir: docker}, nil)
|
||||
if err := ix.Apply(ctx, first); err != nil {
|
||||
@@ -95,7 +95,7 @@ func storeHoldersNewManifestWaitsForEveryCountedEngine(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stays("past its bound,")
|
||||
f, err := health.DecodeFinding(findings.vals[heldKey])
|
||||
f, err := mcc.DecodeFinding(findings.vals[heldKey])
|
||||
if err != nil || f.Kind != HoldStandingKind || !strings.Contains(f.Summary, "n2 lacks form:seat-reach") {
|
||||
t.Fatalf("past its bound the finding %s = %+v (%v), want manifest-held naming n2", heldKey, f, err)
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
@@ -599,20 +599,19 @@ func (ix *Indexer) finding(ctx context.Context, id, kind string, raise bool, sum
|
||||
if ix.Findings == nil {
|
||||
return
|
||||
}
|
||||
key := health.FindingKey(health.ScopeModule, id, kind)
|
||||
key := mcc.Key(mcc.ScopeModule, id, kind)
|
||||
err := write(ctx, ix.Findings, key, func(value []byte, found bool) ([]byte, bool, error) {
|
||||
if !raise {
|
||||
return nil, found, nil
|
||||
}
|
||||
if found {
|
||||
if f, err := health.DecodeFinding(value); err == nil && f.Summary == summary {
|
||||
if f, err := mcc.DecodeFinding(value); err == nil && f.Summary == summary {
|
||||
return nil, false, nil
|
||||
}
|
||||
}
|
||||
at := ix.now().UTC()
|
||||
data, err := health.EncodeFinding(health.Finding{Key: key, Kind: kind, Subject: health.Subject{Scope: health.ScopeModule, ID: id},
|
||||
Severity: health.Warning, Summary: summary, Headline: headline, Explanation: explanation, Resolved: resolved,
|
||||
Evidence: []health.Evidence{{At: at, Said: summary}}, Source: kind, Observer: Module, At: at})
|
||||
data, err := mcc.EncodeFinding(mcc.Observation{Scope: mcc.ScopeModule, ID: id, Kind: kind, Summary: summary,
|
||||
Headline: headline, Explanation: explanation, Resolved: resolved, Source: kind}.Finding(Module, "", at))
|
||||
return data, false, err
|
||||
})
|
||||
if err != nil {
|
||||
@@ -762,7 +761,7 @@ func OutOfStepOf(defs, findings views.Source) ([]OutOfStepRow, error) {
|
||||
if err != nil || !ok || v == nil {
|
||||
continue
|
||||
}
|
||||
f, err := health.DecodeFinding(v.Value)
|
||||
f, err := mcc.DecodeFinding(v.Value)
|
||||
if err != nil || f.Kind != OutOfStepKind {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/graph"
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
@@ -30,7 +30,7 @@ var ReadTools = []ViewedTool{
|
||||
{Tool: "indexer_read_graph", State: graph.State, Words: "the module graph: each module's build and provision edges."},
|
||||
{Tool: "indexer_read_heard", State: HeardState, Words: "the forge messages the indexer heard and what it did with each."},
|
||||
{Tool: "indexer_read_taken", State: "taken", Words: "each repository's merge the indexer took in last."},
|
||||
{Tool: "indexer_read_findings", State: health.FindingsState, Words: "the indexer's findings, which the condition keeper raises and clears."},
|
||||
{Tool: "indexer_read_findings", State: mcc.FindingsState, Words: "the indexer's findings, which the condition keeper raises and clears."},
|
||||
{Tool: "indexer_read_seat_definitions", State: SeatDefinitionsState, Words: "the seat definitions the trunk's and each open pull request's contracts modules hold, resolved, or why one does not parse."},
|
||||
}
|
||||
|
||||
@@ -51,6 +51,6 @@ var ViewedStates = map[string]string{
|
||||
graph.State: graph.Bucket,
|
||||
HeardState: HeardBucket,
|
||||
"taken": TakenBucket,
|
||||
health.FindingsState: health.FindingsBucket(Module),
|
||||
mcc.FindingsState: mcc.FindingsBucket(Module),
|
||||
SeatDefinitionsState: SeatDefinitionsBucket,
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/composer"
|
||||
"git.novox.be/novox/mesh-networking/modules/mesh-wireguard/go/overlay"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/overlay"
|
||||
)
|
||||
|
||||
// The judge (novox/hq ADR 0578 §1): a manifest alone is accepted, or refused with each problem; an unknown field is
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/graph"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
|
||||
"mesh-delivery-indexer/internal/index"
|
||||
@@ -114,7 +114,7 @@ func TestManifestDeclarations(t *testing.T) { // 1238/AC1, 1444 (reads the build
|
||||
}
|
||||
// 1126 note 76: heard keeps the last 64 FORGE messages the indexer handled, for indexer_heard.
|
||||
if want := []state{{Name: "candidates", History: 10}, {Name: "heard", History: 64}, {Name: "manifests", History: 1}, {Name: "modules", History: 20}, {Name: "predefined", History: 5}, {Name: "config-candidates", History: 5}, {Name: "taken", History: 1}, {Name: "takeins", History: 1}, {Name: "verdicts", History: 5}, {Name: "oldsections", History: 1}, {Name: index.PackagesState, History: index.PackagesHistory},
|
||||
{Name: graph.State, History: graph.History}, {Name: views.MarksState, History: 1}, {Name: health.FindingsState, History: 5}, {Name: views.StatusState, History: 1},
|
||||
{Name: graph.State, History: graph.History}, {Name: views.MarksState, History: 1}, {Name: mcc.FindingsState, History: 5}, {Name: views.StatusState, History: 1},
|
||||
{Name: index.RequirementsState, History: 5}, {Name: index.SeatDefinitionsState, History: 5},
|
||||
{Name: index.HoldsState, History: 5}, {Name: index.EngineReadsState, History: 1}, {Name: index.HoldBoundsState, History: 1, KeyTTL: true}, {Name: index.PendingState, History: 1}}; !reflect.DeepEqual(m.State, want) { // DLV-I7, DLV-I17, ADR 0632 §2
|
||||
t.Errorf("state = %+v, want %+v", m.State, want)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate"
|
||||
@@ -21,7 +22,6 @@ import (
|
||||
"git.novox.be/novox/mesh-delivery/sdk/enginereads"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/busretry"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
)
|
||||
|
||||
@@ -414,7 +414,7 @@ func main() {
|
||||
r.ConditionsState, r.AttemptsState = read(stdio.State(view.StatusConditionsState)), read(stdio.State(view.StatusAttemptsState))
|
||||
r.PresenceState, r.StuckState = read(stdio.State(view.StatusPresenceState)), read(stdio.State(view.StatusStuckState))
|
||||
r.SourceState = read(stdio.State(view.GateModule + ".source"))
|
||||
r.ProvisionsState = read(stdio.State(provisions.ProvisionsRead))
|
||||
r.ProvisionsState = read(stdio.State(meshprovisionerclient.ProvisionsRead))
|
||||
r.BuildLog = stdio.Log(builds.BuildLogRead).Since
|
||||
r.Pending = pendingOf
|
||||
u := view.UsageReader{Haves: r.HavesState, Resolved: read(stdio.State("mesh-config.resolved")), Tries: read(stdio.State("mesh-delivery-checker.tries")),
|
||||
|
||||
@@ -14,12 +14,12 @@ import (
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/graph"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
)
|
||||
|
||||
// encoded is v as its contract's encoder writes it, failing the test when it refuses.
|
||||
@@ -85,9 +85,9 @@ func tiersToolSaysEachModulesWait(t *testing.T) {
|
||||
}.reader().State
|
||||
r.WantsState.History = func(string) ([]view.Revision, error) { return []view.Revision{{At: since}}, nil }
|
||||
r.HavesState = fake{key(nodeengineclient.HaveKey("ace", "db")): have(nodeengine.HaveByNodeModuleValue{Fp: fp("a"), Phase: nodeengineclient.PhaseRunning, Health: nodeengineclient.HealthOK})}.reader().State
|
||||
p, err := provisions.Encode(provisions.Provision{Provision: "database", Consumer: provisions.End{Module: "web", Node: "ace"},
|
||||
Provider: provisions.End{Module: "db", Node: "ace"}, State: provisions.Asked, Why: "the build db runs does not offer it", At: since})
|
||||
r.ProvisionsState = fake{key(provisions.Key("ace", "web", "database", "")): encoded(t, p, err)}.reader().State
|
||||
p, err := meshprovisionerclient.Encode(meshprovisionerclient.Provision{Provision: "database", Consumer: meshprovisionerclient.End{Module: "web", Node: "ace"},
|
||||
Provider: meshprovisionerclient.End{Module: "db", Node: "ace"}, State: meshprovisionerclient.Asked, Why: "the build db runs does not offer it", At: since})
|
||||
r.ProvisionsState = fake{key(meshprovisionerclient.Key("ace", "web", "database", "")): encoded(t, p, err)}.reader().State
|
||||
off, err := meshwatchdogsclient.EncodeNodePresence(meshwatchdogsclient.NodePresence{Online: false})
|
||||
r.PresenceState = fake{key(meshwatchdogsclient.PresenceNodeKey("g14")): encoded(t, off, err)}.reader().State
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ module mesh-delivery-view
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/identity-and-access/go/clients/meshvaultclient v0.0.0-00010101000000-000000000000
|
||||
@@ -50,3 +51,6 @@ require (
|
||||
replace git.novox.be/novox/mesh-delivery/sdk => ../../sdk
|
||||
|
||||
replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein => ../mesh-delivery-indexer/takein
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers v0.0.0-00010101000000-000000000000
|
||||
|
||||
@@ -8,9 +8,11 @@ import (
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
mcseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
|
||||
healers "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/motion"
|
||||
)
|
||||
|
||||
@@ -28,8 +30,8 @@ const StatusTool = "view_status"
|
||||
|
||||
// The states status reads, as the view's manifest names them.
|
||||
const (
|
||||
StatusConditionsState = health.KeeperModule + "." + health.ConditionsState
|
||||
StatusAttemptsState = health.HealersModule + "." + health.AttemptsState
|
||||
StatusConditionsState = mcseat.Seat + "." + mcseat.StateConditions
|
||||
StatusAttemptsState = healers.Seat + "." + healers.StateAttempts
|
||||
StatusPresenceState = WatchmanModule + ".presence"
|
||||
StatusStuckState = WatchmanModule + ".stuck"
|
||||
)
|
||||
@@ -115,17 +117,17 @@ func DeriveStatus(r StatusRead, now time.Time) Status {
|
||||
if raw, err := values(r.Conditions); err != nil {
|
||||
st.ConditionsUnread = "the condition keeper's conditions cannot be read: " + err.Error()
|
||||
} else {
|
||||
var open []health.Condition
|
||||
var open []mcseat.ConditionsByKeyValue
|
||||
for _, v := range raw {
|
||||
var c health.Condition
|
||||
var c mcseat.ConditionsByKeyValue
|
||||
if json.Unmarshal(v, &c) == nil && c.Key != "" {
|
||||
open = append(open, c)
|
||||
}
|
||||
}
|
||||
health.Order(open)
|
||||
mcc.Order(open)
|
||||
for _, c := range open {
|
||||
st.Conditions = append(st.Conditions, StatusCondition{Key: c.Key, Severity: string(c.Severity), Machine: c.Subject.Machine,
|
||||
Summary: c.Summary, Raised: c.Raised, Silenced: c.SilencedAt(now)})
|
||||
st.Conditions = append(st.Conditions, StatusCondition{Key: c.Key, Severity: c.Severity, Machine: c.Subject.Machine,
|
||||
Summary: c.Summary, Raised: c.Raised, Silenced: mcc.SilencedAt(c, now)})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,13 +205,13 @@ func DeriveStatus(r StatusRead, now time.Time) Status {
|
||||
st.HealsUnread = "mesh-healers' attempts cannot be read: " + err.Error()
|
||||
} else {
|
||||
for _, v := range raw {
|
||||
var a health.Attempt
|
||||
var a healers.AttemptsByAttemptValue
|
||||
if json.Unmarshal(v, &a) != nil || now.Sub(a.Begun) > HealsWithin {
|
||||
continue
|
||||
}
|
||||
outcome := a.Outcome
|
||||
if outcome == "" {
|
||||
outcome = health.OutcomeActing
|
||||
outcome = healers.AttemptsByAttemptValueOutcomeActing
|
||||
}
|
||||
st.Heals[outcome]++
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliveryclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/graph"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
)
|
||||
|
||||
// The tiers of a source revision are a view, worked out at each call and never stored (novox/hq ADR 0603 §1, §6): the
|
||||
@@ -389,7 +389,7 @@ func provisionWaits(node, module, a string, provided map[string]json.RawMessage,
|
||||
if perr != nil {
|
||||
return []TierWait{{Edge: edge, Node: node, Words: "the provisioner's keys cannot be read: " + perr.Error()}}
|
||||
}
|
||||
prefix, _ := provisions.Key(node, module, a, "")
|
||||
prefix, _ := meshprovisionerclient.Key(node, module, a, "")
|
||||
var out []TierWait
|
||||
found := false
|
||||
for _, key := range slices.Sorted(maps.Keys(provided)) {
|
||||
@@ -397,12 +397,12 @@ func provisionWaits(node, module, a string, provided map[string]json.RawMessage,
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
p, err := provisions.Decode(provided[key])
|
||||
p, err := meshprovisionerclient.Decode(provided[key])
|
||||
if err != nil {
|
||||
out = append(out, TierWait{Edge: edge, Node: node, Words: "the provision key " + key + " does not read: " + err.Error()})
|
||||
continue
|
||||
}
|
||||
if p.State == provisions.Provided {
|
||||
if p.State == meshprovisionerclient.Provided {
|
||||
continue
|
||||
}
|
||||
words := "the provision " + key + " is " + p.State
|
||||
|
||||
@@ -10,12 +10,14 @@ import (
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
mcseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
|
||||
healers "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshhealers"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
"git.novox.be/novox/mesh-sdk/go/motion"
|
||||
)
|
||||
@@ -301,8 +303,8 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) {
|
||||
fin := t0.Add(time.Minute)
|
||||
r := StatusRead{
|
||||
Conditions: states(map[string]string{
|
||||
"machine.b.silent": enc(health.Condition{Key: "machine.b.silent", Severity: health.Warning, Summary: "b silent", Raised: t0}),
|
||||
"core.doctor.self-check": enc(health.Condition{Key: "core.doctor.self-check", Severity: health.Urgent, Summary: "no run", Raised: t0.Add(time.Minute)}),
|
||||
"machine.b.silent": enc(mcseat.ConditionsByKeyValue{Key: "machine.b.silent", Severity: mcc.Warning, Summary: "b silent", Raised: t0}),
|
||||
"core.doctor.self-check": enc(mcseat.ConditionsByKeyValue{Key: "core.doctor.self-check", Severity: mcc.Urgent, Summary: "no run", Raised: t0.Add(time.Minute)}),
|
||||
}),
|
||||
Presence: states(map[string]string{"a": presence(true), "b": presence(false)}),
|
||||
Stuck: states(map[string]string{stuckWant: stuckOf(AssignerWantsBucket, "want.b.web", "b to run web", false),
|
||||
@@ -310,8 +312,8 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) {
|
||||
Wants: states(map[string]string{"want.a.web": want(fp2), "want.a.mail": want(fp1), "want.b.web": want(fp2), "want.a.db": want(fp3)}),
|
||||
Haves: states(map[string]string{"a.web": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""), "a.mail": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""),
|
||||
"b.web": have(fp1, nodeengineclient.PhaseRunning, nodeengineclient.HealthOK, ""), "a.db": have(fp3, nodeengineclient.PhaseRunning, nodeengineclient.HealthFailed, "the unit failed")}),
|
||||
Attempts: states(map[string]string{"1": enc(health.Attempt{Outcome: health.OutcomeActed, Begun: t0, Finished: &fin}),
|
||||
"2": enc(health.Attempt{Outcome: health.OutcomeEscalated, Begun: t0}), "old": enc(health.Attempt{Outcome: health.OutcomeActed, Begun: now.Add(-8 * 24 * time.Hour)})}),
|
||||
Attempts: states(map[string]string{"1": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeActed, Begun: t0, Finished: &fin}),
|
||||
"2": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeEscalated, Begun: t0}), "old": enc(healers.AttemptsByAttemptValue{Outcome: healers.AttemptsByAttemptValueOutcomeActed, Begun: now.Add(-8 * 24 * time.Hour)})}),
|
||||
}
|
||||
st := DeriveStatus(r, now)
|
||||
if len(st.Conditions) != 2 || st.Conditions[0].Key != "core.doctor.self-check" || st.Conditions[1].Key != "machine.b.silent" {
|
||||
@@ -328,7 +330,7 @@ func statusDerivesEachPartFromItsBucket(t *testing.T) {
|
||||
if !reflect.DeepEqual(st.Moving, wantMoving) {
|
||||
t.Errorf("moving = %+v\nwant %+v", st.Moving, wantMoving)
|
||||
}
|
||||
if !reflect.DeepEqual(st.Heals, map[string]int{health.OutcomeActed: 1, health.OutcomeEscalated: 1}) || st.Well {
|
||||
if !reflect.DeepEqual(st.Heals, map[string]int{healers.AttemptsByAttemptValueOutcomeActed: 1, healers.AttemptsByAttemptValueOutcomeEscalated: 1}) || st.Well {
|
||||
t.Errorf("heals = %v, well %v", st.Heals, st.Well)
|
||||
}
|
||||
// A part it cannot read is said, and the mesh is not well; with nothing wrong and every part read it is.
|
||||
|
||||
@@ -41,3 +41,4 @@ replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun
|
||||
require git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000
|
||||
|
||||
replace git.novox.be/novox/mesh-delivery/sdk => ../../sdk
|
||||
require git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000
|
||||
|
||||
@@ -3,40 +3,40 @@ package watch
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/heard"
|
||||
)
|
||||
|
||||
// The watchman is an observer of the seat mesh-watchdogs (novox/hq ADR 0564 §2, §4): what it observes wrong it writes as a
|
||||
// finding, one key `<scope>.<id>.<kind>` of its own bucket `findings` in mesh-sdk's layout (health.Finding), only when what
|
||||
// finding, one key `<scope>.<id>.<kind>` of its own bucket `findings` in the seat mesh-conditions' layout (meshconditionsclient), only when what
|
||||
// it says changes, and it deletes the key when it no longer observes it. The condition keeper (mesh-conditions) raises and
|
||||
// clears the conditions from them; the watchman writes no condition and reads none (Limits 11).
|
||||
|
||||
// FindingsBucket is the watchman's findings.
|
||||
var FindingsBucket = health.FindingsBucket(health.WatchmanModule)
|
||||
var FindingsBucket = mcc.FindingsBucket(Observer)
|
||||
|
||||
// Observer is the name a finding of the watchman carries.
|
||||
const Observer = health.WatchmanModule
|
||||
const Observer = "mesh-delivery-watchman"
|
||||
|
||||
// The scopes and severities a finding of the watchman names, as the controller's conditions name them, so the keeper's
|
||||
// `compare` meets the same keys.
|
||||
const (
|
||||
ScopeMachine = health.ScopeMachine
|
||||
ScopeDelivery = health.ScopeDelivery
|
||||
ScopeModule = health.ScopeModule
|
||||
ScopeProvider = health.ScopeProvider
|
||||
ScopeBus = health.ScopeBus
|
||||
ScopeCore = health.ScopeCore
|
||||
ScopeMachine = mcc.ScopeMachine
|
||||
ScopeDelivery = mcc.ScopeDelivery
|
||||
ScopeModule = mcc.ScopeModule
|
||||
ScopeProvider = mcc.ScopeProvider
|
||||
ScopeBus = mcc.ScopeBus
|
||||
ScopeCore = mcc.ScopeCore
|
||||
|
||||
Urgent = string(health.Urgent)
|
||||
Warning = string(health.Warning)
|
||||
Urgent = mcc.Urgent
|
||||
Warning = mcc.Warning
|
||||
)
|
||||
|
||||
// Finding is what the watchman builds of one thing it observes wrong: its subject (scope, id, the machine and the others
|
||||
// it concerns), kind and severity, its evidence (Summary, and Said with Since, its one observation), the words the
|
||||
// operator reads (ADR 0253; empty leaves the keeper's wording of the kind), and the row or fact it comes from (Source).
|
||||
// It is written as health.Finding.
|
||||
// It is written as the seat's finding.
|
||||
type Finding struct {
|
||||
Scope, ID, Token, Kind, Machine string
|
||||
Also []string
|
||||
@@ -51,8 +51,8 @@ type Finding struct {
|
||||
Since time.Time
|
||||
}
|
||||
|
||||
// FindingKey composes a finding's key as the controller composes a condition's (health.Key).
|
||||
func FindingKey(scope, id, token string) string { return health.FindingKey(scope, id, token) }
|
||||
// FindingKey composes a finding's key as the controller composes a condition's (mcc.Key).
|
||||
func FindingKey(scope, id, token string) string { return mcc.Key(scope, id, token) }
|
||||
|
||||
// Key is the finding's key: its token, or its kind when it has none.
|
||||
func (f Finding) Key() string {
|
||||
@@ -63,27 +63,21 @@ func (f Finding) Key() string {
|
||||
return FindingKey(f.Scope, f.ID, token)
|
||||
}
|
||||
|
||||
// EncodeFinding is f in mesh-sdk's layout, refusing one the keeper could not make a condition of.
|
||||
// EncodeFinding is f in the seat's layout, refusing one the keeper could not make a condition of.
|
||||
func EncodeFinding(f Finding) ([]byte, error) {
|
||||
said := f.Said
|
||||
if said == "" {
|
||||
said = f.Summary
|
||||
}
|
||||
return health.EncodeFinding(health.Finding{Key: f.Key(), Kind: f.Kind, Ref: f.Token,
|
||||
Subject: health.Subject{Scope: f.Scope, ID: f.ID, Machine: f.Machine, Also: f.Also},
|
||||
Severity: health.Severity(f.Severity), Summary: f.Summary, Headline: f.Headline, Explanation: f.Explanation,
|
||||
Resolved: f.Resolved, Needs: f.Needs, Evidence: []health.Evidence{{At: f.Since.UTC(), Said: said}},
|
||||
Source: f.Source, Observer: Observer, At: f.Since.UTC()})
|
||||
return mcc.EncodeFinding(mcc.Observation{Scope: f.Scope, ID: f.ID, Kind: f.Kind, Ref: f.Token, Machine: f.Machine, Also: f.Also,
|
||||
Severity: f.Severity, Summary: f.Summary, Said: f.Said, Headline: f.Headline, Explanation: f.Explanation,
|
||||
Resolved: f.Resolved, Needs: f.Needs, Source: f.Source}.Finding(Observer, "", f.Since))
|
||||
}
|
||||
|
||||
// DecodeFinding reads a finding the watchman wrote.
|
||||
func DecodeFinding(data []byte) (Finding, error) {
|
||||
h, err := health.DecodeFinding(data)
|
||||
h, err := mcc.DecodeFinding(data)
|
||||
if err != nil {
|
||||
return Finding{}, err
|
||||
}
|
||||
f := Finding{Scope: h.Subject.Scope, ID: h.Subject.ID, Token: h.Ref, Kind: h.Kind, Machine: h.Subject.Machine,
|
||||
Also: h.Subject.Also, Severity: string(h.Severity), Summary: h.Summary, Headline: h.Headline, Explanation: h.Explanation,
|
||||
Also: h.Subject.Also, Severity: h.Severity, Summary: h.Summary, Headline: h.Headline, Explanation: h.Explanation,
|
||||
Needs: h.Needs, Resolved: h.Resolved, Source: h.Source, Observer: h.Observer, Since: h.At}
|
||||
if len(h.Evidence) > 0 {
|
||||
f.Said = h.Evidence[0].Said
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
|
||||
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
||||
mcc "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshwantsclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/heard"
|
||||
@@ -277,7 +277,7 @@ func TestTheWatchmansFindings(t *testing.T) {
|
||||
case !row.noState && row.want == "" && stands:
|
||||
t.Errorf("%s: the finding stands once bound", row.name)
|
||||
case row.want != "":
|
||||
f, err := health.DecodeFinding(raw)
|
||||
f, err := mcc.DecodeFinding(raw)
|
||||
// Review round 2: it says it clears at the part's next start, since Bind runs at the start.
|
||||
if err != nil || f.Kind != heard.Kind || f.Summary != row.want || f.Observer != "mesh-delivery-indexer" || !strings.Contains(f.Explanation, "next start") {
|
||||
t.Errorf("%s: the finding %+v (%v), want summary %q", row.name, f, err, row.want)
|
||||
|
||||
Reference in New Issue
Block a user