openSUSE:Packaging for transactional-updates

Jump to: navigation, search


This document describes requirements for RPMs to work together with transactional updates.

Transactional Update

Transactional updates are atomic. This means, either the update is fully applied without any error, or no change is made to the system. Additionally transactional upates should not influence the currently running processes. On openSUSE we achieve this by using btrfs with snapshots and rollback. But instead of creating a snapshot, updating the current system and rolling back if an error happened, we create a snapshot, update this snapshot, and do a "rollback" to that snapshot if no error occured. In this situation, not all data is available. Accessible is only the main root btrfs subvolume. All other subvolumes, which were created to prevent them from being rolled back, are not accessible during update of the RPM! This means, any file normally stored in these subvolumes cannot be accessed and modified, or new files created during update are not visible later in the running system. This includes especially the /srv, /opt and /var directories.

FHS 3.0 says about this directories:

  • /opt is reserved for the installation of add-on application software packages.
  • /srv contains site-specific data which is served by this system.
  • /var contains variable data files. This includes spool directories and files, administrative and logging data, and transient and temporary files. It is specified here in order to make it possible to mount /usr read-only. Everything that once went into /usr that is written to during system operation (as opposed to installation and software maintenance) must be in /var.
  • /var/lib holds state information pertaining to an application or the system. State information is data that programs modify while they run, and that pertains to one specific host. Users must never need to modify files in /var/lib to configure a package's operation, and the specific file hierarchy used to store the data must not be exposed to regular users.

Most of the openSUSE RPMs are fine and will not create any problems. Others need to be adjusted. Most of the changes are not only needed for transactional updates, but also for snapshots and rollback.

Guidelines

Data and applications

User data and applications need to be strictly separated. User data should be in another subvolume than the main root subvolume with the application. Applications should always be in the main root subvolume and not in other subvolumes. "/srv" is a real nightmare in this regard: it contains applications, user data and configuration files mixed up.


Pre/Post install sections

Applications modifying data or config files in the pre/post install sections need to be careful, where this data is located. If the data is in other subvolumes, the modifications should be done during the next reboot, e.g., with a systemd unit file. But be careful that the unit is only running once after the update and not with every reboot again.


Restarting services

Since the new/updated applications are not available in the running system, restarting any service does not make any sense, it will only interrupt the running services and start the old code again. The standard systemd macros take care of this and are fine.


Directories

If an RPM contains directories which are outside the root subvolume, these directories will also not be visible, same for changes of ownership or permissions. For /var and /srv we have a tool which reads the RPM database at boot time and creates missing directories. systemd-tmpfiles can be used to create new directories, for example, too.


Files in /var

RPMs should not package files in /var, as these files cannot be created, updated or deleted during installation, update or removal of that package. A better solution is to use systemd-tmpfiles to create these files:

  • Store the files in a directory below /usr/share or /usr/lib
  • Create a /usr/lib/tmpfiles.d/<package>.conf file which copies or links the file to /var

An example (taken from ypserv) could look like:

ypserv.conf:

  d /var/yp 0755 - - -
  L /var/yp/Makefile - - - - ../../usr/lib/yp/ypMakefile
  L /var/yp/securenets - - - - ../../usr/lib/yp/securenets.example

ypserv.spec:

  %post
  %tmpfiles_create ypserv.conf

For more information, read the documentation for the tmpfiles configuration file format