s6-rc
Software
skarnet.org
The s6-rc-update program
s6-rc-update is an online service database switcher:
it will replace your compiled service database with another
one, and adjust the live state accordingly. This allows you to
change your set of services without having to reboot.
Live upgrading a service database is not easy, and no
fully automated system can get it right in all cases.
s6-rc-update will do its best on its own, but it lets the user
give it instructions to handle
difficult cases; and rather than implement doubtful
heuristics, it will fail with an error message in
situations it cannot solve.
Interface
s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] [ -f convfile ] newdb
- s6-rc-update analyzes the current live state, the current compiled service
database, and the compiled service database contained at newdb
(which must be an absolute path).
- Additionally, it can process an optional conversion file containing
instructions.
- It computes the necessary service transitions to safely update the live
database.
- It shuts down the necessary services.
- It updates the live directory so that newdb becomes the
live compiled service database.
- It starts up the necessary services.
Exit codes
- 0: success
- 1: failure to perform some state transitions
- 2: timed out
- 3: unknown service name in the conversion file
- 4: invalid service database
- 5: wrong service type in the conversion file
- 6: duplicate service in the conversion file
- 100: wrong usage
- 111: system call failed
Options
- -n : dry run. s6-rc-update will compute the service
transitions, and print the s6-rc command lines
it would execute to perform those transitions. It will not actually
run them or modify the live database.
- -v verbosity : be more or less
verbose. Default is 1: warning and error messages will be printed to
stderr. 0 silences warnings. 2 adds a bit more information about
what s6-rc-update is doing. 3 or more is heavy debug output.
- -t timeout : if s6-rc-update cannot
perform its job within timeout milliseconds, it will exit.
The default is 0, meaning infinite (no timeout). Be aware that timing
out and exiting may leave the live database in an inconsistent state,
so use of this option is not recommended.
- -l live : look for the
live state in live. It must be an absolute path.
Default is /run/s6-rc.
The default can be changed at compile-time by giving the
--livedir=live option to ./configure.
- -f convfile : use the conversion
file located at convfile. Default is /dev/null,
meaning no special instructions.
Transition details
s6-rc-update's job is to ensure consistency of the live state across
a change of compiled service databases. To do so, it must make sure
that the services that are up at the time of its invocation are still
up after its invocation; but service definitions in the new compiled
may be different from those in the old one - in particular, dependencies
may change, or a service can change types: a oneshot can become
a longrun and vice-versa, and an atomic service can even become a
bundle.
Service identity
s6-rc-update examines atomic services, as defined in the old compiled,
that are up at invocation time, and computes what is necessary for the
"same" service, as defined in the new compiled, to be up. Barring
instructions from the conversion file, the service is "the same" if it has the
same name in the new compiled, no matter its type.
So, if there is an up oneshot named sshd in the old compiled,
and there is a longrun named sshd in the new compiled, then
s6-rc-update will decide that the new sshd longrun will replace
the old sshd oneshot. If the new compiled defines a sshd
bundle instead, then s6-rc-update will decide that the old sshd
oneshot will be replaced with the contents of the sshd bundle.
Restarts
s6-rc-update tries to avoid needlessly restarting services. For instance,
running it with a new compiled that is an exact copy of
the old compiled should not cause any restarts. s6-rc-update will flag a
service to be restarted in the following cases:
- The service has disappeared in the new compiled. In this case, the
old service will simply be stopped.
- The service has changed types: a oneshot becomes a longrun, a longrun
becomes a oneshot, or an atomic service becomes a bundle. In this case, the
old service will be stopped, then the new service will be started.
- The service has a dependency to a service that must restart, or to an
old service that must stop, or to a new service that did not previously
exist or that was previously down.
- There is an instruction to restart the service in the conversion file.
Steps
After it has decided what services it should restart, s6-rc-update will:
- Invoke s6-rc to stop old services.
- Update the live directory with the data from the new compiled.
This is the critical part; s6-rc should not be interrupted at this point.
It does its best to avoid risking leaving behind an inconsistent state,
but a 100% atomicity guarantee is impossible to achieve.
- Adjust pipe names for the existing pipelines, if needed.
- Exec into s6-rc to start new services.
The conversion file
The conversion file is used to give s6-rc-update instructions when the
change of databases is not entirely straightforward. Currently, it
supports the following features:
- changing the name of a service
- forcing a restart on a service
Format
The conversion file is a sequence of lines; each line is parsed
independently, there's no carrying of information from one line to
the next.
A line is lexed into words by the
execlineb
lexer, which means that words are normally separated by whitespace, but
can be quoted, that # comments are recognized, etc.
The first word in a line must be the name of an "old" atomic service, i.e.
an atomic service contained in the current live database. The remaining
words in the line are instructions telling s6-rc-update how to convert
that service.
Renaming
If the second word in the line is ->, then the third word in the
line must be the new name of the service in the new database: s6-rc-update
will then rename it. It is possible
to rename an atomic service to another atomic service or a bundle, but no
matter whether a service is renamed or not, changing its type will force a
restart.
ps output as supervising the old name. This is purely cosmetic and
will have no impact on the service; nevertheless, if you wish to avoid that,
simply force a restart on every service you rename.
Restarting
If the word following either the old name, or a renaming instruction, is the
word restart, then the service will forced to restart.
Examples
Consider the following conversion file:
# Simple conversion file
mount-var -> mount-rwfs
httpd restart
sqld -> mysqld restart
- It will rename mount-var to mount-rwfs, not restarting it
if mount-var in the old database and mount-rwfs in the new
database have the same type and do not depend on services that would force a
restart.
- It will restart httpd
- It will rename sqld to mysqld and make it restart.
Notes
- The live argument to the -l option, if present, should
be the same argument that was given to the
s6-rc-init invocation when the system was
booted. In other words: it should be the name of the symbolic link pointing
to the real directory containing the live information, not the name of the
real directory.
- If a longrun service is renamed from oldname to newname,
but not restarted, the
s6-supervise
process in charge of it will still show up in the process list as
s6-supervise oldname. This is purely cosmetic and
will have no impact on the service; nevertheless, if you wish to avoid that,
simply force a restart on every longrun you rename.
- After a s6-rc-update invocation, the old compiled service database
is left unchanged where it was, and the new compiled
service database is used in-place. If the machine is rebooted, the
s6-rc-init invocation will still boot on the
old compiled unless more work is performed. It is recommended to keep a
current symbolic link to the current compiled, to always
s6-rc-init on current, and to
make current a link to the new compiled right after a s6-rc-update
invocation.