pacman reads the node-engine's packages first and the controller's mirror per node until the lease write; compare counts only an indexer that was read, and a forge not heard is said in the row (review round 1)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -30,7 +30,7 @@ that seat (ADR 0207).
|
||||
`package.changed`. A list over the bus's cap on a value is not written: the key keeps its last value and
|
||||
`<node>.not-current` says the size and since when, which the health says too. `pacman_packages`,
|
||||
`pacman_updates`, `pacman_installed` and `pacman_foreign` answer every node from these states, and what no
|
||||
module declares from the node-engine's `packages`, without asking a machine.
|
||||
module declares from the node-engine's `packages`, else the controller's `declared-packages` until its lease is written, without asking a machine.
|
||||
- **Upgrades as runs, one node at a time (ADR 0508).** Every full upgrade and every rollback is a run in the
|
||||
state `runs` at `<node>.<run>`, written at each step and emitted as it: the package record taken and read back
|
||||
(`records`, kept `record-days`), the DKMS gate before the transaction (a kernel an installed DKMS module's own
|
||||
|
||||
@@ -133,7 +133,7 @@ func TestTheKeeperDeclaresTheModulesStatesAndEvents(t *testing.T) {
|
||||
}
|
||||
// The verbs read which packages each node's modules declare; the process reads no other module's state
|
||||
// (ADR 0507 §5, ADR 0436 §1).
|
||||
if got := strs(raw["reads"]); !reflect.DeepEqual(got, []string{"node-engine.packages"}) {
|
||||
if got := strs(raw["reads"]); !reflect.DeepEqual(got, []string{"node-engine.packages", "mesh-controller.declared-packages"}) {
|
||||
t.Errorf("reads: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,17 @@ import (
|
||||
// DeclaredPackagesState is the node-engine's state of the packages its node's modules declare, one key per node,
|
||||
// written by that node's engine alone (ADR 0565 clause 6, which moved ADR 0507 §5's mirror off the controller), read
|
||||
// through the manifest's `reads`.
|
||||
const DeclaredPackagesState = "node-engine." + delivery.EnginePackagesState
|
||||
const DeclaredPackagesState = SourceEngine
|
||||
|
||||
// ControllerDeclaredState is the controller's mirror of the same packages (ADR 0507 §5), the per-node fallback for a node
|
||||
// whose engine has written no key yet, until the controller's lease is written away (ADR 0565 clause 6).
|
||||
const ControllerDeclaredState = "mesh-controller.declared-packages"
|
||||
|
||||
// The sources a node's declaration is read from, said in the answer.
|
||||
const (
|
||||
SourceEngine = "node-engine.packages"
|
||||
SourceController = "mesh-controller.declared-packages"
|
||||
)
|
||||
|
||||
// declaredValue is a node's key of `packages`, in mesh-sdk's layout (the controller's mirror unchanged).
|
||||
type declaredValue = delivery.DeclaredPackages
|
||||
@@ -107,28 +117,35 @@ func (m *Machine) installedOn(node string) ([]nodeInstalled, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// declaredOn is what each node's modules declare present, by node and package, with the declaring modules; a
|
||||
// node whose engine has written no key is missing.
|
||||
func (m *Machine) declaredOn(nodes []string) (map[string]map[string][]string, error) {
|
||||
r := m.States(DeclaredPackagesState)
|
||||
// declaredOn is what each node's modules declare present, by node and package, with the declaring modules, and the source
|
||||
// that answered for each node: its engine's key, else the controller's mirror; a node neither holds is missing.
|
||||
func (m *Machine) declaredOn(nodes []string) (map[string]map[string][]string, map[string]string, error) {
|
||||
out := map[string]map[string][]string{}
|
||||
for _, n := range nodes {
|
||||
var v declaredValue
|
||||
found, err := readValue(r, n, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
out[n] = map[string][]string{}
|
||||
for _, p := range v.Packages {
|
||||
if !p.Absent {
|
||||
out[n][p.Package] = p.Modules
|
||||
from := map[string]string{}
|
||||
for _, source := range []string{SourceEngine, SourceController} {
|
||||
r := m.States(source)
|
||||
for _, n := range nodes {
|
||||
if from[n] != "" {
|
||||
continue
|
||||
}
|
||||
var v declaredValue
|
||||
found, err := readValue(r, n, &v)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
from[n] = source
|
||||
out[n] = map[string][]string{}
|
||||
for _, p := range v.Packages {
|
||||
if !p.Absent {
|
||||
out[n][p.Package] = p.Modules
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
return out, from, nil
|
||||
}
|
||||
|
||||
// NodeView is one node in the view.
|
||||
@@ -142,9 +159,11 @@ type NodeView struct {
|
||||
Current bool `json:"current"`
|
||||
NotCurrent *NotCurrent `json:"not_current,omitempty"`
|
||||
// Undeclared is the packages installed explicitly from a repository that no module assigned to the node
|
||||
// declares; null when the node-engine has published no declaration of the node.
|
||||
// declares; null when neither the node-engine nor the controller's mirror holds a declaration of the node.
|
||||
Undeclared []PackageVersion `json:"undeclared"`
|
||||
Foreign []PackageVersion `json:"foreign"`
|
||||
// DeclaredFrom is the source that answered for the node's declaration; empty when neither holds one.
|
||||
DeclaredFrom string `json:"declared_from,omitempty"`
|
||||
}
|
||||
|
||||
// Spread is one package across the nodes: its version on each node that has it.
|
||||
@@ -163,6 +182,8 @@ type PackageOnNode struct {
|
||||
Foreign bool `json:"foreign,omitempty"`
|
||||
DeclaredBy []string `json:"declared_by"`
|
||||
Current bool `json:"current"`
|
||||
// DeclaredFrom is the source that answered for the node's declaration; empty when neither holds one.
|
||||
DeclaredFrom string `json:"declared_from,omitempty"`
|
||||
}
|
||||
|
||||
// Packages is pacman_packages: one package on every node, or the whole view: per node its counts, its explicit
|
||||
@@ -177,14 +198,14 @@ func (m *Machine) Packages(name string, limit int) (map[string]any, error) {
|
||||
for _, ni := range all {
|
||||
nodes = append(nodes, ni.Node)
|
||||
}
|
||||
declared, err := m.declaredOn(nodes)
|
||||
declared, sources, err := m.declaredOn(nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if name != "" {
|
||||
on := []PackageOnNode{}
|
||||
for _, ni := range all {
|
||||
p := PackageOnNode{Node: ni.Node, Current: ni.NotCurrent == nil, DeclaredBy: declared[ni.Node][name]}
|
||||
p := PackageOnNode{Node: ni.Node, Current: ni.NotCurrent == nil, DeclaredBy: declared[ni.Node][name], DeclaredFrom: sources[ni.Node]}
|
||||
if p.DeclaredBy == nil {
|
||||
p.DeclaredBy = []string{}
|
||||
}
|
||||
@@ -205,7 +226,7 @@ func (m *Machine) Packages(name string, limit int) (map[string]any, error) {
|
||||
versions := map[string]map[string]string{}
|
||||
for _, ni := range all {
|
||||
v := NodeView{Node: ni.Node, At: ni.Value.At, Packages: len(ni.Value.Packages), Current: ni.NotCurrent == nil,
|
||||
NotCurrent: ni.NotCurrent, Foreign: []PackageVersion{}}
|
||||
NotCurrent: ni.NotCurrent, Foreign: []PackageVersion{}, DeclaredFrom: sources[ni.Node]}
|
||||
d, known := declared[ni.Node]
|
||||
if known {
|
||||
v.Undeclared = []PackageVersion{}
|
||||
|
||||
@@ -40,7 +40,7 @@ func viewStates(t *testing.T) (*fakeStates, *Machine) {
|
||||
}
|
||||
|
||||
func TestOnePackageOnEveryNodeWithWhoDeclaresIt(t *testing.T) {
|
||||
_, m := viewStates(t)
|
||||
states, m := viewStates(t)
|
||||
r, err := m.Packages("zsh", 500)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -50,6 +50,22 @@ func TestOnePackageOnEveryNodeWithWhoDeclaresIt(t *testing.T) {
|
||||
t.Fatalf("%+v", on)
|
||||
}
|
||||
a, b := on[0], on[1]
|
||||
if a.DeclaredFrom != SourceEngine || b.DeclaredFrom != "" {
|
||||
t.Errorf("sources: %q, %q", a.DeclaredFrom, b.DeclaredFrom)
|
||||
}
|
||||
// A node whose engine has written no key reads the controller's mirror, said so; a node with both reads its engine's.
|
||||
var legacy, stale declaredValue
|
||||
json.Unmarshal([]byte(`{"node":"node-b","packages":[{"package":"zsh","modules":["legacy"],"absent":false}]}`), &legacy)
|
||||
json.Unmarshal([]byte(`{"node":"node-a","packages":[{"package":"zsh","modules":["stale"],"absent":false}]}`), &stale)
|
||||
mirror := states.store(ControllerDeclaredState)
|
||||
mirror.Put("node-b", legacy)
|
||||
mirror.Put("node-a", stale)
|
||||
r2, _ := m.Packages("zsh", 500)
|
||||
on2 := r2["nodes"].([]PackageOnNode)
|
||||
if on2[0].DeclaredFrom != SourceEngine || strings.Join(on2[0].DeclaredBy, ",") != "login,shell" ||
|
||||
on2[1].DeclaredFrom != SourceController || strings.Join(on2[1].DeclaredBy, ",") != "legacy" {
|
||||
t.Errorf("fallback: %+v", on2)
|
||||
}
|
||||
if a.Node != "node-a" || !a.Installed || a.Version != "5.9-2" || !a.Explicit || a.Repository != "extra" ||
|
||||
strings.Join(a.DeclaredBy, ",") != "login,shell" || !a.Current {
|
||||
t.Errorf("node-a: %+v", a)
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
}
|
||||
],
|
||||
"reads": [
|
||||
"node-engine.packages"
|
||||
"node-engine.packages",
|
||||
"mesh-controller.declared-packages"
|
||||
],
|
||||
"uses": [
|
||||
"operator-channel"
|
||||
|
||||
Reference in New Issue
Block a user