Hi… I am well aware that this diff view is very suboptimal. It will be fixed when the refactored server comes along!
Add blubline and acks
# Linit — Lindenii init system and service manager
Partially inspired by [Dinit](https://github.com/davmac314/dinit).
"System state is a computed function of the dependency graph rather than as a mutable imperative set of unit states."
## Concepts
* Each service configuration is called a **unit**.
* Unit names are irrelevant to daily operation.
* Units provide one or more **targets**, which are used to specify
dependencies. It is illegal to have multiple units provide duplicate targets.
* Runtime states
* A target's state is equivalent to the state of the unit that provides it.
* A unit (and therefore its targets) may have one of the following states:
* Disabled: Not required, so it's just off.
* Waiting for dependencies
* Failed: The unit failed (non-zero exit, unexpected exit, etc.)
* Starting: The unit is being started and isn't ready yet.
* Active:
* Running: The unit is working properly.
* Reloading: The unit is working properly and is currently being reloaded.
* Exited: The main process exited, but it's successful because e.g. it's
`oneshot`.
* Running (degraded): The unit is running but one or more of its (direct
or transitive) dependencies are not working (but we do not have direct
hard dependencies that aren't working which would stop us). But we're
still considered well and running; all of our dependents will be
degraded (but not stopped).
* Stopping: The unit is being stopped.
* A target in a state other than "disabled" may have a "coincidental" flag set:
because the unit that provides this target is not disabled (i.e., because
the unit provides other targets that are needed), this target is
coincidentally provided.
* Types of units
* `foreground-notified`: The unit is a supervised foreground process that
supports sd\_notify. It is considered starting until sd\_notify receives
`READY=1`. Other sd\_notify states such as `RELOADING` are also supported.
* `foreground-supervised`: The unit is a supervised foreground process. It
does not support sd\_notify and is considered active while the process is
running; if a `ready-wait` is specified, the supervisor waits that many
seconds before the unit is considered ready (only if it doesn't exit);
if `ready-grep` is specified, the standard output or standard error of the
process must have a line that matches the specified regular expression
before it's considered ready.
* `background-pidfile`: Traditional forking daemon that starts in the
foreground and forks into the background when it's ready, leaving a PID
file at a predetermined path.
* `background-scripted`: Start/stop/reload are implemented by custom scripts.
* `oneshot`: The unit is just a command run once. When it's running it's
considered "starting". It is considered "active but exited" when it exits
successfully, and it's considered "failed" when it exits unsuccessfully.
* `virtual`: Exists solely for dependency management.
* Units may have start and stop timeouts. If a unit is in the
"starting"/"stopping" states for longer than the timeout specified, it is
terminated (killed if unable to terminate), and it enters the failed state.
* There are several types of dependency relationships. All dependency
specifications use target names, not unit names.
* `depends-on` marks a hard runtime dependency. The dependent does not start
until the dependency is active. If a dependency gets out of the active
state, the dependent is stopped.
* `depends-ms` marks a startup milestone. The dependency must start
successfully before the dependent starts. Stopping the dependency later
does not automatically stop the dependent.
* `waits-for` wait for the dependency to either be active or to fail,
before the dependent is started.
Circular dependencies are illegal.
* There are no ad-hoc commands to start/stop individual services. At each point
in time, the system is given one target to satisfy, and it deterministically
finds the minimum set of units needed to satisfy that target. If you want
temporary things to run, then just make a new target that lists your typical
target as a dependency and add the new targets as dependencies.
* Typically you don't want to use depends-on in your main system target,
because when its dependency fails it would take down the entire system.
## TODOs
* Restarts, and retries after timeouts
* Transient targets to perhaps add imperative control temporarily for
debugging?
* `background-scripted` needs to be used very carefully; it's kinda necessary
for compatibility with sysvinit scripts...
* More robust crash recovery in general
* Currently all units files are read (or reloaded) upfront/together and targets
may be uniquely provided by one unit only. This is a bit limiting. Research
better ways to select which unit provides each target.
* Test\_User's comments:
* "all units that provide a target should be started (optionally in parallel)
when that target is needed; the target is considered degraded if one fails
or w/e"
* "you'd need an actual disable mechanism that's prob better than editing
dependency graphs"
## Examples
I forgot how the services below start or present readiness... these are just
conceptual examples.
Let's say you run Maddy, an email server that provides IMAP and SMTP in one
binary. It uses sd\_notify and depends on the network being online — but we
don't want to terminate it when we go offline. Note that exec-stop is typically
unnecessary as we send SIGTERM by default; we just list it here to note that
you could change it.
```
unit: maddy
type: foreground-notified
provides: imapd, smtpd
depends-ms: network-online
exec-start: /usr/bin/maddy run
exec-reload: /bin/kill -USR1 $MAINPID
exec-stop: /bin/kill -TERM $MAINPID
```
`network-online` is a virtual unit that is satisfied if and only if your DHCP
client, network interfaces, local resolver, etc., are ready.
```
unit: network-online
type: virtual
provides: network-online
depends-on: netif, dhcp, dns
```
Of course, these dependencies also need to be defined:
```
unit: dhcpcd
provides: dhcp
depends-on: netif
...
```
```
unit: netif
provides: netif
type: oneshot
exec-start: /etc/my-script-to-set-up-interfaces-with-iproute2
...
```
```
unit: unbound
provides: dns
depends-on: netif
...
```
Let's run an IRC daemon.
```
unit: inspircd
provides: ircd
depends-ms: network-online
...
```
We also have an IRC bot that connects to multiple networks. We want to wait for
our own network to be up before it begins, but if our own network fails then
just connect to other networks anyway.
```
name: irc-bot
type: foreground-notified
provides: irc-bot
depends-ms: network-online
waits-for: ircd
ready-grep: ^connected to
exec-start: /usr/local/bin/irc-bot -c /etc/irc-bot.conf
exec-reload: /bin/kill -USR1 $MAINPID
```
## Acknowledgements Partially inspired by [Dinit](https://github.com/davmac314/dinit).