[systemd-devel] [PATCH v3] systemd.service(5): add some simple examples
Lennart Poettering
lennart at poettering.net
Tue Jan 27 13:19:56 PST 2015
On Tue, 27.01.15 22:10, Christian Seiler (christian at iwakd.de) wrote:
Thanks a ton! Applied!
> Am 27.01.2015 um 21:45 schrieb Lennart Poettering:
> > On Tue, 27.01.15 17:45, Christian Seiler (christian at iwakd.de) wrote:
> >> + <para>Note that systemd assumes here that the
> >> + program will continue running in the foreground
> >> + as long as it's active. If the program
> >
> > I think "foreground" vs. "background" here is probably something to
> > avoid. These are services after all, and hence kinda "background" in
> > all cases. I am not sure how to explain this better though... Maybe
> > clarify that the program does not fork on its own, and that the
> > process systemd starts stays running until the very end of the
> > daemon, or so.
>
> Yes, you are completely right. I've kept the use of 'background' at some
> places, but specifically avoided foreground, since that is really,
> really misleading. I've also rephrased the paragraph in question. I hope
> that's better.
>
> >> + <para>Note that systemd will consider the unit
> >> + to be in the state 'starting' until the program
> >> + has terminated, so ordered dependencies will
> >> + wait for the program to finish before starting
> >> + themselves. The unit will revert to the
> >> + 'inactive' state after the execution is
> >> + done. That means another request to start the
> >> + unit will perform the action again.</para>
> >
> > It might be worth also mentioning here that the the unit this way will
> > never actually be "active". It will go directly from "activating" to
> > "inactive", which might be surprising!
>
> Thanks for the pointer, done!
>
> Now I also mentioned something about multiple ExecStart= for oneshot
> units, which might be useful there.
>
> >> + <para>Similarly to the oneshot services, there
> >> + are sometimes units that need to execute a
> >> + program to set up something and then execute
> >> + another to shut it down, but no process remains
> >> + active while they are considered
> >> + 'started'. Network configuration can sometimes
> >> + fall into this category.</para>
> >
> > Another reason to use RemainAfterExit= are services that shall not
> > execute again and again when they are pulled in, but only the first
> > time...
>
> Mentioned that, thanks!
>
> >> <varname>RemainAfterExit=</varname><option>dbus</option>
> >
> > Typo. Should be Type=, not RemainAfterExit=
>
> *hehe* fixed.
>
> >> + <example>
> >> + <title>Deferred (idle) services</title>
> >
> > Hmm, I wonder if we maybe should remove this part. Idle services are
> > kinda exotic, and I figure people might be tempted to misuse them. I
> > think this might be something to document at the description of Type=,
> > but not push people towards using this beyond that.
>
> When I started writing this, I didn't just want to copy the getty
> service (people can look that up anyway), so I decided to come up with
> something else. However, once I wrote that unit, I realized that this
> could have easily just been a Type=oneshot, RemainAfterExit=yes,
> After=multi-user.target unit and have the same effect, and be a lot more
> consistent with the rest of the way of doing things...
>
> Type=idle is basically really just for gettys or something extremely
> similar (like other interactive apps on VTs) that also get automatically
> restarted.
>
> Since these examples are supposed to provide a starting point for people
> on how to write services, I've removed the section completely, and I
> think this kind of special internal thing should remain in the reference
> documentation.
>
> v3 attached, I also fixed one or two other minor typos I noticed.
>
> Christian
>
> From ff44c16a173b36695e4844b36fbd10ac977bf4a3 Mon Sep 17 00:00:00 2001
> From: Christian Seiler <christian at iwakd.de>
> Date: Tue, 27 Jan 2015 17:38:02 +0100
> Subject: [PATCH] systemd.service(5): add some simple examples
>
> Add a couple of exampels, at least one for each service type that
> include some explanations and pointers to various relevant options.
> ---
> man/systemd.service.xml | 296 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 296 insertions(+)
>
> diff --git a/man/systemd.service.xml b/man/systemd.service.xml
> index 4c890df..f33e8df 100644
> --- a/man/systemd.service.xml
> +++ b/man/systemd.service.xml
> @@ -1358,6 +1358,302 @@ ExecStart=/bin/echo $ONE $TWO $THREE</programlisting>
> </refsect1>
>
> <refsect1>
> + <title>Examples</title>
> +
> + <example>
> + <title>Simple service</title>
> +
> + <para>The following unit file creates a service
> + that will execute
> + <filename>/usr/sbin/foo-daemon</filename>.
> + Since no <varname>Type=</varname> is specified,
> + the default
> + <varname>Type=</varname><option>simple</option>
> + will be assumed. systemd will assume the unit
> + to be started immediately after the program has
> + begun executing.</para>
> +
> + <programlisting>[Unit]
> +Description=Foo
> +
> +[Service]
> +ExecStart=/usr/sbin/foo-daemon
> +
> +[Install]
> +WantedBy=multi-user.target</programlisting>
> +
> + <para>Note that systemd assumes here that the
> + process started by systemd will continue
> + running until the service terminates. If the
> + program daemonizes itself (i.e. forks), please
> + use
> + <varname>Type=</varname><option>forking</option>
> + instead.</para>
> +
> + <para>Since no <varname>ExecStop=</varname> was
> + specified, systemd will send SIGTERM to all
> + processes started from this service, and after
> + a timeout also SIGKILL. This behavior can be
> + modified, see
> + <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>
> + for details.</para>
> +
> + <para>Note that this unit type does not include
> + any type of notification when a service has
> + completed initialization. For this, you should
> + use other unit types, such as
> + <varname>Type=</varname><option>notify</option>
> + if the service understands systemd's
> + notification protocol,
> + <varname>Type=</varname><option>forking</option>
> + if the service can background itself or
> + <varname>Type=</varname><option>dbus</option>
> + if the unit acquires a DBus name once
> + initialization is complete. See below.</para>
> + </example>
> +
> + <example>
> + <title>Oneshot service</title>
> +
> + <para>Sometimes units should just execute an
> + action without keeping active processes, such
> + as a filesystem check or a cleanup action on
> + boot. For this,
> + <varname>Type=</varname><option>oneshot</option>
> + exists. Units of this type will wait until the
> + process specified terminates and then fall back
> + to being inactive. The following unit will
> + perform a clenaup action:</para>
> +
> + <programlisting>[Unit]
> +Description=Cleanup old Foo data
> +
> +[Service]
> +Type=oneshot
> +ExecStart=/usr/sbin/foo-cleanup
> +
> +[Install]
> +WantedBy=multi-user.target</programlisting>
> +
> + <para>Note that systemd will consider the unit
> + to be in the state 'starting' until the program
> + has terminated, so ordered dependencies will
> + wait for the program to finish before starting
> + themselves. The unit will revert to the
> + 'inactive' state after the execution is
> + done, never reaching the 'active' state. That
> + means another request to start the unit will
> + perform the action again.</para>
> +
> + <para><varname>Type=</varname><option>oneshot</option>
> + are the only service units that may have more
> + than one <varname>ExecStart=</varname>
> + specified. They will be executed in order until
> + either they are all successful or one of them
> + fails.</para>
> + </example>
> +
> + <example>
> + <title>Stoppable oneshot service</title>
> +
> + <para>Similarly to the oneshot services, there
> + are sometimes units that need to execute a
> + program to set up something and then execute
> + another to shut it down, but no process remains
> + active while they are considered
> + 'started'. Network configuration can sometimes
> + fall into this category. Another use case is if
> + a oneshot service shall not be executed a
> + each time when they are pulled in as a
> + dependency, but only the first time.</para>
> +
> + <para>For this, systemd knows the setting
> + <varname>RemainAfterExit=</varname><option>yes</option>,
> + which causes systemd to consider the unit to be
> + active if the start action exited successfully.
> + This directive can be used with all types, but
> + is most useful with
> + <varname>Type=</varname><option>oneshot</option>
> + and
> + <varname>Type=</varname><option>simple</option>.
> + With
> + <varname>Type=</varname><option>oneshot</option>
> + systemd waits until the start action has
> + completed before it considers the unit to be
> + active, so dependencies start only after the
> + start action has succeeded. With
> + <varname>Type=</varname><option>simple</option>
> + dependencies will start immediately after the
> + start action has been dispatched. The following
> + unit provides an example for a simple static
> + firewall.</para>
> +
> + <programlisting>[Unit]
> +Description=Simple firewall
> +
> +[Service]
> +Type=oneshot
> +RemainAfterExit=yes
> +ExecStart=/usr/local/sbin/simple-firewall-start
> +ExecStop=/usr/local/sbin/simple-firewall-stop
> +
> +[Install]
> +WantedBy=multi-user.target</programlisting>
> +
> + <para>Since the unit is considered to be
> + running after the start action has exited,
> + invoking <command>systemctl start</command> on
> + that unit again will cause no action to be
> + taken.</para>
> + </example>
> +
> + <example>
> + <title>Traditional forking services</title>
> +
> + <para>Many traditional daemons/services
> + background (i.e. fork, daemonize) themselves
> + when starting. Set
> + <varname>Type=</varname><option>forking</option>
> + in the service's unit file to support this mode
> + of operation. systemd will consider the service
> + to be in the process of initialization while
> + the original program is still running. Once
> + it exits successfully and at least a process
> + remains (and
> + <varname>RemainAfterExit=</varname><option>no</option>),
> + the service is considered started.</para>
> +
> + <para>Often a traditional daemon only consists
> + of one process. Therefore, if only one process
> + is left after the original process terminates,
> + systemd will consider that process the main
> + process of the service. In that case, the
> + <varname>$MAINPID</varname> variable will be
> + available in <varname>ExecReload=</varname>,
> + <varname>ExecStop=</varname>, etc.</para>
> +
> + <para>In case more than one process remains,
> + systemd will be unable to determine the main
> + process, so it will not assume there is one.
> + In that case, <varname>$MAINPID</varname> will
> + not expand to anything. However, if the process
> + decides to write a traditional PID file,
> + systemd will be able to read the main PID from
> + there. Please set <varname>PIDFile=</varname>
> + accordingly. Note that the daemon should write
> + that file before finishing with its
> + initialization, otherwise systemd might try to
> + read the file before it exists.</para>
> +
> + <para>The following example shows a simple
> + daemon that forks and just starts one process
> + in the background:</para>
> +
> + <programlisting>[Unit]
> +Description=Some simple daemon
> +
> +[Service]
> +Type=forking
> +ExecStart=/usr/sbin/my-simple-daemon -d
> +
> +[Install]
> +WantedBy=multi-user.target</programlisting>
> +
> + <para>Please see
> + <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>
> + for details on how you can influence the way
> + systemd terminates the service.</para>
> + </example>
> +
> + <example>
> + <title>DBus services</title>
> +
> + <para>For services that acquire a name on the
> + DBus system bus, use
> + <varname>Type=</varname><option>dbus</option>
> + and set <varname>BusName=</varname>
> + accordingly. The service should not fork
> + (daemonize). systemd will consider the service
> + to be initialized once the name has been
> + acquired on the system bus. The following
> + example shows a typical DBus service:</para>
> +
> + <programlisting>[Unit]
> +Description=Simple DBus service
> +
> +[Service]
> +Type=dbus
> +BusName=org.example.simple-dbus-service
> +ExecStart=/usr/sbin/simple-dbus-service
> +
> +[Install]
> +WantedBy=multi-user.target</programlisting>
> +
> + <para>For <emphasis>bus-activatable</emphasis>
> + services, don't include a
> + <literal>[Install]</literal> section in the
> + systemd service file, but use the
> + <varname>SystemdService=</varname> option in
> + the corresponding DBus service file, for
> + example
> + (<filename>/usr/share/dbus-1/system-services/org.example.simple-dbus-service.service</filename>):</para>
> +
> + <programlisting>[D-BUS Service]
> +Name=org.example.simple-dbus-service
> +Exec=/usr/sbin/simple-dbus-service
> +User=root
> +SystemdService=simple-dbus-service.service</programlisting>
> +
> + <para>Please see
> + <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>
> + for details on how you can influence the way
> + systemd terminates the service.</para>
> + </example>
> +
> + <example>
> + <title>Services that notify systemd about their initialization</title>
> +
> + <para><varname>Type=</varname><option>simple</option>
> + services are really easy to write, but have the
> + major disadvantage of systemd not being able to
> + tell when initialization of the given service
> + is complete. For this reason, systemd supports
> + a simple notification protocol that allows
> + daemons to make systemd aware that they are
> + done initializing. Use
> + <varname>Type=</varname><option>notify</option>
> + for this. A typical service file for such a
> + daemon would look like this:</para>
> +
> + <programlisting>[Unit]
> +Description=Simple notifying service
> +
> +[Service]
> +Type=notify
> +ExecStart=/usr/sbin/simple-notifying-service
> +
> +[Install]
> +WantedBy=multi-user.target</programlisting>
> +
> + <para>Note that the daemon has to support
> + systemd's notification protocol, else systemd
> + will think the service hasn't started yet and
> + kill it after a timeout. For an example of how
> + to update daemons to support this protocol
> + transparently, take a look at
> + <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
> + systemd will consider the unit to be in the
> + 'starting' state until a readiness notification
> + has arrived.</para>
> +
> + <para>Please see
> + <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>
> + for details on how you can influence the way
> + systemd terminates the service.</para>
> + </example>
> + </refsect1>
> +
> + <refsect1>
> <title>See Also</title>
> <para>
> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
> --
> 1.8.3.1
>
Lennart
--
Lennart Poettering, Red Hat
More information about the systemd-devel
mailing list