Answer the node seat's packages from the engine's own key alone
The controller's declared-packages mirror ended with the controller (issue 1126) and is deleted after group B's delivery, so the verb no longer reads or compares it. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -333,8 +333,8 @@ func composeFrom(current *agentNow, composer *atomic.Pointer[selfcompose.Compose
|
||||
// packagesReadFor bounds the verb packages' reads and its write.
|
||||
const packagesReadFor = 20 * time.Second
|
||||
|
||||
// packagesFrom answers the verb packages (novox/hq ADR 0565 §6, §15): this node's key of the engine's state packages
|
||||
// beside the controller's mirror's key for it and their difference; with write, the key written again from what the
|
||||
// packagesFrom answers the verb packages (novox/hq ADR 0565 §6, §15): this node's key of the engine's state packages;
|
||||
// with write, the key written again from what the
|
||||
// composer that runs now handed, refused in words while the node composes none of its own.
|
||||
func packagesFrom(node string, session *link.Session, composer *atomic.Pointer[selfcompose.Composer]) func(write bool) (any, error) {
|
||||
return func(write bool) (any, error) {
|
||||
@@ -344,8 +344,8 @@ func packagesFrom(node string, session *link.Session, composer *atomic.Pointer[s
|
||||
if write {
|
||||
c := composer.Load()
|
||||
if c == nil {
|
||||
return nil, errors.New("this node composes none of its own modules now (it applies the controller's " +
|
||||
"compositions, or its node agent is starting), so it has no packages of its own to write")
|
||||
return nil, errors.New("this node composes none of its own modules now (its node agent is starting), " +
|
||||
"so it has no packages of its own to write")
|
||||
}
|
||||
w, err := c.WritePackages(ctx)
|
||||
if err != nil {
|
||||
@@ -354,12 +354,7 @@ func packagesFrom(node string, session *link.Session, composer *atomic.Pointer[s
|
||||
wrote = &w
|
||||
}
|
||||
key, keyErr := link.EnginePackages{Session: session}.Get(ctx, node)
|
||||
var mirror []byte
|
||||
h, mirrorErr := session.KVHistory(ctx, link.MirrorPackagesBucket, node)
|
||||
if mirrorErr == nil && len(h) > 0 && !h[len(h)-1].Deleted {
|
||||
mirror = h[len(h)-1].Value
|
||||
}
|
||||
v := link.PackagesAnswer(node, key, mirror, keyErr, mirrorErr)
|
||||
v := link.PackagesAnswer(node, key, keyErr)
|
||||
v.Wrote = wrote
|
||||
return v, nil
|
||||
}
|
||||
|
||||
@@ -17,10 +17,6 @@ import (
|
||||
// mesh-host.packages (delivery.EnginePackagesRead).
|
||||
const PackagesBucket = "mesh-host_" + delivery.EnginePackagesState
|
||||
|
||||
// MirrorPackagesBucket is the controller's declared-packages mirror (ADR 0507 §5), which the engine reads its own node's
|
||||
// key of until the lease write, to compare (the node seat's verb packages).
|
||||
const MirrorPackagesBucket = "mesh-controller_declared-packages"
|
||||
|
||||
// packagesStore binds PackagesBucket over the link open now: bound, never created.
|
||||
func (l *natsLink) packagesStore() (nats.KeyValue, error) {
|
||||
kv, err := l.js.KeyValue(PackagesBucket)
|
||||
@@ -83,51 +79,33 @@ func (p EnginePackages) Put(_ context.Context, key string, value []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// PackagesView is the node seat's verb packages' answer (ADR 0565 §6): this node's key of the engine's state packages,
|
||||
// and until the lease write the controller's mirror's key for the node and every package they hold differently.
|
||||
// PackagesView is the node seat's verb packages' answer (ADR 0565 §6): this node's key of the engine's state packages.
|
||||
// The controller's mirror it was once compared with ended with the controller (issue 1126).
|
||||
type PackagesView struct {
|
||||
Node string `json:"node"`
|
||||
// Key is the node's key as the bus holds it (Source); null when the engine has written none.
|
||||
Source string `json:"source"`
|
||||
Key *delivery.DeclaredPackages `json:"key"`
|
||||
KeyError string `json:"key_error,omitempty"`
|
||||
// Mirror is the controller's mirror's key for the node (MirrorSource); null when it holds none or cannot be read.
|
||||
MirrorSource string `json:"mirror_source"`
|
||||
Mirror *delivery.DeclaredPackages `json:"mirror"`
|
||||
MirrorError string `json:"mirror_error,omitempty"`
|
||||
// Differences is every package the two hold differently, read only when both are; Agree when there is none.
|
||||
Differences []delivery.PackageDifference `json:"differences"`
|
||||
Agree bool `json:"agree"`
|
||||
// Wrote says, for write, whether the key was written again (false: it already held what the engine composed).
|
||||
Wrote *bool `json:"wrote,omitempty"`
|
||||
Note string `json:"note,omitempty"`
|
||||
}
|
||||
|
||||
// PackagesAnswer is the verb's answer from the two keys as read (nil: no key), each with its read's error.
|
||||
func PackagesAnswer(node string, key, mirror []byte, keyErr, mirrorErr error) PackagesView {
|
||||
v := PackagesView{Node: node, Source: delivery.EnginePackagesRead, MirrorSource: "mesh-controller.declared-packages",
|
||||
Differences: []delivery.PackageDifference{}}
|
||||
read := func(raw []byte, err error, into **delivery.DeclaredPackages, said *string) {
|
||||
if err == nil && raw != nil {
|
||||
var d delivery.DeclaredPackages
|
||||
if err = json.Unmarshal(raw, &d); err == nil {
|
||||
*into = &d
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
*said = err.Error()
|
||||
// PackagesAnswer is the verb's answer from the key as read (nil: no key), with its read's error.
|
||||
func PackagesAnswer(node string, key []byte, keyErr error) PackagesView {
|
||||
v := PackagesView{Node: node, Source: delivery.EnginePackagesRead}
|
||||
if keyErr == nil && key != nil {
|
||||
var d delivery.DeclaredPackages
|
||||
if keyErr = json.Unmarshal(key, &d); keyErr == nil {
|
||||
v.Key = &d
|
||||
}
|
||||
}
|
||||
read(key, keyErr, &v.Key, &v.KeyError)
|
||||
read(mirror, mirrorErr, &v.Mirror, &v.MirrorError)
|
||||
switch {
|
||||
case v.Key != nil && v.Mirror != nil:
|
||||
v.Differences = delivery.DiffDeclaredPackages(*v.Key, *v.Mirror)
|
||||
v.Agree = len(v.Differences) == 0
|
||||
case v.Key == nil && v.KeyError == "":
|
||||
v.Note = "the engine has written no key for this node yet: pacman reads the controller's mirror for it"
|
||||
case v.Mirror == nil && v.MirrorError == "":
|
||||
v.Note = "the controller's mirror holds no key for this node: nothing to compare"
|
||||
case keyErr != nil:
|
||||
v.KeyError = keyErr.Error()
|
||||
case v.Key == nil:
|
||||
v.Note = "the engine has written no key for this node yet"
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -241,15 +241,13 @@ func TestALinkThatHearsHandOversIsGivenTheQueues(t *testing.T) {
|
||||
return map[string]any{"module": module, "digest": digest, "diff": diff}, nil
|
||||
},
|
||||
Compose: func(module string) (any, error) { return map[string]any{"composed": true, "retried": module}, nil },
|
||||
// ADR 0565 §6, §15: the node's key beside the controller's mirror's, the mirror's from its writer's test.
|
||||
// ADR 0565 §6, §15: the node's key of the engine's state packages.
|
||||
Packages: func(write bool) (any, error) {
|
||||
key := []byte(`{"node":"n1","packages":[{"package":"curl","modules":["backup","web"],"absent":false}]}`)
|
||||
mirror := []byte(`{"node":"n1","packages":[{"package":"curl","modules":["backup","web"],"absent":false},` +
|
||||
`{"package":"nano","modules":["web"],"absent":true}]}`)
|
||||
if !write {
|
||||
return PackagesAnswer("n1", key, mirror, nil, nil), nil
|
||||
return PackagesAnswer("n1", key, nil), nil
|
||||
}
|
||||
v := PackagesAnswer("n1", nil, nil, nil, errors.New("not granted"))
|
||||
v := PackagesAnswer("n1", nil, nil)
|
||||
wrote := true
|
||||
v.Wrote = &wrote
|
||||
return v, nil
|
||||
@@ -265,11 +263,10 @@ func TestALinkThatHearsHandOversIsGivenTheQueues(t *testing.T) {
|
||||
// The recovery verb compose (issue 774) makes a pass now, with a module's apply tried again when named.
|
||||
{"compose", EngineToolSubject("compose", "n1"), `"composed":true,"retried":""`},
|
||||
{"compose", EngineToolSubject("compose", "n1") + " " + `{"module":"route-proxy"}`, `"retried":"route-proxy"`},
|
||||
// The read verb packages (ADR 0565 §6) names both sources and their difference; with write, what it wrote, and a
|
||||
// key the engine has not written, or a mirror it may not read, is said and not an error.
|
||||
{"packages", EngineToolSubject("packages", "n1"), `"differences":[{"package":"nano","absent":true,"engine":[],"mirror":["web"]}],"agree":false`},
|
||||
// The read verb packages (ADR 0565 §6) names its source; with write, what it wrote, and a key the engine has not
|
||||
// written is said and not an error.
|
||||
{"packages", EngineToolSubject("packages", "n1"), `"source":"mesh-host.packages","key":{"node":"n1"`},
|
||||
{"packages", EngineToolSubject("packages", "n1") + " " + `{"write":true}`, `"mirror":null,"mirror_error":"not granted","differences":[],"agree":false,"wrote":true`},
|
||||
{"packages", EngineToolSubject("packages", "n1") + " " + `{"write":true}`, `"key":null,"wrote":true`},
|
||||
{"packages", EngineToolSubject("packages", "n1") + " " + `{"write":"true"}`, `"note":"the engine has written no key for this node yet`},
|
||||
{"unserved", "mesh.seat.node-engine.call.unserved.n1.x", `"error":"the node seat node-engine serves no verb \"unserved\""`},
|
||||
} {
|
||||
|
||||
Reference in New Issue
Block a user