issue 1841/S13: describe the package view, the runs, the round, the root helper and the health read from the bus in pacman's README
This commit is contained in:
+53
-26
@@ -10,10 +10,10 @@ that seat (ADR 0207).
|
||||
(ADR 0207).
|
||||
- **`/etc/pacman.conf`, whole.** A block cannot be added to `[options]` by appending: anything added
|
||||
at the end of the file lands in the last repository's section. So the module owns the file:
|
||||
- The repositories are the union of what the four machines had enabled on 2026-10-04: `core`,
|
||||
`extra` and `multilib`. All four had all three.
|
||||
- The repositories are the union of what the mesh's machines had enabled on 2026-10-04: `core`,
|
||||
`extra` and `multilib`. All had all three.
|
||||
- The options are the distribution's defaults, plus `Color`, `ParallelDownloads = 5`,
|
||||
`VerbosePkgLists`, and `DownloadUser = alpm` (pacman 7; the `alpm` user exists on all four).
|
||||
`VerbosePkgLists`, and `DownloadUser = alpm` (pacman 7; the `alpm` user exists on every machine).
|
||||
- The manifest test runs `pacman-conf` on the rendered file and checks the repository list and the
|
||||
options as pacman reads them. It skips that check where `pacman-conf` is absent.
|
||||
- The host keeps the machine's previous file once, the first time it writes over it (ADR 0102).
|
||||
@@ -23,23 +23,44 @@ that seat (ADR 0207).
|
||||
list stays reflector's to write, not the mesh's.
|
||||
- **Cache cleaning.** The `pacman-contrib` package and `paccache.timer` running and enabled. Each
|
||||
week it keeps the last three versions of each package.
|
||||
- **The weekly upgrade (ADR 0477 clause 5, issue 1574).** `mesh-pacman-weekly-upgrade.timer` and its
|
||||
oneshot service, placed whole in `/etc/systemd/system`. The timer fires every Saturday at 04:00 in the
|
||||
node's local time, the same moment on every node (no random delay), and is `Persistent=true`: a node that
|
||||
was off or asleep then upgrades at its next start. The service runs `/usr/bin/pacman -Syu --noconfirm`, the
|
||||
same arguments `pacman_upgrade` starts (`UpgradeArgs` in the code; a manifest test holds the two together).
|
||||
No other moment upgrades but a hand `pacman_upgrade`, and the mesh restarts no machine for an upgrade: a new
|
||||
kernel waits for the next restart.
|
||||
- **The outcome is the module's health.** The timer's resource asks `pacman_upgrade_health`: unhealthy,
|
||||
naming the exit and the last `error:` line of the journal, when the last weekly upgrade failed; healthy
|
||||
while it runs, after it passed, and before it ever ran. The controller raises the module's condition for
|
||||
the node from it. A failed service stays failed until
|
||||
the next run, so the condition stands until an upgrade passes; a hand `pacman_upgrade` does not clear
|
||||
it. A restart of the machine clears the failed state and with it the condition, and the next Saturday
|
||||
runs again. A run that goes on longer than two hours is unhealthy too, naming when it started and the
|
||||
last line of its journal: it is hung and holds pacman's database lock. The service has no start
|
||||
timeout on purpose, because killing pacman in the middle of a transaction is worse; the hung run is
|
||||
said, not killed.
|
||||
- **The package view on the bus (ADR 0507).** A process of its own, the keeper (`pacman-tools keeper`, account
|
||||
`pacman-keeper`, its own bus account), keeps the node's packages in the state `installed` and what an upgrade
|
||||
would change in `updates`, written only on change: at its start, whenever pacman's database lock is released
|
||||
(an inotify watch), when reflector rewrites the mirror list, and once a day. Each change of the packages is
|
||||
`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 controller's `declared-packages`, 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
|
||||
`Linux-Maximum` or `BUILD_EXCLUSIVE_KERNEL` excludes is held with its headers, `upgrade.kernel-held`), the
|
||||
transaction as a unit of its own, its end, and the after-upgrade check (`.pacnew`/`.pacsave` files, the news
|
||||
since the previous upgrade, units newly failed, a restart needed, processes still mapping a replaced file by
|
||||
unit and executable, DKMS modules not built for an installed kernel). pacman's log is read once into `runs`
|
||||
as history.
|
||||
- **The round.** The nodes upgrade in the order of the mesh-level key `upgrade-order` (a trusted list,
|
||||
`predefined.json`; the module's config value of the same name falls back to it). On Saturday at 04:00 local
|
||||
time the first node of the order opens the week's round in `rounds`; each node's keeper watches `rounds` and
|
||||
`runs` and starts its own run when the node before it passed its after-upgrade check. A failed run or check
|
||||
stops the round there; only the operator passes a node (`pacman_round` with `pass` and a reason asks on the
|
||||
operator's channel, and the round goes on only on the operator's Approve). With no order set no round opens.
|
||||
- **Acts are asks.** `pacman_upgrade` and `pacman_rollback` with `apply` write an ask in `asks` at
|
||||
`<node>.<id>`, which that node's keeper alone takes.
|
||||
- **The root helper (ADR 0510).** The keeper never runs as root. The acts that need root go through a second
|
||||
process of the same build, `pacman-root` (`pacman-tools root`), running as root with no bus account, on a
|
||||
unix socket in `${dir:state}/root/` that only the keeper's account may open, the peer's account checked on
|
||||
every connection. It serves four verbs and refuses everything else: start a run's full upgrade as the unit
|
||||
`mesh-pacman-upgrade-<run>` (leaving out held packages), start a rollback's unit with the plan in the request
|
||||
(packages from the cache or the Arch Linux Archive, the dated repository's file found by name), read which
|
||||
processes map a replaced file, and read a transaction unit's journal. No sudo rule is placed.
|
||||
- **The health is read from the bus.** The keeper's health check (`pacman_upgrade_health`) is unhealthy while
|
||||
no `upgrade-order` is set; while the node's latest run was refused, failed or did not pass its check (until
|
||||
a later run passes); while its transaction goes on past two hours (hung, said and not killed); while a
|
||||
kernel is held; and while the round stands still at this node or at the node it waits for, naming it and
|
||||
since when. A node that slept through a run is judged by what the bus holds, not by a unit's age (issue
|
||||
1579). The weekly timer of ADR 0477 §5 and its service are dropped from the manifest, so the node-engine
|
||||
removes them.
|
||||
|
||||
## What it improves
|
||||
|
||||
@@ -62,21 +83,27 @@ that seat (ADR 0207).
|
||||
|---|---|---|
|
||||
| `pacman_search` | r | `pacman -Ss`: repository, name, version, groups, installed and at which version, description |
|
||||
| `pacman_info` | r | `-Qi`, or `-Si` when not installed, with lists as lists |
|
||||
| `pacman_installed` | r | every package with version, explicit or dependency, foreign; filters and totals |
|
||||
| `pacman_installed` | r | every package with version, explicit or dependency, foreign; filters and totals, from `installed` on the bus |
|
||||
| `pacman_packages` | r | every node's packages from the bus: one package everywhere, differing versions, packages on some nodes only, each node's explicit packages no module declares, foreign apart, nodes not current |
|
||||
| `pacman_owns` | r | which package owns a path, or `owned: false` |
|
||||
| `pacman_files` | r | what a package placed, bounded |
|
||||
| `pacman_updates` | r | `checkupdates`: what a full upgrade would change, never setting up a partial upgrade |
|
||||
| `pacman_upgrade` | a | starts `pacman -Syu --noconfirm` (sudo -n) as a transient unit that outlives the call; answers the unit and the news since the last upgrade; given the unit, how it went |
|
||||
| `pacman_upgrade_health` | r | whether the weekly upgrade last passed: the timer's health check (see the weekly upgrade above) |
|
||||
| `pacman_updates` | r | what a full upgrade would change, for one node or all, from `updates` on the bus |
|
||||
| `pacman_upgrade` | a | asks a node's keeper for a full upgrade as a run (an ask in `asks`); answers the ask and the news since the last upgrade; given a transaction unit, how it goes |
|
||||
| `pacman_upgrade_health` | r | the keeper's health check, read from the bus (see the health above) |
|
||||
| `pacman_upgrades` | r | every run of every node from `runs`: narrowed to a node and days, or one run whole |
|
||||
| `pacman_round` | r/a | where every node stands in the newest rounds; `pass` with a reason asks the operator to let a round go on past a node |
|
||||
| `pacman_rollback` | r/a | what returning a node to a run's record would change, each package with its source; `apply` asks the node's keeper to run it |
|
||||
| `pacman_orphans` | r | `pacman -Qdt` |
|
||||
| `pacman_remove_orphans` | a | `pacman -Rs` on named orphans, or all of them, as a unit of its own; a name that is not an orphan is refused |
|
||||
| `pacman_cache` | r/a | size, interrupted downloads, what paccache would free keeping N; `clean: true` removes them |
|
||||
| `pacman_history` | r | `/var/log/pacman.log`: installs, upgrades, downgrades, reinstalls and removals since a day, and the last full upgrade |
|
||||
| `pacman_mirrors` | r/a | the list, its generator and age, reflector's options, timer and last run; `refresh: true` starts reflector |
|
||||
| `pacman_foreign` | r | `pacman -Qm` |
|
||||
| `pacman_foreign` | r | the foreign packages, from `installed` on the bus |
|
||||
| `pacman_news` | r | the distribution's news since the last full upgrade (or a day), over https; no network is `reachable: false` |
|
||||
| `pacman_config` | r | `pacman-conf`: options, repositories, and whether `/etc/pacman.conf` is the module's |
|
||||
|
||||
A transaction never runs as the tool's own child. An upgrade takes longer than the 20 s a call may
|
||||
take, and a pacman killed mid-transaction leaves a half-upgraded machine and a lock. So a transaction
|
||||
runs as a transient unit (`systemd-run`, named `mesh-pacman-…`), and its log is read from the journal.
|
||||
runs as a transient unit (`systemd-run`, named `mesh-pacman-…`), and its log is read from the journal. A
|
||||
run's transaction is started by the root helper; removing orphans and cleaning the cache still go through
|
||||
`sudo -n` from the tools bundle.
|
||||
|
||||
Reference in New Issue
Block a user