diff options
Diffstat (limited to 'man/systemd.offline-updates.xml')
-rw-r--r-- | man/systemd.offline-updates.xml | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/man/systemd.offline-updates.xml b/man/systemd.offline-updates.xml new file mode 100644 index 0000000..6706451 --- /dev/null +++ b/man/systemd.offline-updates.xml @@ -0,0 +1,163 @@ +<?xml version='1.0'?> <!--*-nxml-*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> +<!-- SPDX-License-Identifier: LGPL-2.1-or-later --> + +<refentry id="systemd.offline-updates"> + <refentryinfo> + <title>systemd.offline-updates</title> + <productname>systemd</productname> + </refentryinfo> + + <refmeta> + <refentrytitle>systemd.offline-updates</refentrytitle> + <manvolnum>7</manvolnum> + </refmeta> + + <refnamediv> + <refname>systemd.offline-updates</refname> + <refpurpose>Implementation of offline updates in systemd</refpurpose> + </refnamediv> + + <refsect1> + <title>Implementing Offline System Updates</title> + + <para>This man page describes how to implement "offline" system updates with systemd. By "offline" + OS updates we mean package installations and updates that are run with the system booted into a + special system update mode, in order to avoid problems related to conflicts of libraries and + services that are currently running with those on disk. This document is inspired by this + <ulink url="https://wiki.gnome.org/Design/OS/SoftwareUpdates">GNOME design whiteboard</ulink>. + </para> + + <para>The logic:</para> + + <orderedlist> + <listitem> + <para>The package manager prepares system updates by downloading all (.rpm or .deb or + whatever) packages to update off-line in a special directory + <filename index="false">/var/lib/system-update</filename> (or + another directory of the package/upgrade manager's choice).</para> + </listitem> + + <listitem> + <para>When the user OK'ed the update, the symlink <filename>/system-update</filename> is + created that points to <filename index="false">/var/lib/system-update</filename> (or + wherever the directory with the upgrade files is located) and the system is rebooted. This + symlink is in the root directory, since we need to check for it very early at boot, at a + time where <filename>/var/</filename> is not available yet.</para> + </listitem> + + <listitem> + <para>Very early in the new boot + <citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry> + checks whether <filename>/system-update</filename> exists. If so, it (temporarily and for + this boot only) redirects (i.e. symlinks) <filename>default.target</filename> to + <filename>system-update.target</filename>, a special target that pulls in the base system + (i.e. <filename>sysinit.target</filename>, so that all file systems are mounted but little + else) and the system update units.</para> + </listitem> + + <listitem> + <para>The system now continues to boot into <filename>default.target</filename>, and + thus into <filename>system-update.target</filename>. This target pulls in all system + update units. Only one service should perform an update (see the next point), and all + the other ones should exit cleanly with a "success" return code and without doing + anything. Update services should be ordered after <filename>sysinit.target</filename> + so that the update starts after all file systems have been mounted.</para> + </listitem> + + <listitem> + <para>As the first step, an update service should check if the + <filename>/system-update</filename> symlink points to the location used by that update + service. In case it does not exist or points to a different location, the service must exit + without error. It is possible for multiple update services to be installed, and for multiple + update services to be launched in parallel, and only the one that corresponds to the tool + that <emphasis>created</emphasis> the symlink before reboot should perform any actions. It + is unsafe to run multiple updates in parallel.</para> + </listitem> + + <listitem> + <para>The update service should now do its job. If applicable and possible, it should + create a file system snapshot, then install all packages. After completion (regardless + whether the update succeeded or failed) the machine must be rebooted, for example by + calling <command>systemctl reboot</command>. In addition, on failure the script should + revert to the old file system snapshot (without the symlink).</para> + </listitem> + + <listitem> + <para>The update scripts should exit only after the update is finished. It is expected + that the service which performs the update will cause the machine to reboot after it + is done. If the <filename>system-update.target</filename> is successfully reached, i.e. + all update services have run, and the <filename>/system-update</filename> symlink still + exists, it will be removed and the machine rebooted as a safety measure.</para> + </listitem> + + <listitem> + <para>After a reboot, now that the <filename>/system-update</filename> symlink is gone, + the generator won't redirect <filename>default.target</filename> anymore and the system + now boots into the default target again.</para> + </listitem> + </orderedlist> + </refsect1> + + <refsect1> + <title>Recommendations</title> + + <orderedlist> + <listitem> + <para>To make things a bit more robust we recommend hooking the update script into + <filename>system-update.target</filename> via a <filename index="false">.wants/</filename> + symlink in the distribution package, rather than depending on <command>systemctl + enable</command> in the postinst scriptlets of your package. More specifically, for your + update script create a .service file, without [Install] section, and then add a symlink like + <filename index="false">/usr/lib/systemd/system/system-update.target.wants/foobar.service</filename> + → <filename index="false">../foobar.service</filename> to your package.</para> + </listitem> + + <listitem> + <para>Make sure to remove the <filename>/system-update</filename> symlink as early as + possible in the update script to avoid reboot loops in case the update fails.</para> + </listitem> + + <listitem> + <para>Use <varname>FailureAction=reboot</varname> in the service file for your update script + to ensure that a reboot is automatically triggered if the update fails. + <varname>FailureAction=</varname> makes sure that the specified unit is activated if your + script exits uncleanly (by non-zero error code, or signal/coredump). If your script succeeds + you should trigger the reboot in your own code, for example by invoking logind's + <command>Reboot()</command> call or calling <command>systemctl reboot</command>. See + <citerefentry><refentrytitle>org.freedesktop.login1</refentrytitle><manvolnum>5</manvolnum></citerefentry> + for details about the logind D-Bus API.</para> + </listitem> + + <listitem> + <para>The update service should declare <varname>DefaultDependencies=no</varname>, + <varname>Requires=sysinit.target</varname>, <varname>After=sysinit.target</varname>, + <varname>After=system-update-pre.target</varname>, <varname>Before=system-update.target</varname> + and explicitly pull in any other services it requires.</para> + </listitem> + + <listitem> + <para>It may be desirable to always run an auxiliary unit when booting + into offline-updates mode, which itself does not install updates. To + do this create a .service file with + <varname>Wants=system-update-pre.target</varname> and + <varname>Before=system-update-pre.target</varname> and add a symlink + to that file under + <filename index="false">/usr/lib/systemd/system-update.target.wants</filename> + .</para> + </listitem> + </orderedlist> + </refsect1> + + <refsect1> + <title>See also</title> + + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry project='mankier'><refentrytitle>dnf.plugin.system-upgrade</refentrytitle><manvolnum>8</manvolnum></citerefentry> + </para> + </refsect1> +</refentry> |