diff options
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/mdev.conf | 2 | ||||
| -rw-r--r-- | examples/var_service/README_distro_proposal.txt | 298 |
2 files changed, 300 insertions, 0 deletions
diff --git a/examples/mdev.conf b/examples/mdev.conf index 51795694d..fab1dc451 100644 --- a/examples/mdev.conf +++ b/examples/mdev.conf | |||
| @@ -34,3 +34,5 @@ fd[0-9]* 0:11 660 | |||
| 34 | 34 | ||
| 35 | sd[a-z]* 0:6 660 | 35 | sd[a-z]* 0:6 660 |
| 36 | hd[a-z]* 0:6 660 | 36 | hd[a-z]* 0:6 660 |
| 37 | |||
| 38 | hw_random 0:0 600 =hwrng | ||
diff --git a/examples/var_service/README_distro_proposal.txt b/examples/var_service/README_distro_proposal.txt new file mode 100644 index 000000000..9ba952cb4 --- /dev/null +++ b/examples/var_service/README_distro_proposal.txt | |||
| @@ -0,0 +1,298 @@ | |||
| 1 | A distro which already uses runit | ||
| 2 | |||
| 3 | I installed Void Linux, in order to see what do they have. | ||
| 4 | Xfce desktop looks fairly okay, network is up. | ||
| 5 | ps tells me they did put X, dbus, NM and udev into runsvdir-supervised tree: | ||
| 6 | |||
| 7 | 1 ? 00:00:01 runit | ||
| 8 | 623 ? 00:00:00 runsvdir | ||
| 9 | 629 ? 00:00:00 runsv | ||
| 10 | 650 tty1 00:00:00 agetty | ||
| 11 | 630 ? 00:00:00 runsv | ||
| 12 | 644 ? 00:00:09 NetworkManager | ||
| 13 | 1737 ? 00:00:00 dhclient | ||
| 14 | 631 ? 00:00:00 runsv | ||
| 15 | 639 tty4 00:00:00 agetty | ||
| 16 | 632 ? 00:00:00 runsv | ||
| 17 | 640 ? 00:00:00 sshd | ||
| 18 | 1804 ? 00:00:00 sshd | ||
| 19 | 1809 pts/3 00:00:00 sh | ||
| 20 | 1818 pts/3 00:00:00 ps | ||
| 21 | 633 ? 00:00:00 runsv | ||
| 22 | 637 tty5 00:00:00 agetty | ||
| 23 | 634 ? 00:00:00 runsv | ||
| 24 | 796 ? 00:00:00 dhclient | ||
| 25 | 635 ? 00:00:00 runsv | ||
| 26 | 649 ? 00:00:00 uuidd | ||
| 27 | 636 ? 00:00:00 runsv | ||
| 28 | 647 ? 00:00:00 acpid | ||
| 29 | 638 ? 00:00:00 runsv | ||
| 30 | 652 ? 00:00:00 console-kit-dae | ||
| 31 | 641 ? 00:00:00 runsv | ||
| 32 | 651 tty6 00:00:00 agetty | ||
| 33 | 642 ? 00:00:00 runsv | ||
| 34 | 660 tty2 00:00:00 agetty | ||
| 35 | 643 ? 00:00:00 runsv | ||
| 36 | 657 ? 00:00:02 dbus-daemon | ||
| 37 | 645 ? 00:00:00 runsv | ||
| 38 | 658 ? 00:00:00 cgmanager | ||
| 39 | 648 ? 00:00:00 runsv | ||
| 40 | 656 tty3 00:00:00 agetty | ||
| 41 | 653 ? 00:00:00 runsv | ||
| 42 | 655 ? 00:00:00 lxdm-binary | ||
| 43 | 698 tty7 00:00:14 Xorg | ||
| 44 | 729 ? 00:00:00 lxdm-session | ||
| 45 | 956 ? 00:00:00 sh | ||
| 46 | 982 ? 00:00:00 xfce4-session | ||
| 47 | 1006 ? 00:00:04 nm-applet | ||
| 48 | 654 ? 00:00:00 runsv | ||
| 49 | 659 ? 00:00:00 udevd | ||
| 50 | |||
| 51 | Here is a link to Void Linux's wiki: | ||
| 52 | |||
| 53 | https://wiki.voidlinux.eu/Runit | ||
| 54 | |||
| 55 | Void Linux packages install their services as subdirectories of /etc/rc, | ||
| 56 | such as /etc/sv/sshd, with a script file, "run", and a link | ||
| 57 | "supervise" -> /run/runit/supervise.sshd | ||
| 58 | |||
| 59 | For sshd, "run" contains: | ||
| 60 | |||
| 61 | #!/bin/sh | ||
| 62 | ssh-keygen -A >/dev/null 2>&1 # generate host keys if they don't exist | ||
| 63 | [ -r conf ] && . ./conf | ||
| 64 | exec /usr/bin/sshd -D $OPTS | ||
| 65 | |||
| 66 | That's it from the POV of the packager. | ||
| 67 | |||
| 68 | This is pretty minimalistic, and yet, it is already distro-specific: | ||
| 69 | the link to /run/runit/* is conceptually wrong, it requires packagers | ||
| 70 | to know that /etc/rc should not be mutable and thus they need to use | ||
| 71 | a different location in filesystem for supervise/ directory. | ||
| 72 | |||
| 73 | I think a good thing would be to require just one file: the "run" script. | ||
| 74 | The rest should be handled by distro tooling, not by packager. | ||
| 75 | |||
| 76 | A similar issue is arising with logging. It would be ideal if packagers | ||
| 77 | would not need to know how a particular distro manages logs. | ||
| 78 | Whatever their daemons print to stdout/stderr, should be automagically logged | ||
| 79 | in a way distro prefers. | ||
| 80 | |||
| 81 | * * * * * * * * | ||
| 82 | |||
| 83 | Proposed "standard" on how distros should use runit | ||
| 84 | |||
| 85 | The original idea of services-as-directories belongs to D.J.Bernstein (djb), | ||
| 86 | and his project to implement it is daemontools: https://cr.yp.to/daemontools.html | ||
| 87 | |||
| 88 | There are several reimplementations of daemontools: | ||
| 89 | - runit: by Gerrit Pape, http://smarden.org/runit/ | ||
| 90 | (busybox has it included) | ||
| 91 | - s6: by Laurent Bercot, http://skarnet.org/software/s6/ | ||
| 92 | |||
| 93 | |||
| 94 | It is not required that a specific clone should be used. Let evolution work. | ||
| 95 | |||
| 96 | Terminology | ||
| 97 | |||
| 98 | daemon: any long running background program. Common examples are sshd, getty, | ||
| 99 | ntpd, dhcp client... | ||
| 100 | |||
| 101 | service: daemon controlled by a service monitor. | ||
| 102 | |||
| 103 | service directory: a directory with an executable file (script) named "run" | ||
| 104 | which (usually) execs some daemon, possibly after some preparatory steps. | ||
| 105 | It should start it not as a child or daemonized process, but by exec'ing it | ||
| 106 | (inheriting the same PID and the place in the process tree). | ||
| 107 | |||
| 108 | service monitor: a tool which watches a set of service directories. | ||
| 109 | In daemontools package, it is called "svscan". In runit, it is called | ||
| 110 | "runsvdir". In s6, it is called "s6-svscan". | ||
| 111 | Service monitor starts a supervisor for each service directory. | ||
| 112 | If it dies, it restarts it. If service directory disappears, | ||
| 113 | service monitor will not be restarted if it dies. | ||
| 114 | runit's service monitor (runsvdir) sends SIGTERM to supervisors | ||
| 115 | whose directories disappeared. | ||
| 116 | |||
| 117 | supervisor: a tool which monitors one service directory. | ||
| 118 | It runs "run" script as its child. It restarts it if it dies. | ||
| 119 | It can be instructed to start/stop/signal its child. | ||
| 120 | In daemontools package, it is called "supervise". In runit, it is called | ||
| 121 | "runsv". In s6, it is called "s6-supervise". | ||
| 122 | |||
| 123 | Conceptually, a daemontools clone can be designed such that it does not *have* | ||
| 124 | the supervisor component: service monitor can directly monitor all its daemons | ||
| 125 | (for example, this may be a good idea for memory-constrained systems). | ||
| 126 | However all three existing projects (daemontools/runit/s6) do have a per-service | ||
| 127 | supervisor process. | ||
| 128 | |||
| 129 | log service: a service which is exclusively tasked with logging | ||
| 130 | the output of another service. It is implemented as log/ subdirectory | ||
| 131 | in a service directory. It has the same structure as "normal" | ||
| 132 | service dirs: it has a "run" script which starts a logging tool. | ||
| 133 | |||
| 134 | If log service exists, stdout of its "main" service is piped | ||
| 135 | to log service. Stops/restarts of either of them do not sever the pipe | ||
| 136 | between them. | ||
| 137 | |||
| 138 | If log service exists, daemontools and s6 run a pair of supervisors | ||
| 139 | (one for the daemon, one for the logger); runit runs only one supervisor | ||
| 140 | per service, which is handling both of them (presumably this is done | ||
| 141 | to use fewer processes and thus, fewer resources). | ||
| 142 | |||
| 143 | |||
| 144 | User API | ||
| 145 | |||
| 146 | "Users" of service monitoring are authors of software which has daemons. | ||
| 147 | They need to package their daemons to be installed as services at package | ||
| 148 | install time. And they need to do this for many distros. | ||
| 149 | The less distros diverge, the easier users' lives are. | ||
| 150 | |||
| 151 | System-wide service dirs reside in a distro-specific location. | ||
| 152 | The recommended location is /var/service. (However, since it is not | ||
| 153 | a mandatory location, avoid depending on it in your run scripts. | ||
| 154 | Void Linux wanted to have it somewhere in /run/*, and they solved this | ||
| 155 | by making /var/service a symlink). | ||
| 156 | |||
| 157 | The install location for service dirs is /etc/rc: | ||
| 158 | when e.g. ntpd daemon is installed, it creates the /etc/rc/ntpd | ||
| 159 | directory with (minimally) one executable file (script) named "run" | ||
| 160 | which starts ntpd daemon. It can have other files there. | ||
| 161 | |||
| 162 | At boot, distro should copy /etc/rc/* to a suitable writable | ||
| 163 | directory (common choice are /var/service, /run/service etc). | ||
| 164 | It should create log/ directories in each subdirectory | ||
| 165 | and create "run" files in them with suitable (for this particular distro) | ||
| 166 | logging tool invocation, unless this directory chose to channel | ||
| 167 | all logging from all daemons through service monitor process | ||
| 168 | and log all of them into one file/database/whatever, | ||
| 169 | in which case log/ directories should not be created. | ||
| 170 | |||
| 171 | It is allowable for a distro to directly use /etc/rc/ as the only | ||
| 172 | location of its service directories. (For example, | ||
| 173 | /var/service may be a symlink to /etc/rc). | ||
| 174 | However, it poses some problems: | ||
| 175 | |||
| 176 | (1) Supervision tools will need to write to subdirectories: | ||
| 177 | the control of running daemons is implemented via some files and fifos | ||
| 178 | in automatically created supervise/ subdirectory in each /etc/rc/DIR. | ||
| 179 | |||
| 180 | (2) Creation of a new service can race with the rescanning of /etc/rc/ | ||
| 181 | by service monitor: service monitor may see a directory with only some files | ||
| 182 | present. If it attempts to start the service in this state, all sorts | ||
| 183 | of bad things may happen. This may be worked around by various | ||
| 184 | heuristics in service monitor which give new service a few seconds | ||
| 185 | of "grace time" to be fully populated; but this is not yet | ||
| 186 | implemented in any of three packages. | ||
| 187 | This also may be worked around by creating a .dotdir (a directory | ||
| 188 | whose name starts with a dot), populating it, and then renaming; | ||
| 189 | but packaging tools usually do not have an option to do this | ||
| 190 | automatically - additional install scripting in packages will be needed. | ||
| 191 | |||
| 192 | Daemons' output file descriptors are handled somewhat awkwardly | ||
| 193 | by various daemontools implementations. For example, for runit tools, | ||
| 194 | daemons' stdout goes to wherever runsvdir's stdout was directed; | ||
| 195 | stderr goes to runsvdir, which in turn "rotates" it on its command line | ||
| 196 | (which is visible in ps output). | ||
| 197 | |||
| 198 | Hopefully this get changed/standardized; while it is not, the "run" file | ||
| 199 | should start with a | ||
| 200 | |||
| 201 | exec 2>&1 | ||
| 202 | |||
| 203 | command, making stderr equivalent to stdout. | ||
| 204 | An especially primitive service which does not want its output to be logged | ||
| 205 | with standard tools can do | ||
| 206 | |||
| 207 | exec >LOGFILE 2>&1 | ||
| 208 | |||
| 209 | or even | ||
| 210 | |||
| 211 | exec >/dev/null 2>&1 | ||
| 212 | |||
| 213 | To prevent creation of distro-specific log/ directory, a service directory | ||
| 214 | in /etc/rc can contain an empty "log" file. | ||
| 215 | |||
| 216 | |||
| 217 | Controlling daemons | ||
| 218 | |||
| 219 | The "svc" tool is available for admins and scripts to control services. | ||
| 220 | In particular, often one service needs to control another: | ||
| 221 | e.g. ifplugd can detect that the network cable was just plugged in, | ||
| 222 | and it needs to (re)start DHCP service for this network device. | ||
| 223 | |||
| 224 | The name of this tool is not standard either, which is an obvious problem. | ||
| 225 | I propose to fix this by implementing a tool with fixed name and API by all | ||
| 226 | daemontools clones. Lets use original daemontools name and API. Thus: | ||
| 227 | |||
| 228 | The following form must work: | ||
| 229 | |||
| 230 | svc -udopchaitkx DIR | ||
| 231 | |||
| 232 | Options map to up/down/once/STOP/CONT/HUP/ALRM/INT/TERM/KILL/exit | ||
| 233 | commands to the daemon being controlled. | ||
| 234 | |||
| 235 | The form with one option letter must work. If multiple-option form | ||
| 236 | is supported, there is no guarantee in which order they take effect: | ||
| 237 | svc -it DIR can deliver TERM and INT in any order. | ||
| 238 | |||
| 239 | If more than one DIR can be specified (which is not a requirement), | ||
| 240 | there is no guarantee in which order commands are sent to them. | ||
| 241 | |||
| 242 | If DIR has no slash and is not "." or "..", it is assumed to be | ||
| 243 | relative to the system-wide service directory. | ||
| 244 | |||
| 245 | [Currently, "svc" exists only in daemontools and in busybox. | ||
| 246 | This proposal asks developers of other daemontools implementations | ||
| 247 | to add "svc" command to their projects] | ||
| 248 | |||
| 249 | The "svok DIR" tool exits 0 if service is running, and nonzero if not. | ||
| 250 | |||
| 251 | Other tools with different names and APIs may exist; however | ||
| 252 | for portability scripts should use the above tools. | ||
| 253 | |||
| 254 | Creation of a new service on a running system should be done atomically. | ||
| 255 | To this end, first create and populate a new /etc/rc/DIR. | ||
| 256 | |||
| 257 | Then "activate" it by running ??????? - this copies (or symlinks, | ||
| 258 | depending on the distro) its files to the "live" service directory, | ||
| 259 | wherever it is located on this distro. | ||
| 260 | |||
| 261 | Removal of the service should be done as follows: | ||
| 262 | svc -d DIR [DIR/log], then remove the service directory: | ||
| 263 | this makes service monitor SIGTERM per-directory supervisors | ||
| 264 | (if they exist in the implementation). | ||
| 265 | |||
| 266 | |||
| 267 | Implementation details | ||
| 268 | |||
| 269 | Top-level service monitor program name is not standardized | ||
| 270 | [svscan, runsvdir, s6-svscan ...] - it does not need to be, | ||
| 271 | as far as daemon packagers are concerned. | ||
| 272 | |||
| 273 | It may run one per-directory supervisor, or two supervisors | ||
| 274 | (one for DIR/ and one for DIR/log/); for memory-constrained systems | ||
| 275 | an implementation is possible which itself controls all services, without | ||
| 276 | intermediate supervisors. | ||
| 277 | [runsvdir runs one "runsv DIR" per DIR, runsv handles DIR/log/ if that exists] | ||
| 278 | [svscan runs a pair of "supervise DIR" and "supervise DIR/log"] | ||
| 279 | |||
| 280 | Directories are remembered by device+inode numbers, not names. Renaming a directory | ||
| 281 | does not affect the running service (unless it is renamed to a .dotdir). | ||
| 282 | |||
| 283 | Removal (or .dotdiring) of a directory sends SIGTERM to any running services. | ||
| 284 | |||
| 285 | Standard output of non-logged services goes to standard output of service monitor. | ||
| 286 | Standard output of logger services goes to standard output of service monitor. | ||
| 287 | Standard error of them always goes to standard error of service monitor. | ||
| 288 | |||
| 289 | If you want to log standard error of your logged service along with its stdout, use | ||
| 290 | "exec 2>&1" in the beginning of your "run" script. | ||
| 291 | |||
| 292 | Whether stdout/stderr of service monitor is discarded (>/dev/null) | ||
| 293 | or logged in some way is system-dependent. | ||
| 294 | |||
| 295 | |||
| 296 | Containers | ||
| 297 | |||
| 298 | [What do containers need?] | ||
