admin.adoc (12825B)
1 == System Administration 2 3 === Services on a running system 4 5 Liminix services are built on s6-rc, which is itself layered on s6. 6 Services are defined at build time in your configuration (see 7 <<_services>> for information) and can't be added 8 to/changed at runtime, but to monitor events or diagnose problems you 9 may need to inspect them on the running system. Here are some of the 10 most commonly used s6,-rc commands: 11 12 .Service management quick reference 13 [width="100%",cols="55%,45%",options="header",] 14 |=== 15 |What |How 16 |List all running services |`+s6-rc -a list+` 17 18 |List all services that are *not* running |`+s6-rc -da list+` 19 20 |List services that `+wombat+` depends on 21 |`+s6-rc-db dependencies wombat+` 22 23 |... transitively |`+s6-rc-db all-dependencies wombat+` 24 25 |List services that depend on service `+wombat+` 26 |`+s6-rc-db -d dependencies wombat+` 27 28 |... transitively |`+s6-rc-db -d all-dependencies wombat+` 29 30 |Stop service `+wombat+` and everything depending on it 31 |`+s6-rc -d change wombat+` 32 33 |Start service `+wombat+` (but not any services depending on it) 34 |`+s6-rc -u change wombat+` 35 36 |Start service `+wombat+` and all* services depending on it 37 |`+s6-rc-up-tree wombat+` 38 |=== 39 40 `+s6-rc-up-tree+` brings up a service and all services that depend on 41 it, except for any services that depend on a "controlled" service that 42 is not currently running. Controlled services are not started at boot 43 time but in response to external events (e.g. plugging in a particular 44 piece of hardware) so you probably don't want to be starting them by 45 hand if the conditions aren't there. 46 47 A service may be *up* or *down* (there are no intermediate states like 48 "started" or "stopping" or "dying" or "cogitating"). Some (but not all) 49 services have "readiness" notifications: the dependents of a service 50 with a readiness notification won't be started until the service signals 51 (by writing to a nominated file descriptor) that it's prepared to start 52 work. Most services defined by Liminix also have a `+timeout-up+` 53 parameter, which means that if a service has readiness notifications and 54 doesn't become ready in the allotted time (defaults 20 seconds) it will 55 be terminated and its state set to *down*. 56 57 If the process providing a service dies, it will be restarted 58 automatically. Liminix does not automatically set it to *down*. 59 60 (If the process providing a service dies without ever notifying 61 readiness, Liminix will restart it as many times as it has to until the 62 timeout period elapses, and then stop it and mark it down.) 63 64 ==== Controlled services 65 66 *Controlled* services are those which are started/stopped on demand by a 67 *controller* (another service) instead of being started at boot time. 68 For example: 69 70 * `+svc.uevent-rule.build+` creates a controlled service which is active 71 when a particular hardware device (identified by uevent/sysfs directory) 72 is present. 73 * `+svc.round-robin.build+` creates a service controller that invokes 74 two or more services in turn, running the next one when the process 75 providing the previous one exits. We use this for failover from one 76 network connection to a backup connection, for example. 77 * `+svc.health-check.build+` creates a service controller that runs a 78 controlled service and periodically tests whether it is healthy by 79 running an external health check command or script. If the check command 80 repeatedly fails, the controlled service is restarted. 81 + 82 The Configuration section of the manual describes controlled services in 83 more detail. Some operational considerations 84 * `+round-robin+` detects a service status by looking at its `+outputs+` 85 directory, so it won't work unless the service creates some outputs. 86 This is considered a bug and will be fixed in a future release 87 * `+health-check+` works for longruns but not for oneshots, as it 88 internally relies on `+s6-svc+` to restart the process 89 90 ==== Logs 91 92 Logs for all services are collated into `+/run/log/current+`. The log 93 file is rotated when it reaches a threshold size, into another file in 94 the same directory whose name contains a TAI64 timestamp. 95 96 Each log line is prefixed with a TAI64 timestamp and the name of the 97 service, if it is a longrun. If it is a oneshot, a timestamp and the 98 name of some other service. To convert the timestamp into a 99 human-readable format, use `+s6-tai64nlocal+`. 100 101 [source,console] 102 ---- 103 # ls -l /run/log/ 104 -rw-r--r-- 1 0 lock 105 -rw-r--r-- 1 0 state 106 -rwxr--r-- 1 98059 @4000000000025cb629c311ac.s 107 -rwxr--r-- 1 98061 @40000000000260f7309c7fb4.s 108 -rwxr--r-- 1 98041 @40000000000265233a6cc0b6.s 109 -rwxr--r-- 1 98019 @400000000002695d10c06929.s 110 -rwxr--r-- 1 98064 @4000000000026d84189559e0.s 111 -rwxr--r-- 1 98055 @40000000000271ce1e031d91.s 112 -rwxr--r-- 1 98054 @400000000002760229733626.s 113 -rwxr--r-- 1 98104 @4000000000027a2e3b6f4e12.s 114 -rwxr--r-- 1 98023 @4000000000027e6f0ed24a6c.s 115 -rw-r--r-- 1 42374 current 116 117 # tail -2 /run/log/current 118 @40000000000284f130747343 wan.link.pppoe Connect: ppp0 <--> /dev/pts/0 119 @40000000000284f230acc669 wan.link.pppoe sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x667a9594> <pcomp> <accomp>] 120 # tail -2 /run/log/current | s6-tai64nlocal 121 1970-01-02 21:51:45.828598156 wan.link.pppoe sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x667a9594> <pcomp> <accom 122 p>] 123 1970-01-02 21:51:48.832588765 wan.link.pppoe sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x667a9594> <pcomp> <accom 124 p>] 125 ---- 126 127 ===== Log persistence 128 129 Logs written to `+/run/log/+` will not survive a reboot or crash, as it 130 is an ephemeral filesystem. 131 132 On supported hardware you can enable logging to 133 https://www.kernel.org/doc/Documentation/ABI/testing/pstore[pstore] 134 which means the most recent log messages will be preserved on reboot. 135 Set the config option `+logging.persistent.enable = true+` to log 136 messages to `+/dev/pmsg0+` as well as to the regular log. This is a 137 circular buffer, so when it fills up newer messages will overwrite the 138 oldest messages. 139 140 Logs found in pstore after a reboot will be moved at startup to 141 `+/run/log/previous-boot+` 142 143 === Updating an installed system 144 145 If your system has a writable root filesystem (JFFS2, btrfs etc 146 -anything but squashfs), we have mechanisms for in-places updates 147 analogous to `+nixos-rebuild+`, but the operation is a bit different 148 because it expects to run on a build machine and then copy to the host 149 device using `+ssh+`. 150 151 To use this, build the `+outputs.updater+` target and then run the 152 `+update.sh+` script it generates. 153 154 [source,console] 155 ---- 156 nix-build -I liminix-config=./my-configuration.nix \ 157 --arg device "import ./devices/mydevice" \ 158 -A outputs.updater 159 ./result/bin/update.sh root@the-device 160 ---- 161 162 The update script uses min-copy-closure to copy new or changed packages 163 to the device, then (perhaps) reboots it. The reboot behaviour can be 164 affected by flags: 165 166 * [.title-ref]#--no-reboot# will cause it not to reboot at all, if you 167 would rather do that yourself. Note that none of the newly-installed or 168 updated services will be running until you do. 169 * [.title-ref]#--fast# causes it tn not do a full reboot, but instead to 170 restart only the services that have been changed. This will restart all 171 of the services that have updated store paths (and anything that depends 172 on them), but will not affect services that haven't changed. 173 174 It doesn't delete old packages automatically: to do that run 175 `+min-collect-garbage+`, which will delete any packages not in the 176 current system closure. Note that Liminix does not have the NixOS 177 concept of environments or generations, and there is no way back from 178 this except for building the previous configuration again. 179 180 ==== Caveats 181 182 * it needs there to be enough free space on the device for all the new 183 packages in addition to all the packages already on it - which may be a 184 problem if there is little flash storage or if a lot of things have 185 changed (e.g. a new version of nixpkgs). 186 * it may not be able to upgrade the kernel: this is device-dependent. If 187 your device boots from a kernel image on a raw MTD partition or or UBI 188 volume, update.sh is unable to alter the kernel partition. If your 189 device boots from a kernel inside the filesystem (e.g. using 190 bootloader.extlinux or bootloder.fit) then the kernel will be upgraded 191 along with the userland 192 193 ==== Recovery/downgrades 194 195 The `+update.sh+` script also creates a timestamped symlink on the 196 device which points to the system configuration it installs. If you 197 install a configuration that doesn't work, you can revert to any other 198 installed configuration by 199 200 [arabic] 201 . booting to some kind of rescue or recovery system (which may be some 202 vendor-provided rescue option, or your own recovery system perhaps based 203 on `+examples/recovery.nix+`) and mounting your Liminix filesystem on 204 /mnt 205 . picking another previously-installed configuration that _link:[did] 206 work, and switching back to it: 207 208 [source,console] 209 ---- 210 # ls -ld /mnt/*configuration 211 lrwxrwxrwx 1 90 /mnt/20252102T182104.configuration -> nix/store/v1w0h4zw65ah4c2r0k7nyy125qrxhq78-system-configuration-aarch64-unknown-linux-musl 212 lrwxrwxrwx 1 90 /mnt/20251802T181822.configuration -> nix/store/wqjl9s9xljl2wg8257292zghws9ssidk-system-configuration-aarch64-unknown-linux-musl 213 # : 20251802T181822 is the working system, so reinstall it 214 # /mnt/20251802T181822.configuration/bin/install /mnt 215 # umount /mnt 216 # reboot 217 ---- 218 219 This will install the previous configuration's activation binary into 220 /bin, and copy its kernel and initramfs into /boot. Note that it depends 221 on the previous system not having been garbage-collected. 222 223 ==== Adding packages 224 225 If you simply wish to add a package without any change to services, you 226 can call `+min-copy-closure+` directly to install any package in Nixpkgs 227 or in the Liminix overlay 228 229 [source,console] 230 ---- 231 nix-build -I liminix-config=./my-configuration.nix \ 232 --arg device "import ./devices/mydevice" -A pkgs.tcpdump 233 234 nix-shell -p min-copy-closure root@the-device result/ 235 ---- 236 237 Note that this only copies the package and its dependencies to the 238 device: it doesn't update any profile to add it to `+$PATH+` 239 240 [reftext="Levitate"] 241 [[levitate]] 242 === Levitate: Reinstalling on a running system 243 244 Liminix is initially installed from a monolithic `+firmware.bin+` - and 245 unless you're running a writable filesystem, the only way to update it 246 is to build and install a whole new `+firmware.bin+`. However, you 247 probably would prefer not to have to remove it from its installation 248 site, unplug it from the network and stick serial cables in it all over 249 again. 250 251 It is not (generally) safe to install a new firmware onto the flash 252 partitions that the active system is running on. To address this we have 253 `+levitate+`, which a way for a running Liminix system to "soft restart" 254 into a ramdisk running only a limited set of services, so that the main 255 partitions can then be safely flashed. 256 257 ==== Configuration 258 259 Levitate _needs to be configured when you create the initial system_ to 260 specify which services/packages/etc to run in maintenance mode. Most 261 likely you want to configure a network interface and an ssh for example 262 so that you can login to reflash it. 263 264 [source,nix] 265 ---- 266 defaultProfile.packages = with pkgs; [ 267 ... 268 (levitate.override { 269 config = { 270 services = { 271 inherit (config.services) dhcpc sshd watchdog; 272 }; 273 defaultProfile.packages = [ mtdutils ]; 274 users.root = config.users.root; 275 }; 276 }) 277 ]; 278 ---- 279 280 ==== Use 281 282 Connect (with ssh, probably) to the running Liminix system that you wish 283 to upgrade. 284 285 [source,console] 286 ---- 287 bash$ ssh root@the-device 288 ---- 289 290 Run `+levitate+`. This takes a little while (perhaps a few tens of 291 seconds) to execute, and copies all config required for maintenance mode 292 to `+/run/maintenance+`. 293 294 [source,console] 295 ---- 296 # levitate 297 ---- 298 299 Reboot into maintenance mode. You will be logged out 300 301 [source,console] 302 ---- 303 # reboot 304 ---- 305 306 Connect to the device again - note that the ssh host key will have 307 changed. 308 309 [source,console] 310 ---- 311 # ssh -o UserKnownHostsFile=/dev/null root@the-device 312 ---- 313 314 Check we're in maintenance mode 315 316 [source,console] 317 ---- 318 # cat /etc/banner 319 320 LADIES AND GENTLEMEN WE ARE FLOATING IN SPACE 321 322 Most services are disabled. The system is operating 323 with a ram-based root filesystem, making it safe to 324 overwrite the flash devices in order to perform 325 upgrades and maintenance. 326 327 Don't forget to reboot when you have finished. 328 ---- 329 330 Perform the upgrade, using flashcp. This is an example, your device will 331 differ 332 333 [source,console] 334 ---- 335 # cat /proc/mtd 336 dev: size erasesize name 337 mtd0: 00030000 00010000 "u-boot" 338 mtd1: 00010000 00010000 "u-boot-env" 339 mtd2: 00010000 00010000 "factory" 340 mtd3: 00f80000 00010000 "firmware" 341 mtd4: 00220000 00010000 "kernel" 342 mtd5: 00d60000 00010000 "rootfs" 343 mtd6: 00010000 00010000 "art" 344 # flashcp -v firmware.bin mtd:firmware 345 ---- 346 347 All done 348 349 [source,console] 350 ---- 351 # reboot 352 ----