[stapelberg]: Hi! So first of all, the type of this lecture
is that it's going to be a workshop, just to make the expectations
clear, I have a few slides prepared that
should give you a general introduction
and they will take
probably about half of the time we have allocated
for this slot, and afterwards
we can answer your questions
or have some hands-down hacking
on actual packages.
My name is Michael Stapelberg
Just a quick show of hands so that I know my audience --
who of you maintains a Debian package
in Debian or derivatives?
OK, that's almost everybody
Perfect.
How many of you actually added
systemd support to their packages already?
OK, a couple.
Who of you are looking into doing that?
OK, perfect! You are exactly the right audience.
Great. So the topics I want to cover with my slides are:
First of all, how systemd works for package maintainers Great. So the topics I want to cover with my slides are:
First of all, how systemd works for package maintainers
That means I'm not going to cover all of it First of all, how systemd works for package maintainers
That means I'm not going to cover all of it
And also it's not so much of a user standpoint
but just what you need to know to get you started on testing your stuff in systemd.
We will then have a look at an example service file
where we'll make clear what all the different directives are supposed to mean
We will look at the tmpfiles mechanism
and at dh-systemd, a debhelper plugin
We will consider a few more advanced examples, and then finally we will
answer your questions, hopefully.
So, non-topics for this presentation are:
systemd sucks, let's just use something else instead
When will debian ever finally switch the default, and essentially anything that ever came up on debian-devel. I'm not going to talk about that.
This is just about how to make it work if you have already accepted that this is something that you want to do.
So, how does systemd work?
Essentially, where we previously had initscripts, we now have service files.
Service files are just a special kind of unit files
so the more generic term is unit files and that which corresponds to an initscript is a service file.
So previously, you would have /etc/init.d/apache2 as an initscript
and the corresponding file would be /lib/systemd/system/apache2.service
Now what's important here to notice
Is that the base name (apart from the .service suffix)
needs to be the same, because what will happen is that
systemd, when booting on a machine
will look at all the services in /etc/init.d
and use them if they are available
but if there is also a service file, that will take precedence.
So in order to make sure that systemd uses your service file and not
your service file plus the old initscript, make sure that the name is correct.
Before you ask, yes there are also mechanisms to make sure that
when you have a name transition, because you've adopted the upstream name for a service file
or something like that, then you can have a compatibility symlink.
We can cover that later.
And essentially, systemctl does what service did.
So if you had service apache2 start
Then you would use systemctl start apache2.service
In recent versions, you can even skip the .service suffix so it would just be systemctl start apache2
The systemctl tool is mostly for the actual users, or for you when testing.
and just like you would usually use /etc/init.d/apache2 start as an actual user
but "service" inside your maintenance script, we have something for that.
Now, what we had in SystemV init were runlevels
and they were poorly defined and different from distribution to distribution
And what systemd does to replace them is that it has something called a target.
A target is precisely the same as a runlevel
it just has a much nicer name
and the names are standardized between all the different distributions.
The most important targets for you are basic.target, multi-user.target and graphical.target
Each of them is more specific than the other
in that it starts more services for a particular use case
So basic.target is what everybody of you will run
and then multi-user.target extends basic.target with more stuff
and graphical.target brings in all the graphical components like a display manager
and stuff that you would normally not use on servers where multi-user.target is what you would want to use.
You can look that up if you care later on in the manpage systemd.special.
Just as previously, with SystemV init
we had symlinks to enable a service
and these symlinks were created by update-rc.d
we still have symlinks to enable a service
now they're just created by systemctl enable
Again, systemctl is what you would use as a user, or while testing, etc.
And we have a maintainer script equivalent of that.
Are there any questions so far? This is really the basic stuff.
[question]: What is the reason there are different commands for the user and the maintainer scripts?
[stapelberg]: I think will go into this later, but I can just briefly explain it
The maintainer scripts also need to work on machines where systemd is not actually installed. [stapelberg]: I think will go into this later, but I can just briefly explain it
The maintainer scripts also need to work on machines where systemd is not actually installed.
So that's why we can't use systemctl.
Alright, let's look at an example service file.
I just picked vnstat.service
which is a tiny daemon that will just store (and plot later on) your network traffic.
What you can see here is a very clear, human-readable configuration file
And this is the service file. it's called vnstat.service.
It starts with a [Unit] section, and you can see
just like inifiles, which probably everybody of you is comfortable with
or .desktop files, which have the same format, so this is actually a .desktop file.
There are sections which are enclosed in square brackets, and then there's key/value pairs
separated by an equals sign, so that's really simple.
The first section is entirely just for humans.
So the description will tell me what kind of service this is, if I'm looking at my system and wondering what is this that's starting up here.
The second section is the [Service] section, and this is actually where
all the relevant stuff is.
What we specify here in the second line is ExecStart, which is
the command that systemd will run when trying to start that service.
In this case, it's really simple, you just start the vnstatd binary.
What you need to notice here though is that systemd does not invoke a shell to start it up,
so you need to specify the full path, and you don't have your usual
shell stuff in your command line, so just keep that in mind.
We also have the ExecReload line, and there could also be an ExecStop line.
In the absence of an ExecStop line, systemd will just kill the service
And it will do what many many people implemented in initscripts by hand
which is to gently try to kill it, and if that doesn't work within a certain timespan
then it will try to kill it harder, until it finally succeeds.
The ExecReload line is pretty standard
the thing is that not all of the services provide a way of reloading in the first place
so we need to have such a line to tell systemd what to do on a reload command
Some other service (you could probably think of the bind nameserver)
have a different way of reloading (so you could call "rndc reload" in that case)
but this one is really simple, it just sends SIGHUP to the service, and then it will reload.
the $MAINPID is not actually a shell variable or anything
it's just a special thing that you can use in unit files and service files in particular.
And then we also have the User= line which will specify
under which user this program will be started. That's pretty straightforward.
The last section is also interesting
it's called the [Install] section, and it has a line called
WantedBy=multi-user.target
And that essentially says that when this service file
is enabled on the machine
it will be pulled in by multi-user.target, so this specifies
which runlevel it runs in, so to say.
Are there any questions so far?
yes -- microphone?
[question]: can there be more than one WantedBy= line?
[stapelberg]: Yes, there can be multiple WantedBy= lines.
More questions -- over there?
[question]: So just to make sure that I understand correctly
If systemd tries to restart or reload a service
it first executes this reload phrase, and then it execs
the start phrase again?
[stapelberg]: No, there's two different cases here. One is the reload case
and the other one is the restart case.
In the reload case, it just executes what's specified here
If the service file supports reloading; if it doesn't, then you can't reload it.
If you do a restart, it will
first execute stop if present, or kill it if not present, and then start it again.
[question]: Fine. OK, thank you. first execute stop if present, or kill it if not present, and then start it again.
[stapelberg]: one more question here? [question]: Fine. OK, thank you.
[stapelberg]: one more question here?
[question]: Is there an equivalent to debian's force-reload,
where you care so much about wanting it to reload that you're OK with it falling back to stop and start if necessary?
which debian's sysvinit system does support in the usual skeleton file.
[stapelberg]: I think there is a try-reload action, but I would have to confirm that. We can do that later.
[question]: Is there also something to stop a service?
[stapelberg]: Yes, I already mentioned that you can specify ExecStop=, and if you don't, it will just kill it.
[question]: Sorry, I didn't hear that.
[stapelberg]: one more question here?
[question, quoting from a man page]: "tries to reload if possible and falls back to restart"
[stapelberg]: He just said there's a "reload-or-restart" command in systemctl that does precisely what you asked for.
[question]: Are there other things than start, reload, stop, and ... can you define other things?
[stapelberg]: Can you clarify what you mean by that?
[question]: For example, status, or I was thinking more about something specific to a certain daemon?
For instance, fetchmail can have an "awaken" option
it does a sleep of 5 minutes or something, and you can say "check right now"
[stapelberg]: What exactly is the question? I still don't get it.
[question]: Can you have some exec line in there --
[stapelberg]: -- Oh, can we have a custom action, like in initscripts, is that what you mean? No, we can't.
There are different ways of coping with that:
Most often there's an alternative to what you want to do
But I think it's really clean and nice that they standardized on a few verbs, and all of these work with all of the services
(except for the reload one, obviously)
but you can't have really custom weird stuff.
You could ship that in an additional shell script. That's what I would usually use as a first suggestion
if there's no specific, no better way of solving the problem. But we can discuss that later on.
for specific services that you might have in mind.
Any more general questions up until here?
[question]: Maybe you answered and I missed it, but about the possibility of querying the status of the service?
[stapelberg]: Yes, obviously. As I said, I will show that in the second part.
Now, tmpfiles:
The tmpfiles mechanism is really useful not only within systemd
but also oftentimes when people read about it they think "hey, this could be useful standalone."
What it does, is it provides a mechanism to configure creating temporary directories, like runtime directories.
As a really simple example, I have here the lighttpd configuration file
where we will essentially say "create a directory called /run/lighttpd"
with this mode, this user, this group, and no more arguments.
There are some arguments you could specify there, for cleaning it up every ten days or some delay like that
that's all supported. This mechanism is much more powerful than this very simple example.
it can also support not only directories, but also files, pipes, symlinks, etc.
I don't want to go into all of the details, but this is the preferred mechanism to create a /run/something
and it's much much cleaner than having all these varying mkdir commands
that sometimes specify a user and a group and sometimes they don't and then they don't have a mode, etc. etc.
So this is what we want to use. Question?
[question]: There's no implicit conflict with other things, so I have to take care to do a proper namespace organization?
and, for example, call my temporary directory like my service and not
choose an arbitrary name which would perhaps clash with another service?
[stapelberg]: Sure. I mean obviously you need to watch out for filesystem clashes in debian packages.
That's just as it always has been.
[question]: So it's the mechanism, you have to provide the policy.
[stapelberg]: Yes, obviously.
Alright -- service file location:
oftentimes, the upstream provider ships a service file, and that's the way it's meant to be.
because the upstream should know best how to install the service on a particular machine
Now, that doesn't always happen
but if it happens please use the upstream service file
and if the upstream file is really broken, please work with upstream to fix it
If it's broken in some minor detail, you might ask upstream
if it's acceptable to change it in the way that it would be better
I don't have any specific details; one example that would come to mind is that some
upstream service files are actually pretty old -- like they were written in 2009 or something
and by now they're, for example, referring to syslog.target as a dependency
whereas syslog is autostarted nowadays by socket activation.
So that could be removed, and then the service file would be simpler
and more idiomatic, and that would be a typical change that you could push upstream
I don't say that I expect any of you to know what the idiomatic service files
are, and contribute that upstream; I'm just saying that it would be the right thing to do.
Question?
[question]: So you say just write the debian/packagename.service and .tmpfiles
but most debhelpers also accept just debian/service and, just the type of the file
without the package prefix if there's only one binary package -- is that supported?
[stapelberg]: To be honest, I didn't test it, but i'm using the exact same debhelper plugin code
that all the others are using, so I would expect it to be supported.
What we also support, even though I didn't actually program it
is "package.(and then some actual package name)" if it's only for a specific package in a set of all packages
[ed: he means sourcepackgename.binarypackagename.service] is "package.(and then some actual package name)" if it's only for a specific package in a set of all packages
which is a typical debhelper feature in that sense. [ed: he means sourcepackgename.binarypackagename.service]
which is a typical debhelper feature in that sense.
[question]: Thanks!
[stapelberg]: Sure. [question]: Thanks!
[stapelberg]: Sure.
Now, to actually cover that point, if upstream actually doesn't ship a service file and/or a tmpfile
then you can just place them in debian/$yourpackagename.service and debian/$yourpackagename.tmpfile and it will be installed.
It will be installed by dh_installinit, which might confuse you
because dh_installinit is for initscripts and not for servicefiles
and in fact, we by now have dh_systemd, so that's weird!
The only reason why that is is because of historic reasons. and in fact, we by now have dh_systemd, so that's weird!
The only reason why that is is because of historic reasons.
We first started implementing it in dh_installinit,
but then it turned out that it would make the helper very complex and weird We first started implementing it in dh_installinit,
but then it turned out that it would make the helper very complex and weird
and handling upstart and sysv and systemd all at the same time is really not a good idea but then it turned out that it would make dhelper very complex and weird
and handling upstart and sysv and systemd all at the same time is really not a good idea
So we decided to leave it there for the time being, but eventually to migrate it
If you use just the dh command it will all just work, you don't have to care
In all the other cases, currently policy dictates that you still need to ship an initscript
so that's all fine, and as soon as policy gets changed, I promise that we will be in a state where you don't have to care about this either.
I already mentioned to please send service files upstream, but I'll just stress it again.
Not only if you have an upstream service file and modify it and fix it, please send it upstream
but also, if you create a service file, please send it upstream so that upstream can distribute it.
Some upstream software might not agree; some are actually very thankful.
Question over there
[question]: Assuming upstream ships a valid service file, what's the best practice:
Is it to call dh_installinit specifying the path in the upstream directory,
or copying it into the debian directory before dh_installinit is invoked? Is it to call dh_installinit specifying the path in the upstream directory,
or copying it into the debian directory before dh_installinit is invoked?
[stapelberg]: In case upstream installs it, just let upstream install it. I'm not sure I get the question.
[question]: The question is: in case upstream does not install it; they ship it, but they do not install it?
[stapelberg]: OK, in case they don't install it, and then what is the second part of your question? just put it in debian/ as I explained.
[question]: So you can put it manually in debian/ before dh_installinit is invoked.
Or you can invoke dh_installinit with the path from the upstream directory
[stapelberg]: Oh, right, yes. Or you can invoke dh_installinit with the path from the upstream directory
So if upstream doesn't install it, but ship it
[question]: Yes. So if upstream doesn't install it, but ship it
[stapelberg]: Yeah, you could either manually copy it before, or just use what you suggest. [question]: Yes.
[stapelberg]: Yeah, you could either manually copy it before, or just use what you suggest.
Any more questions?
Great, let's move on.
Getting your service enabled: I already mentioned that just as with update-rc.d you need to enable services
and the easiest way, if you already have a service file shipped by upstream
or if you put your own service file into debian/package.service
is you add a build dependency on dh-systemd
and then you use the dh command, which you hopefully already use
and add the --with=systemd flag
and then all automatically happens and it will just work.
The maintainer scripts that are generated
as part of that package build will contain the appropriate code
they will call a binary called deb-systemd-helper instead of systemctl as I mentioned earlier
which avoids having a dependency on systemd on all the packages which is probably politically not a good move.
If you are not using dh, you can also add the dh_systemd_enable and dh_systemd_start calls directly
in the wiki we have instructions, and the link is provided on these slides.
To test your package -- oh, a question here?
[question]: So you mentioned the deb-systemd-helper maintainer scripts
I know the scope of systemd is broader than sysvinit, but
in the sysvinit world, policy recommends
whether or not you are using sysvinit, including other things like sysvrc or openrc or a few of the other minor ones
(and I think also upstart) they recommend
using invoke-rc.d and update-rc.d in debian maintainer scripts as a way of
both abstracting from the specific system and for
handling the case where you're debootstrapping and the daemons are not running because of policy-rc.d
so the question is: why this instead of those
and if policy-rc.d is configured to not start or stop, will this respect that?
[stapelberg]: We have another of these helpers called deb-systemd-invoke which is for the invoke-rc.d part
and it will try to respect policy. Unfortunately, policy is really hard
It's a really horrible standard -- it's underdocumented and I had a really hard time figuring out how it works
so it will support the use cases I could identify
and if you have use cases that are broken please talk to me and we can try to fix it
Also, to answer the first part of your question, update-rc.d is really hard to have a good solution in there
we tried implementing it in there, but it turned out to not work that well, and upstream is not that responsive to our concerns.
so we actually chose to implement a separate helper that we have under tight control and can release independently of sysvrc
which turned out to be a much better solution because we already refactored it once and iterated on it
quite a few times, and by now it's actually in a pretty good state.
So that's why.
Alright! So, to test your package, which is actually the most interesting part
you will just install systemd, and then you can boot with the init=/bin/systemd kernel parameter
Installing systemd does not involve breaking sysvinit or anything
there's no conflicts in that package, you can still have both of them.
If you just install systemd, nothing will happen.
If you boot with init=/bin/systemd, you will actually use systemd
so that distinction is important. You can always switch back and forth.
So testing it is really simple. you just reboot.
You could reboot in a vm if you don't like to reboot your main machine.
Then what you would typically do is you check that your service starts properly on boot
You would probably check the reload action, check stop, start, restart, and that's about it, I would say.
because there's really not that much more to it, except if your service makes use of really advanced features and all that stuff.
In general, I would say that your users will report bug reports if your service does not work with systemd right now
There are plenty of users of systemd and debian that care enough to submit bug reports.
So it's not expected of you to test it all the time
and convert all your systems and run it all the time; a brief test will be enough.
Now to an advanced example:
There's actually a few more features that were maybe already mentioned if you listened to the previous talk by Lennart
We have a nice service called debian codesearch which I happen to maintain
And the service file is actually much more complicated.
It not only specifies a user and a group
It also has some arguments in here, and you can see that
the service file format supports line wrapping, so if your command line is pretty long
then it might make sense to wrap it and have it really nice.
Also, we have standard output redirected to /dev/null because it's really noisy
and mostly used for debugging. so when I feel like debugging, I can just change that to get standard output
but in the default case I just want standard error
Now also, my service does not actually care to log to syslog, so I say that standard error should go to the journal
which will then end up in the syslog.
Also, I cannot obviously exclude that there are bugs, but I also cannot sit in front of a computer 24/7 and restart my server if it crashes
So what I want is that whenever it fails (that is, it exits with an exit code that is not 0)
I want it to just wait a second and then restart it.
So far I think in production I only restarted my servers once
and then promptly fixed the bug so most of the time it's perfect, but you know: better safe than sorry!
The other parts of the unit file are probably clear by now
and what you will see in practice is that most of the service files really look
kind of the same. It's pretty simple, they're pretty short
they all use the same features.
One more interesting feature that you should be aware of
Who of you -- show of hands -- maintains a package that ships a dbus service?
one or two? OK
For the others, this is more of an academic interest
but systemd can actually care about dbus-activated services
so whereas dbus usually would start on its own in older versions
nowadays it's better to use systemd for it
because then it all ends up in the same hierarchy and it all gets tracked and you get all the benefits and stuff
so what you do is you add Type=dbus and you specify the BusName
and you don't have an [Install] section -- it's not missing on the slide, it's just not there.
and then systemd will activate that service whenever that bus name is actually accessed.
This is a more advanced example of the dh_systemd debhelper plugin
what we do here is we install a service that should not actually be installed by default.
and the way we do this is we override the dh_systemd_enable target and specify the --no-enable flag
This should not be a surprise to any of you who has been using debhelper in the past
I just wanted to mention it and make sure that you understand what the options are here.
-- I will answer that in a second --
The second example here is for the second part of the dh_systemd debhelper plugin
It's dh_systemd_start
and what I specify here is the --restart-after-upgrade flag which will make sure that the package does not get stopped
then replaced then started, but will just get replaced and then restarted afterward
which is kind of cleaner, but the package needs to support it. Question?
[question]: Why do you call the dh_systemd_enable with an option of --no-enable
instead of just leaving the target empty?
[stapelberg]: That's an excellent question, and the comment above tries to somewhat explain it
The thing is that when you purge the package
if the user decided to enable it even though you ship it disabled by default
then you need to clean up the symlinks
So that's what dh_systemd_enable also generates maintainer scripts for
So that still needs to run, so we can't just skip it.
In the first version we tried, but it didn't work out.
More questions?
In the back?
[question]: You mentioned services triggered by dbus actions
[stapelberg]: Yes
[question]: Is there a way to disable them even if the service is installed?
[stapelberg]: Yes, you can mask any service. I can show you that later.
One more question?
[question]: So you say --restart-after-upgrade; how does restart -- I guess this is more general, but it's prompted by this
how does restart work if the service is not running?
[stapelberg]: That's a good question. I would have to really look it up.
I think there is a try-restart action
that would restart if it's running
but not start it if it's not running
[question]: For example, in this case you set up the service to
remain disabled upon install in this example
so if you install the package it is not enabled
Then the user takes no action so if you install the package it is not enabled
Then the user takes no action
and then they upgrade their system
and a new version of the package is installed, it tries to restart?
[stapelberg]: The thing is, as I was saying, there is a restart action in systemctl and there is a try-restart
The difference is try-restart will only restart it if it's running, which probably answers your question
The caveat is that
currently, if you maintain a package that ships
a system V initscript and a systemd service file, it will still use invoke-rc.d for the actual starting/restarting etc.
And the invoke-rc.d actually has code to divert that to systemd
but the problem is it's not flexible enough to use try-restart and the fancy stuff
so this might need some actual hand-tweaking or just ignoring it for now.
Alright! So before we enter the questions and hands-on part of this workshop
I just want to make sure that you're all aware that we will provide help
There is a wiki page which is linked here called https://wiki.debian.org/Systemd/Packaging
which contains most of the information hopefully, or at least pointers
We have an irc channel on irc.debian.org called #debian-systemd
where you can just stop by at any time
Most of the time there's somebody around who actually knows how to write service files and stuff
There is a mailing list that we are all active and we really do mean it
Please ask! Also, during debconf, if there is at any time any questions
from any of you or from your friends
please ask. we're here for answering these sorts of questions.
Now just one more quick note: finding documentation
There are manpages -- a lot of manpages
They are roughly categorized by the sections I previously showed in service files
So there's a systemd.service, there's a systemd.exec, etc.
There's also an overview on the freedesktop.org web site (http://www.freedesktop.org/wiki/Software/systemd/) where it points to all the documentation
The particularly interesting parts of that are the systemd for administrators blog series
where Lennart talks about a lot of features that are interesting and how to actually make use of them in your service files
And then there's a link for package repositories for the various distributions
where you can just look if there already is a service file for that particular package that you maintain
even though it doesn't ship one upstream
So the best thing in that case would also be to adopt the service file and then also make upstream accept that.
Alright! That's the talk part so far. Now I'm ready to answer any questions or look at any packages
[question]: What are the plans for backports?
I mean if you want to make backports to wheezy, can we use the dh_systemd helper?
[stapelberg]: Yes, the dh_systemd helper is available in wheezy backports
Be aware that the systemd version in wheezy is version 44, and we're currently trying to get version 204, which is much more recent
into debian -- it had a version jump because of udev.
So it's not that much more recent, it's just more recent.
So there might be issues and it's up to you if you decide to commit to maintaining support
for that old systemd version with your service files in wheezy, just so you know.
If there is no immediate question, I would just go on to show you a little bit of stuff and we can answer questions as we go
[question]: I have to prepend that at the moment I'm not maintaining any package that has to start daemons at poweron
So I know nearly nothing about it.
But I am a bit confused. Since I understand there are a lot of these kind of systems
systemd, sysvinit, and so on
As a package maintainer, what do I have to do
if I want to support all of them, I have to provide
the script or description file that they need for each of them
[stapelberg]: -- to answer this, the policy mandates -- the script or description file that they need for each of them
[stapelberg]: -- to answer this, the policy mandates --
[question]: For example, just to complete the question, in particular if we consider just sysvinit, it is one that we have [stapelberg]: -- to answer this, the policy mandates --
[question]: For example, just to complete the question, in particular if we consider just sysvinit, it is one that we have
by default, and systemd, which we are discussing now
If I want to provide a systemd information file
Do I also have to provide a sysvinit scripts
or is there some compatibility layer that enables me to write one thing
and (at least in common cases) expect some magic to make it work for other systems
[stapelberg]: OK, I would be happy to answer that after the talk because that's not really the focus of this talk.
So now, let me just show you a few handy things that might be useful
I have a terminal here that you hopefully can read in the back
Is that OK? Great! So let's just have a look at
thinkfan.service and what I was using here is the systemctl command and you can see multiple interesting things
First of all, it is active and running, so that's good.
It shows that I started it 6 days ago, when I last rebooted my laptop
It also shows the main pid, which is 2588, and that's the binary that corresponds to it.
For more complex services, there are more binaries in the cgroup hierarchy
What is particularly interesting for you is
first of all, where the service file actually lives; so make sure you ship it to the correct path.
There's also a lintian warning for that, so if you use lintian you should catch that
It should go to /lib/systemd/system, as I mentioned
It also should be enabled unless, of course, you decided to not enable it by default
Now, I can just show you systemctl stop, it will be that
[question]: the video projector does not show all of the terminal
[stapelberg]: That is a good point. The first two columns are not shown, so let's make it like this
Should be much better!
Not perfect. Better?
[question, unintelligible]
[stapelberg]: Yeah, whatever. That's good enough.
thinkfan.service -- now it's still enabled. It's still loaded but it's inactive because I stopped it
I can start it again
check that it's started
You can also see that it used this ExecStart line
I can also actually show you the service file. There's really no magic in here.
There is an ExecReload directive here, so we can test if the reload actually works
Which I need to do as root
And then in the status output we will see that it tried to reload the service
code=exited, status = 0/SUCCESS, so that worked.
So those are a few simple things you can check to see if your service actually works
10 minutes, yes. Are there any questions now? Microphone?
[question]: The example has Type=forking. What are the other values which are valid?
[stapelberg]: So that was obviously a suggestion to open the man page and show you that actually it is documented
The manpage in question here is systemd.service, as I tried to explain earlier
There's multiple Types -- there is simple
There's forking, oneshot, dbus, notify or idle
The most interesting ones are simple, forking, oneshot, and dbus
dbus I already explained -- that's if you have an actual dbus service
There's oneshot, which is for stuff like doing one thing and then nothing
like, it's not a permanently running service, it's just a simple command like a shell script
and then it will stay active, as in "started" afterwards
There is forking and there is simple. The difference between simple and forking
is that simple will -- the daemon you're starting, if it's a Type=simple one
should just continue running in the foreground, whereas a forking one will fork itself into background.
The preferred model is using simple because, you know, it's simple.
forking has the implicit assumption, and I think this is important to know, that
as long as the daemon is still running in the foreground, it's not ready
The unit file will be considered started precisely at the moment where the daemon forks.
That is not necessarily what your upstream software implements, but that's how it's
[question, unintelligible]
[stapelberg]: The question was: when it forks, or when the main process exits?
Obviously, I think when the main process exits.
[question]: It would be really strange in the other case
[stapelberg]: That's how it usually works, right? You double-fork and then you exit the main process.
More questions?
Masking processes -- perfect, let's do that!
So I have thinkfan and I now decide
That it's really a shame that my fan is not spinning up as much as I would like
So what I will just do is I will mask thinkfan.service and it will helpfully
print out what it actually did, which is it just created a symlink in /etc/systemd/system/thinkfan.service
pointing to /dev/null
Essentially, it will try to load that service file but fail, because it can't read /dev/null.
So if I now check status
on thinkfan.service, it will tell me that it's masked
but it's also still running. So if I now do systemctl stop
and then status, it's now dead, and it will not be started on my next boot.
This is different from enable and disable because it also works for dbus services and it's really like the last resort
If you really really don't want this thing to be started, mask it. Question?
[question]: In this case, you cannot start it by hand, you have another method implemented in systemd
[question]: If I want it to not start at boot, but I want to be able to run it by hand
[stapelberg]: Yes, then you obviously disable it because disable just means don't start it at boot, but you can still start and stop and restart and all that stuff
masked is really "don't start this at all"
So now, because I don't like loud fans, let me just unmask that
So it told me that it deleted that symlink, and I can start it again and it will just work.
More questions please? Over there.
[question]: When it's active, it says "active (running)" or it says "inactive (dead)"
Is there any particular meaning that there is a part "active" and a part in parenthesis?
[stapelberg]: It could be "active (exited)" and that would be the case for the oneshot services
that just fork one command, then exited, but the unit is still considered active because the command succeeded.
More questions over here?
[question]: Is there any support for -- what happens when a daemon dies, is it restarted, like a few times, or ?
[stapelberg]: I actually had this on my slides earlier
Yes: more features, here we go. You can specify RestartSec=1 and Restart=on-failure
There's more options in that direction to restart stuff when it dies
More questions please? Here.
[question]: It's about the packaging
Is it possible to use dpkg triggers -- instead we just put a file in /lib/systemd
And then the dpkg trigger happens
It means it will work with other packaging systems like cdbs without modification
[stapelberg]: we actually have sent a patch to cdbs and it supports dh_systemd by now. It means it will work with other packaging systems like cdbs without modification
[stapelberg]: we actually have sent a patch to cdbs and it supports dh_systemd by now.
[question]: OK, but why are you not using trigger support?
[stapelberg]: Not using what, sorry?
[question]: Instead of inserting a debhelper snippet in postinst
you could have registered a trigger
[stapelberg]: It's more complicated than that because
[question]: It will be executed when it detects a file appearing in some allocation [stapelberg]: It's more complicated than that because
[question]: It will be executed when it detects a file appearing in some allocation
[stapelberg]: Yeah, but we don't want to enable all the services by default
And then we would need to maintain a whitelist or a blacklist of services
and stuff, and it really needs to be more flexible than that
OK, more questions?
Another one?
[question]: This time it's for services that need several instances
Like stunnel
[stapelberg]: Oh, multiple instances, yes
[question]: Yes, multiple instances; usually they come with several configuration files
And we want one instance per configuration file
And be able to control them separately
[stapelberg]: Yes, so there are actually --
[question]: It's a bummer[?] to do that with sysV [stapelberg]: Yes, so there are actually --
[question]: It's a bummer[?] to do that with sysV
[stapelberg]: There are good examples here of how that works. There's ifup and there's getty [question]: It's a bummer[?] to do that with sysV
[stapelberg]: There are good examples here of how that works. There's ifup and there's getty
Let me just show you getty
which has getty@tty1.service
and what's interesting is you can see that
the service file path actually does not include that
so if you have a look at the service file
You can see that it's much more complicated than I would like it to be
But the interesting part for us is that there's %I
which will be replaced with whatever you specify after the @
So you can make your service file contain the @
in the filename and then use %I and then start a specific instance of that
[question]: And the user is expected to create all the @ files?
[stapelberg]: Yes
OK! More questions?
Here.
[question]: How about this socket-based activation?
[stapelberg]: Socket activation -- that is a good question!
Let me just have a look if I have any socket activation files lying around here
I have approx.socket, which seems kind of appropriate for this conference.
Socket activation essentially works like this, where you have
[Socket] instead of [Service] in your service file
In your socket file, sorry
You specify a TCP port
or a unix socket or whatever it should listen on
And then there is Accept=yes
where the default is Accept=no
The difference is that Accept=yes mimics the inetd-style behavior
of just starting one process per connection, which is kind of wasteful
and the actual real good socket activation is
not having that, but patching the service to
when being started, inherit the file descriptor
of the socket and then just integrate it in its event loop and handle that.
And many services are already patched for that.
Some of them are patched, but not in debian, and some of them you would need to patch.
But this is really a thing of like an hour or two.
I did it for bacula once, for example.
OK. Question over here?
[question]: So the socket file just includes information about where to listen
And if to accept or not, or to start. Is that just in the service file then?
[stapelberg]: Yes, the socket file has to match, by name, the service file
And because I used Accept=yes, it needs to be approx@.service, not approx.service
And then this will in turn just take the standard input from the socket, like inetd does, and start it up.
One more question?
[question]: Why do I have to add the @?
[stapelberg]: Because if you use inetd-style stuff, then for every incoming new connection it will start a separate process.
so all these processes show up in your cgroup hierarchy. [stapelberg]: Because if you use inetd-style stuff, then for every incoming new connection it will start a separate process.
so all these processes show up in your cgroup hierarchy.
So that's why the instance is used in this case.
Does that also relate to ExecStart=- instead of directly the path?
No, in fact, I already looked at this and wondered why it is there
I think it should not be there, because the - means that failures should be ignored.
I'm not entirely sure why it makes sense to have it here
My suspicion would be that if there's a connection and then it goes away
then it shouldn't -- I would need to look that up. Sorry, no answer.
More questions? Last question, we have one minute left.
Last question over there.
[question]: Thank you. Where are dependencies defined in this thing?
[stapelberg]: Oh yes, that's a good question. Ideally, dependencies are not defined anywhere because they are implicit by socket activation.
In case that's not the case, for example, if my
-- I think I should probably have it here, let me just have a look real quick --
dcs-web.service, it's actually more complicated. No it doesn't have it.
So there is, in the [Unit] section, where we also specified the Description, there can be a Before= and After=
So in my case, I would start codesearch after postgresql came up
and I would just specify After=postgresql.service
You can specify multiple services there, you can specify the directive multiple times
But usually it should not be required to specify dependencies, which is nice.
OK, thank you.
OK, time is over. I would like to say, thank you very much for your attention.
If you have any questions, please let me know and we can fix it.
[talkmeister]: Thank you, Michael.
[clapping] [talkmeister]: Thank you, Michael.
[clapping]