pacman keeps one mirror list for the mesh, ranked in the write that opens each round and written by every node (ADR 0585, issue 1876)
Each node's reflector ranked its own list on its own timer, and on 2026-10-31 one node's lagging first mirror left it a Node.js version behind the rest. The list is now the module's state mirrors, key list: the node that opens a week's round ranks it with the module's reflector options, keeps only mirrors whose last sync is no older than the newest found, and the round's key names the list's revision. Every keeper writes /etc/pacman.d/mirrorlist whole from the key through the root helper's new verb mirrorlist, when the key changes and when the file differs, and never writes an empty or unreadable list. reflector.timer is declared stopped and disabled, and reflector.conf saves nothing. pacman_mirrors answers the shared list, its ranker and age and whether this node's file matches; with refresh it asks this node's keeper to rank again, refused while a round runs, naming it. The round's integration test proves the opening write and both nodes' files. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -34,10 +34,11 @@ func newRootBed(t *testing.T) *rootBed {
|
||||
}
|
||||
return Ran{}
|
||||
},
|
||||
Proc: stubProc{"/proc": {"1"}, "/proc/1/maps": {"7f00 r-xp 0 0:1 1 /usr/lib/libc.so.6 (deleted)"}, "/proc/1/cgroup": {"0::/system.slice/sshd.service"}, "/proc/1/exe": {"/usr/bin/sshd"}},
|
||||
ProcRoot: "/proc",
|
||||
PlanDir: t.TempDir(),
|
||||
Self: "/var/lib/mesh/daemons/pacman-root/pacman-tools",
|
||||
Proc: stubProc{"/proc": {"1"}, "/proc/1/maps": {"7f00 r-xp 0 0:1 1 /usr/lib/libc.so.6 (deleted)"}, "/proc/1/cgroup": {"0::/system.slice/sshd.service"}, "/proc/1/exe": {"/usr/bin/sshd"}},
|
||||
ProcRoot: "/proc",
|
||||
PlanDir: t.TempDir(),
|
||||
Self: "/var/lib/mesh/daemons/pacman-root/pacman-tools",
|
||||
MirrorlistPath: filepath.Join(t.TempDir(), "mirrorlist"),
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -113,8 +114,16 @@ func TestTheRootHelperStartsARollbackWithThePlanInTheRequest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// And (ADR 0585 §3) the verb mirrorlist writes the mirror list file whole from the servers it is sent, running nothing.
|
||||
func TestTheRootHelperReadsTheReplacedFilesMappings(t *testing.T) {
|
||||
b := newRootBed(t)
|
||||
servers := []string{"https://a.example/$repo/os/$arch", "https://b.example/archlinux/$repo/os/$arch"}
|
||||
if a := b.h.Handle(RootRequest{Verb: VerbMirrorlist, Servers: servers}); a.Error != "" {
|
||||
t.Fatalf("the mirror list refused: %s", a.Error)
|
||||
}
|
||||
if got, err := os.ReadFile(b.h.MirrorlistPath); err != nil || string(got) != string(RenderMirrorlist(servers)) || len(b.ran) != 0 {
|
||||
t.Fatalf("the mirror list file holds %q (%v), ran %v", got, err, b.ran)
|
||||
}
|
||||
a := b.h.Handle(RootRequest{Verb: VerbMaps})
|
||||
want := []Mapped{{Unit: "sshd.service", Executable: "/usr/bin/sshd"}}
|
||||
if a.Error != "" || !reflect.DeepEqual(a.Mapped, want) {
|
||||
@@ -169,6 +178,11 @@ func TestTheRootHelperRefusesEverythingOffItsList(t *testing.T) {
|
||||
"a removal with a location": {Verb: VerbRollback, Run: aRun, Plan: with(func(i *RollbackItem) {
|
||||
i.Source, i.To = SourceRemoved, ""
|
||||
})},
|
||||
// ADR 0585 §3: never an empty mirror list, nor anything but a server in it.
|
||||
"an empty mirror list": {Verb: VerbMirrorlist},
|
||||
"a mirror list carrying a line": {Verb: VerbMirrorlist, Servers: []string{"https://a.example/$repo/os/$arch\nInclude = /tmp/x"}},
|
||||
"a mirror list of a local file": {Verb: VerbMirrorlist, Servers: []string{"file:///tmp/$repo/os/$arch"}},
|
||||
"a mirror list of another shape": {Verb: VerbMirrorlist, Servers: []string{"https://a.example/x"}},
|
||||
}
|
||||
for name, req := range cases {
|
||||
b := newRootBed(t)
|
||||
|
||||
Reference in New Issue
Block a user