Re: s6-rc design ; comparison with anopa

From: Laurent Bercot <ska-skaware_at_skarnet.org>
Date: Sat, 25 Apr 2015 03:15:31 +0200

> On that note, one thing you've apparently done/planned is auto-stopping,
> whereas there is no such thing in anopa. This is because I always felt
> like while auto-starting can be easily predictable/have expected
> behavior, things aren't the same when it comes to stopping.
>
> That is, start httpd and it will auto-start dependency php which will
> auto-start dependency sqld; fine. But I'm not sure stopping sqld should
> stop php, despite the dependency. Maybe one just wants to shut down
> sqld, not the whole webserver.

  If php depends on sqld, it means php isn't functional when sqld is down.
So, if you shut down sqld without shutting down php, your webserver will
be unreliable.
  If you really want to do that, bypass s6-rc and run
"s6-svc -d $live/servicedirs/sqld". s6-rc won't notice when you manually
down a service. You can keep it down, or manually bring back up later.

  It's a case of "if you do this, you're supposed to know what you are doing
and the tool won't try to change it behind your back".


> Then there's also the case of, imagine you start foobar & web. web is a
> bundle with httpd, php & sqld, foobar is a service w/ a dependency on sqld.
> Now you stop web; should sqld be stopped? about foobar? What is the
> expected behavior here?

  If you stop web, it means you stop httpd, php and sqld, and also foobar
since foobar depends on sqld. If you don't want to do that, don't stop web:
stop httpd and php instead. You'll keep sqld and foobar.

  Better, make a bundle web = httpd+php and web+sqld = httpd+php+sqld.
Start web+sqld, stop web. sqld and foobar are untouched.

  Bundles are great. You can define a bundle for every possible combination
of services if you're so inclined (it's still 2^n, so don't overdo it, but
yeah). Bundle resolution is fast: it's a name lookup in a directory. With
ext4, you could have a million bundle names before you'd start noticing
slowdowns in resolutions.


> I'm not sure there's one, different
> people/scenario will have different expectations... it always seemed too
> "complicated" so I went with no auto-stopping at all.

  I don't think auto-stopping is any more complex than auto-starting. It's
exactly symmetrical. The difficult part is designing the right dependency
graph, and that's a job for packagers. Yes, they will screw it up, but
please let's fix the world one step at a time.


> Just so I understand: why are you talking about smbd-log as a separate
> service, and not the logger of service smbd, as usual with s6? Or is
> that what you're referring to here with smbd-log?

  A service and its logger are defined as separate longrun services for
s6-rc. The compiler will recognize that smbd-log is a logger for smbd-run
and create the proper service directory with a log/ subdirectory, and
register "smbd-run" as the service directory for the daemon and
"smbd-run/log" as the service directory for the logger. But in the
compiled database, those are two different services.

  It makes sense, because unlike systemd, we don't want to start daemons
before their loggers are operational. And loggers are not a given: they
may depend on the oneshot service "mount /var/log", for instance. It would
be silly to have the daemon itself depend on /var/log.


> I'm not sure where you put the scandir in this? I believe "original"
> servicedirs where taken from the source and put into the compiled, and
> s6-rc will create the actual servicedirs in the scandir with s6-rc-init,
> correct? So that would be part of live?
> How about the oneshot scripts?

  s6-rc-init is supposed to run in stage 2, so it assumes there is an
operational scandir already (probably empty or almost empty). You give
the location of the scandir as an argument to s6-rc-init.
  s6-rc-init creates live, makes $live/scandir a symlink to the scandir
given in argument (so s6-rc always knows how to find it), and creates
all service directories under $live/servicedirs with down files. Then
it symlinks them all into the scandir and calls s6-svscanctl -a.

  The oneshot scripts are read-only, they don't need anything in live,
so they're a part of compiled.
  Of course, there's a $live/state file that maintains the state of
all atomic services, oneshots as well as longruns.


> Also, with anopa I wanted to fill what's missing in s6, and that
> included a full init system, so stage 1. You originally said s6-rc was
> meant to be a full init system, but now you're saying you have another
> tool/package in mind for that, s6-init. That's fine, but with anopa I
> wanted the whole thing, yes.

  Which is great! Making stage 1 more accessible is arguably more urgent
or important than managing services, but it's also harder to do in a
portable way, that's why I started working on s6-rc first. It's more or
less the only reason.


> One thing though, your compilation process only does copy servicedirs,
> or is there more (besides the whole "packing" them into a binary form
> alongside dependency graphs)?

  It actually creates service directories depending on the information
that has been given in the source. Nothing is set in stone yet. For
instance, there could be an "automatically create a basic log service
for a daemon, reading the log user and the logdir from the source"
feature. There will be annotations in the source for s6-rc-update.
Oneshot "start" and "stop" scripts are preprocessed (by the execline
parser) so they're stored in command-line form in the compiled.
(To write a start script in shell: /bin/sh -c "script" is easy
enough.)

  I'm open to other suggestions.


> What I like with aa-enable is that servicedirs are created from a source
> servicedir and some config data. So one can have a single openvpn_at_
> source servicedir, and use it to create different servicedirs with
> different configs. There's also the bits to easily use the same logger,
> but also service-specific log script...

  s6-rc-compile actually generates the servicedirs from the source data,
which isn't exactly a servicedir - it contains run and finish scripts,
but also additional information. I haven't settled on a format yet, if
for instance instantiability is important I'll think about supporting it.
I need to make the s6-rc-compile engine extensible so future additions
are easy and clean.


> Right. I haven't thought about this that much, but my general feeling is
> that I'm not for auto-removing anything, so if foobar is updated and
> doesn't depend on foo anymore, but adds a new dependency on bar, adding
> & starting bar is obviously good; Removing or even stopping foo on the
> other hand, I'm not so sure.

  s6-rc-update would only stop foo if it isn't defined anymore in the new
compiled, i.e. if the package manager has removed it. There is no reason
to stop foo just because foobar doesn't depend on it anymore.


> ...it uses a longrun service to spawn things, a la s6-sudo or something?

  Ding ding ding, we have a winner!
  There's a "s6-oneshot-runner" longrun that's automatically added at
compile-time, and every oneshot depends on it. The start or stop scripts
(I mean command lines) are actually sent to the s6-oneshot-runner daemon
via s6-sudo.


> But what happens if two oneshots started/running in parallel both want
> user input? How does that work in a manner that isn't confusing/unclear?
> Yeah the pipe is used so aa-start will process all password inputs
> sequentially, and the user will always know where she's typing because
> (as for regular output) the prompt is prefixed with the service name.

  Ah, it's for sequentialization. Good point, I hadn't thought of that.

(You could just use the standard controlling terminal rule: if a member
of a background process group tries to use the terminal, it will be
stopped via SIGTTIN/SIGTTOU. It's just a matter of sending a SIGCONT
to the group when you're done. However, process group and session
management are one of the hairier parts of Unix (rule: if it involves
a terminal, it sucks) and I totally understand that you want no part
of it.)


> The wants dependencies are just a way to pull a service without failing
> if that service fails to start, some sort of "optional dependency" I guess.
> E.g. one could say that php only wants sqld, so even if the later can't
> be started the website can work, and everything that doesn't need db
> will work, the rest failing with db connection errors, instead of having
> no website at all.

  I see. With s6-rc, you would just make a "web" bundle, containing "httpd"
and "php", and a "web+sqld" bundle, containing "web" and "sqld". You would
launch web+sqld, and even if sqld fails, httpd and php are still brought up.


> Separating order & dependency also allows to set up some order in
> services in case, but without the need for them to be actual
> dependencies, which may also be handy for source servicedirs to plan for
> different uses/configs.

  Do you have a real-life example ? I can imagine how that can be useful,
but a dependency manager is complex enough as is, and I don't want to
add more complexity if there's no real, actual use for it that cannot
be achieved another way.


> Re: essential, the point of that file is only so that on boot, if e.g.
> no getty could be started a shell is opened, otherwise you'd have no way
> of logging in. But if it's only sqld that failed, no need for that you
> can login as usual. (Similarly on boot, if mounting root-fs fails open a
> terminal, if something else did but root-fs was mounted, no need to stop
> & open a terminal.)

  Hmmm... I think I see.
  With s6-rc, you'd delegate that to the application. Something like
  s6-rc -u getty1 || s6-rc -u debugshell; s6-rc -u myrunlevel

  and myrunlevel should not depend on getty1. I really, really do not want
to introduce disjunctions in dependencies: that would turn the simple
dependency engine into a full boolean expression evaluator, and I don't
want to code that if it can be avoided.

-- 
  Laurent
Received on Sat Apr 25 2015 - 01:15:31 UTC

This archive was generated by hypermail 2.3.0 : Sun May 09 2021 - 19:38:49 UTC