<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>akeil.de (Posts about systemd)</title><link>https://akeil.de/</link><description></description><atom:link href="https://akeil.de/categories/systemd.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Sat, 02 Jan 2021 21:07:04 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Coordinate Scripts With systemd</title><link>https://akeil.de/posts/coordinate-scripts-with-systemd/</link><dc:creator>Alexander Keil</dc:creator><description>&lt;div class="section" id="coordinate-scripts-with-systemd"&gt;
&lt;h2&gt;Coordinate Scripts With systemd&lt;/h2&gt;
&lt;dl class="field-list simple"&gt;
&lt;dt&gt;author&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;akeil&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;date&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;2013-12-14&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;version&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;1&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Use systemd to execute scripts,
controlling the order of execution.&lt;/p&gt;
&lt;dl class="simple"&gt;
&lt;dt&gt;Assuming we have:&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;a single preparation unit - &lt;code class="docutils literal"&gt;prep.service&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;multiple "task" units - &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;task-N.service&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a single cleanup script - &lt;code class="docutils literal"&gt;done.service&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;We want to run the &lt;em&gt;prep unit&lt;/em&gt; once,
then run all our &lt;em&gt;task units&lt;/em&gt;
and finally the &lt;em&gt;done unit&lt;/em&gt; once.&lt;/p&gt;
&lt;p&gt;Defining dependencies between tasks is relatively simple when each task
is represented by a &lt;a class="reference external" href="http://www.freedesktop.org/software/systemd/man/systemd.unit.html"&gt;systemd unit&lt;/a&gt; &lt;a class="footnote-reference brackets" href="https://akeil.de/posts/coordinate-scripts-with-systemd/#id1" id="id2"&gt;1&lt;/a&gt;.
Dependencies are defined using &lt;code class="docutils literal"&gt;Requires=&lt;/code&gt; or &lt;code class="docutils literal"&gt;Wants=&lt;/code&gt;
and order of execution is defined with &lt;code class="docutils literal"&gt;After=&lt;/code&gt; and &lt;code class="docutils literal"&gt;Before=&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The only thing left is to make sure that the "preparation"
and "finish" steps are executed only once, even if multiple tasks are run
(and not once for each task).&lt;/p&gt;
&lt;p&gt;To achieve this a &lt;code class="docutils literal"&gt;.target&lt;/code&gt; is created
and all tasks are associated to that target.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Note&lt;/p&gt;
&lt;dl class="simple"&gt;
&lt;dt&gt;Steps:&lt;/dt&gt;
&lt;dd&gt;&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;p&gt;Create &lt;code class="docutils literal"&gt;.service&lt;/code&gt; files for the commands that must be executed &lt;em&gt;before&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create &lt;code class="docutils literal"&gt;.service&lt;/code&gt; for commands that should be executed &lt;em&gt;after&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create as single &lt;code class="docutils literal"&gt;.target&lt;/code&gt; for all tasks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code class="docutils literal"&gt;.service&lt;/code&gt; for each task, make it &lt;code class="docutils literal"&gt;WantedBy=&lt;/code&gt; the target.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;div class="section" id="target-unit"&gt;
&lt;h3&gt;Target Unit&lt;/h3&gt;
&lt;p&gt;A &lt;a class="reference external" href="http://www.freedesktop.org/software/systemd/man/systemd.target.html"&gt;systemd target&lt;/a&gt; &lt;a class="footnote-reference brackets" href="https://akeil.de/posts/coordinate-scripts-with-systemd/#id3" id="id4"&gt;2&lt;/a&gt; is used to group several units together.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;target&lt;/em&gt; file goes into &lt;code class="docutils literal"&gt;/etc/systemd/system&lt;/code&gt; and looks like this:&lt;/p&gt;
&lt;pre class="code ini"&gt;&lt;a name="rest_code_e7c75c92097c41c0a61f5a55125bd5c8-1"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# tasks.target ---------------------------------------&lt;/span&gt;
&lt;a name="rest_code_e7c75c92097c41c0a61f5a55125bd5c8-2"&gt;&lt;/a&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;a name="rest_code_e7c75c92097c41c0a61f5a55125bd5c8-3"&gt;&lt;/a&gt;&lt;span class="na"&gt;Description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Tasks Target&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;The target can be started manually with:&lt;/p&gt;
&lt;pre class="code shell-session"&gt;&lt;a name="rest_code_91cdad81cfc045cd809226b8df2be069-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;#&lt;/span&gt; systemctl start tasks.target
&lt;/pre&gt;&lt;p&gt;The &lt;em&gt;task units&lt;/em&gt; are associated with the target using &lt;code class="docutils literal"&gt;WantedBy=&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This means, if we &lt;em&gt;enable&lt;/em&gt; one or more &lt;em&gt;task units&lt;/em&gt; with&lt;/p&gt;
&lt;pre class="code shell-session"&gt;&lt;a name="rest_code_50eb4ceb35f145f292203870b6683152-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;#&lt;/span&gt; systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; task-1.service task-2.service
&lt;/pre&gt;&lt;p&gt;... starting the &lt;code class="docutils literal"&gt;tasks.target&lt;/code&gt; will start all of the associated
units.&lt;/p&gt;
&lt;p&gt;This allows us to start all tasks with a single invocation
which in turn means that we execute any number of tasks
and the &lt;em&gt;prep&lt;/em&gt; and &lt;em&gt;done&lt;/em&gt; units only once.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="task-units"&gt;
&lt;h3&gt;Task Units&lt;/h3&gt;
&lt;p&gt;Each &lt;em&gt;task unit&lt;/em&gt; specifies the &lt;code class="docutils literal"&gt;prep.service&lt;/code&gt; as a
precondition using &lt;code class="docutils literal"&gt;Requires=&lt;/code&gt; and &lt;code class="docutils literal"&gt;After=&lt;/code&gt;.
It also specifies the &lt;code class="docutils literal"&gt;done.service&lt;/code&gt; using &lt;code class="docutils literal"&gt;Wants=&lt;/code&gt;
and &lt;code class="docutils literal"&gt;Before=&lt;/code&gt; to have it run after the tasks.&lt;/p&gt;
&lt;pre class="code ini"&gt;&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-1"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# task.service ---------------------------------------&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-2"&gt;&lt;/a&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-3"&gt;&lt;/a&gt;&lt;span class="na"&gt;Description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;A task unit&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-4"&gt;&lt;/a&gt;&lt;span class="na"&gt;Requires&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;prep.service&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-5"&gt;&lt;/a&gt;&lt;span class="na"&gt;After&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;prep.service&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-6"&gt;&lt;/a&gt;&lt;span class="na"&gt;Wants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;done.service&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-7"&gt;&lt;/a&gt;&lt;span class="na"&gt;Before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;done.service&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-8"&gt;&lt;/a&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-9"&gt;&lt;/a&gt;&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-10"&gt;&lt;/a&gt;&lt;span class="na"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;someuser&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-11"&gt;&lt;/a&gt;&lt;span class="na"&gt;Group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;somegroup&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-12"&gt;&lt;/a&gt;&lt;span class="na"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;oneshot&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-13"&gt;&lt;/a&gt;&lt;span class="na"&gt;ExecStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/script.sh&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-14"&gt;&lt;/a&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-15"&gt;&lt;/a&gt;&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;a name="rest_code_7a31e88d12b1475a9a15985e4752a076-16"&gt;&lt;/a&gt;&lt;span class="na"&gt;WantedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;tasks.target&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;The &lt;code class="docutils literal"&gt;Requires=prep.service&lt;/code&gt; directive means that the task is not started
if the &lt;code class="docutils literal"&gt;prep.service&lt;/code&gt; failed.
Using &lt;code class="docutils literal"&gt;Wants=prep.service&lt;/code&gt; would try to start the &lt;em&gt;prep unit&lt;/em&gt; first
but continue with the tasks regardless of whether preparation was
successful or not.&lt;/p&gt;
&lt;p&gt;The &lt;code class="docutils literal"&gt;User=&lt;/code&gt; and &lt;code class="docutils literal"&gt;Group=&lt;/code&gt; properties can be used to run the command
under a different user than root.&lt;/p&gt;
&lt;p&gt;Not all tasks have to specify the same dependencies.
It is also possible that tasks depend on each other.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="prep-and-done-units"&gt;
&lt;h3&gt;Prep and Done Units&lt;/h3&gt;
&lt;p&gt;The &lt;code class="docutils literal"&gt;prep.service&lt;/code&gt; and the &lt;code class="docutils literal"&gt;done.service&lt;/code&gt; are plain units
and do not define any dependencies.&lt;/p&gt;
&lt;p&gt;the &lt;em&gt;prep unit&lt;/em&gt; should be configured with &lt;code class="docutils literal"&gt;Type=oneshot&lt;/code&gt;
to have it complete before the first task can be started.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="service-type"&gt;
&lt;h3&gt;Service Type&lt;/h3&gt;
&lt;p&gt;By default, &lt;code class="docutils literal"&gt;Before=&lt;/code&gt; and &lt;code class="docutils literal"&gt;After=&lt;/code&gt; only control the order in which
services are &lt;em&gt;started&lt;/em&gt;.
To make sure that the &lt;em&gt;prep unit&lt;/em&gt; completes before the tasks are started,
use &lt;code class="docutils literal"&gt;Type=oneshot&lt;/code&gt; in the &lt;code class="docutils literal"&gt;[Service]&lt;/code&gt; definition.&lt;/p&gt;
&lt;p&gt;From the &lt;a class="reference external" href="http://www.freedesktop.org/software/systemd/man/systemd.service.html"&gt;systemd service&lt;/a&gt; &lt;a class="footnote-reference brackets" href="https://akeil.de/posts/coordinate-scripts-with-systemd/#id5" id="id6"&gt;3&lt;/a&gt; documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Behavior of oneshot is similar to simple;
however, it is expected that the process has to exit
before systemd starts follow-up units.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The same goes for the &lt;em&gt;task units&lt;/em&gt; if the &lt;em&gt;done unit&lt;/em&gt; should only
be executed after the tasks are complete.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="locations"&gt;
&lt;h3&gt;Locations&lt;/h3&gt;
&lt;dl class="simple"&gt;
&lt;dt&gt;Custom unit files go into:&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal"&gt;/etc/systemd/system&lt;/code&gt; for system-wide scope&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;~/.config/systemd/user&lt;/span&gt;&lt;/code&gt; for user-specific scope&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;hr class="docutils"&gt;
&lt;dl class="footnote brackets"&gt;
&lt;dt class="label" id="id1"&gt;&lt;span class="brackets"&gt;&lt;a class="fn-backref" href="https://akeil.de/posts/coordinate-scripts-with-systemd/#id2"&gt;1&lt;/a&gt;&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a class="reference external" href="http://www.freedesktop.org/software/systemd/man/systemd.unit.html"&gt;http://www.freedesktop.org/software/systemd/man/systemd.unit.html&lt;/a&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="label" id="id3"&gt;&lt;span class="brackets"&gt;&lt;a class="fn-backref" href="https://akeil.de/posts/coordinate-scripts-with-systemd/#id4"&gt;2&lt;/a&gt;&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a class="reference external" href="http://www.freedesktop.org/software/systemd/man/systemd.target.html"&gt;http://www.freedesktop.org/software/systemd/man/systemd.target.html&lt;/a&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt class="label" id="id5"&gt;&lt;span class="brackets"&gt;&lt;a class="fn-backref" href="https://akeil.de/posts/coordinate-scripts-with-systemd/#id6"&gt;3&lt;/a&gt;&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;&lt;a class="reference external" href="http://www.freedesktop.org/software/systemd/man/systemd.service.html"&gt;http://www.freedesktop.org/software/systemd/man/systemd.service.html&lt;/a&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>linux</category><category>systemd</category><guid>https://akeil.de/posts/coordinate-scripts-with-systemd/</guid><pubDate>Sun, 14 Dec 2014 13:43:38 GMT</pubDate></item></channel></rss>