Files
finit/doc/conditions.md
T
Joachim Nilsson c7573fedad Replace 'initctl emit <EV>' with 'initctl cond <cmd> <COND>'
This patch replaces the old 'initctl emit <EV>' idea with a more
full blown condition generator:

    initctl cond <set|clear|flux> <COND>

This aligns better with terminology used elsewhere in the new Finit
service state machine and dependency handling already documented.

The 'flux' sub-command is mostly intended for simulation/test of
Finit itself and should perhaps not be documented.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-07-15 15:51:57 +02:00

5.2 KiB

Finit Conditions

The service state machine

Table of Contents

Introduction

In addition to declaring allowed runlevels per service, it is also possible to declare user-defined conditions as dependencies. Conditions are specified within angle brackets (<>) in the service stanza. Multiple conditions may be specified separated by comma. Conditions are AND'ed during evaluation, i.e. all conditions must be satisfied in order for a service to run.

Example:

    service [2345] <svc/sbin/setupd,svc/sbin/zebra> /sbin/netd -- Network monitor

In this example the Network monitor daemon netd is not started until both the svc/sbin/setupd and svc/sbin/zebra conditions are satisfied. An svc condition is satisfied by the corresponding service's pidfile being created.

Triggering

Conditions are triggered either by plugins or by using the cond command of the initctl control tool.

  • initctl cond set your/cond/here

    To set a condition

  • initctl cond clear your/cond/here

    To clear a condition

Conditions retain their current state until the next reconfiguration or runlevel change. At that point all set conditions transition into the flux state, meaning the condition's state is unknown. (See Internals for the rationale behind this.) Thus, after a reconfiguration it is up to the "owner" of the condition to convey the new (or possibly unchanged) state of it.

Built-in Conditions

Finit is distributed with a pidfile and netlink plugin. If enabled, the pidfile plugin watches /var/run/ for PID files created by monitored services, and sets a corresponding condition in the svc/ namespace. Similarily, the netlink plugin provides basic conditions for when an interface is brought up/down and when a default route (gateway) is set.

With the example listed above, finit does not start the /sbin/netd daemon until setupd and zebra has started and created their PID files. Which they do when they completed their main tasks of setting up VLANs, bridge, interfaces, etc. When netd in turn starts up it creates the file /var/run/netd.pid, and the condition svc/sbin/netd is satisfied. When the file is removed, the condition is cleared.

The full path to the dependency is needed by finit to match the PID file to a monitored process.

Built-in conditions:

  • svc/<PATH>
  • net/route/default
  • net/<IFNAME>/exist
  • net/<IFNAME>/up

Note: up is administratively up, IFF_UP, not link up, IFF_RUNNING.

Debugging

If a service is not being started as it should, the problem might be that one of its conditions is not in the expected state. Use the command initctl status to inspect service status. Services in the ready state are pending a condition.

In that situation, running initctl cond show reveals which of the conditions that are not satisfied. Listed as off below.

Example:

    ~ # initctl cond show
    PID     Service               Status  Condition (+ on, ~ flux, - off)
    ===============================================================================
    1419    /sbin/netd            on      <+svc/sbin/setupd,+svc/sbin/zebra>
    0       /sbin/udhcpc          off     <-net/vlan1/exist>

Here we can see that netd is allowed to run since both its conditions are in the on state, as indicated by the +-prefix. udhcpc however is not allowed to run since net/vlan1/exist condition is not satsifed. As indicated by the --prefix.

To fake interface vlan1 suddenly appearing, and test what happens to udhcpc we can enable debug mode and assert the condition, like this:

    ~ # initctl debug
    ~ # initctl cond set net/vlan1/exist

Then watch the console for the debug messages and then check the output from initctl cond show again. (The client will likely have failed to start, but at least the condition is now satisfied.)

Internals

A condition is always in one of three states:

  • on (+): The condition is asserted.
  • off (-): The condition is deasserted.
  • flux (~): The conditions state is unknown.

All conditions that have not explicitly been set are interpreted as being in the off state.

When a reconfiguration is requested, Finit transitions all conditions to the flux state. As a result, services that depend on a condition are sent SIGSTOP. Once the new state of the condition is asserted, the service receives SIGCONT. If the condition is no longer satisfied the service will then be stopped, otherwise no further action is taken.

This STOP/CONT handling minimizes the number of unnecessary service restarts that would otherwise occur because a depending service was sent SIGHUP for example.

Therefore, any plugin that supplies Finit with conditions must ensure that their state is updated after each reconfiguration. This can be done by binding to the HOOK_SVC_RECONF hook. For an example of how to do this, see plugins/pidfile.c.