liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

admin.adoc (12987B)


      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 Get the image onto the device, somehow
    331 
    332 [source,console]
    333 ----
    334 
    335 build$ cat result/firmware.bin | ssh -e none root@the-device "cat >/run/firmware.bin"
    336 ----
    337 
    338 
    339 Now perform the upgrade, using flashcp. This is an example, your
    340 device will differ
    341 
    342 [source,console]
    343 ----
    344 
    345 # cat /proc/mtd
    346 dev:    size   erasesize  name
    347 mtd0: 00030000 00010000 "u-boot"
    348 mtd1: 00010000 00010000 "u-boot-env"
    349 mtd2: 00010000 00010000 "factory"
    350 mtd3: 00f80000 00010000 "firmware"
    351 mtd4: 00220000 00010000 "kernel"
    352 mtd5: 00d60000 00010000 "rootfs"
    353 mtd6: 00010000 00010000 "art"
    354 # flashcp -v /run/firmware.bin mtd:firmware
    355 ----
    356 
    357 All done
    358 
    359 [source,console]
    360 ----
    361 # reboot
    362 ----