The host reads a one-shot that is not running as having run, so a before-sleep or after-wake unit declared stopped failed on its first apply; drop-ins on the sleep targets pull them in instead.
83 lines
4.9 KiB
Markdown
83 lines
4.9 KiB
Markdown
# power
|
|
|
|
A machine's power (novox/hq ADR 0211). This module holds `node-power` on every machine, servers
|
|
included, because every machine boots and shuts down. It owns logind's power key and lid handling. It
|
|
runs the code other modules contribute for the power moments, and it publishes the machine's power
|
|
states on the bus.
|
|
|
|
## What it owns
|
|
|
|
| | |
|
|
|---|---|
|
|
| `/etc/systemd/logind.conf.d/power.conf` | the power key and the lid, from this module's settings (below); logind is reloaded, never restarted |
|
|
| `/etc/mesh-power/moments/<moment>` | for each moment, every module's code as the controller placed it (`${shell:<moment>:<slot>}`) |
|
|
| `/usr/local/lib/mesh-power/bin/power-moment` | the runner: each module's piece on its own, as root, with `sh`, bounded (`MESH_POWER_BOUND`, default 30 s); every outcome in the journal under `mesh-power` |
|
|
| five units | `mesh-power-after-boot`, `-before-shutdown` (its stop is the shutdown, while the network is still up), `-before-sleep`, `-after-wake`, `-supply` |
|
|
| `/etc/udev/rules.d/90-mesh-power.rules` | a power supply's change starts `mesh-power-supply`, which runs `on-mains` or `on-battery` once per change of source |
|
|
|
|
## The moments, and how a module adds code
|
|
|
|
The moments are `after-boot`, `before-sleep`, `after-wake`, `before-shutdown`, `on-mains` and
|
|
`on-battery`. A module declares a `shell` entry whose `for` names the moment, in the `first`,
|
|
`normal` or `last` slot, with POSIX shell code. That entry depends on this seat (ADR 0210). The code
|
|
runs as root. Code that needs the operator's session finds it itself, as the laptop module's touchpad
|
|
reset does with `runuser`.
|
|
|
|
**One rule for contributed code:** the runner splits the placed file at lines of the form `# <module>`,
|
|
which the controller writes before each module's piece. A comment line of the piece's own that is
|
|
one lowercase word would split it too, so comments in contributed code use more than one word.
|
|
|
|
Code that must run *inside* the sleep transaction, such as the NVIDIA driver's own suspend and
|
|
resume units, is not a contribution. Its module keeps its own drop-ins on the sleep services (ADR
|
|
0211, "What got harder").
|
|
|
|
## Settings
|
|
|
|
`handle-power-key`, `handle-lid-switch`, `handle-lid-switch-external-power` and
|
|
`handle-lid-switch-docked`, each one of logind's actions. They have no defaults, so the mesh's layer
|
|
must be set before the first assignment. The mesh's layer carries logind's own defaults (`poweroff`,
|
|
`suspend`, `suspend`, `ignore`). A machine's layer changes them: the laptop suspends on all four.
|
|
|
|
## Events
|
|
|
|
| event | when |
|
|
|---|---|
|
|
| `booted` | once per boot, not per restart of the runtime (the boot id is remembered) |
|
|
| `sleeping` | before the machine sleeps: the module's watcher holds logind's delay lock, publishes, waits for the bus at most 3 s, and lets go |
|
|
| `woke` | after waking, queued until the bus is reachable |
|
|
| `shutting-down` | before a shutdown, as `sleeping` |
|
|
| `on-mains`, `on-battery` | when the power source changes, on a machine with a Mains supply |
|
|
| `battery-low` | at 10 % on battery, once per discharge |
|
|
|
|
Each carries the time it happened. Events the bus did not take wait in order and go out when it answers
|
|
again. A machine that said `sleeping` is asleep, not out of touch.
|
|
|
|
## Tools
|
|
|
|
| tool | |
|
|
|---|---|
|
|
| `power_state` | boot time, source and battery, lid, logind's settings, and the watcher's lock, last sleep and wake, and queue |
|
|
| `power_hooks` | every moment's contributed pieces, with their module |
|
|
| `power_history` | boots, sleeps, wakes and moment runs from the journal |
|
|
| `power_run` | run one moment now, to test it (needs `sudo -n`) |
|
|
| `power_check` | units, runner, moment files, one logind writer, no hand-placed sleep hooks, the lock held, nothing stuck before the bus |
|
|
|
|
## Migration
|
|
|
|
- **The laptop:** its model module owned `logind.conf.d/power.conf` and a touchpad resume unit. Both
|
|
move here: the file to this module, and the resume to an `after-wake` contribution.
|
|
- **The desktop:** the predecessor left `logind.conf.d/brightness.conf` and
|
|
`/etc/systemd/system-sleep/xinput-reset-touchpad.sh`. Move both aside after the first push;
|
|
`power_check` names them while they remain.
|
|
- **The servers** have no logind drop-ins and no sleep hooks today.
|
|
|
|
The lesson from the day this module was written belongs to the dbus module: a full upgrade restarted
|
|
the system bus live on a workstation, and logins hung until a reboot.
|
|
|
|
**Why the sleep hooks are wanted, not enabled.** The host reads a one-shot unit that is not running
|
|
and has not failed as having run and worked, so a hook unit waiting for a sleep could never be
|
|
declared stopped. The first version tried that and was refused on its first apply. The two sleep
|
|
units are therefore not services the mesh manages. They have no install section, and the sleep
|
|
targets want them through this module's drop-ins (`sleep.target.d`, and `suspend.target.d` with
|
|
its three siblings) — the same way the laptop module asks for the NVIDIA driver's sleep actions.
|