holo-files - Holo plugin to provision files


When using Holo, configuration is usually stored in system packages, so files can be provisioned by just including them in a configuration package. This plugin extends this basic capability to allow one package (a configuration package) to overwrite or modify a file that has been installed by another package (an application package).

Structure of the resource directory

Configuration packages that want to use this plugin must place files in the resource directory at /usr/share/holo/files. Each resource file works on a certain target, as determined by its file name:

                        |           |
                        |           `-- path to target
                        `-- disambiguator

The disambiguator is always required, and allows multiple resource files to operate on the same target (sorted alphabetically by their disambiguator). The pattern of putting a number at the start of the disambiguator is not required, but useful to control the ordering of resource files.

Each target file that has such resource files is an entity within Holo. Its entity ID is file:$target where $target is the absolute path to the target file.

Application strategy

Resource files are applied on the target base, the initial version of the target file that was found during the first holo apply run. This target base is saved at /var/lib/holo/files/base/$target.

Resource files that are plain files or symlinks will just overwrite the target base (or all previous entries), whereas executable resource files with an extra .holoscript suffix can be used to modify the target base (or the result of a previous application step). The target contents will be piped through the script. This is typically used when the default configuration for an application shall be used, but with some minor modifications. The following example uses the default configuration for pacman(8), but enables the "Color" and "TotalDownload" options:

$ cat /usr/share/holo/files/20-enable-color/etc/pacman.conf.holoscript
sed 's/^#\s*Color$/Color/; s/^#\s*TotalDownload$/TotalDownload/'

$ sudo holo apply file:/etc/pacman.conf

Working on file:/etc/pacman.conf
  store at /var/lib/holo/files/base/etc/pacman.conf
  passthru /usr/share/holo/files/20-enable-color/etc/pacman.conf.holoscript

When writing the new target file, ownership and permissions will be copied from the target base, and thus from the original target file. Furthermore, a copy of the provisioned target file is written to /var/lib/holo/files/provisioned/$target for use by holo diff file:$target.

In normal operation, holo-files will refuse to operate on a target file that has been modified or deleted by the user or by another program. Apply --force to reset the target file to its defined state.

Handling package upgrades

Each target file is originally installed by an application package. When that application package is upgraded, system package managers usually detect that the file has been modified, and store the new version contained in the application package next to the target file, in paths such as

$target.rpmnew          # for RPM    (Fedora, Mageia, openSUSE etc.)
$target.dpkg-dist       # for dpkg   (Debian, Ubuntu etc.)
$target.pacnew          # for pacman (Arch Linux etc.)
$target.apk-new         # for APK    (Alpine Linux etc.)

When this happens, the next holo apply run will detect this file and update its target base with this file:

$ sudo pacman -Syu
installing pacman ...
warning: /etc/pacman.conf installed as /etc/pacman.conf.pacnew
$ sudo holo apply file:/etc/pacman.conf

Working on file:/etc/pacman.conf
  store at /var/lib/holo/files/base/etc/pacman.conf
  passthru /usr/share/holo/files/20-enable-color/etc/pacman.conf.holoscript

>> found updated target base: /etc/pacman.conf.pacnew -> /var/lib/holo/files/base/etc/pacman.conf

(Unless disabled, it would not normally be nescessary to manually run sudo holo apply in the above example, as holo-files provides a pacman hook that causes pacman to automatically call holo apply to handle .pacnew files. This is not (yet) true for other package managers.)

This means that when configuration is applied as a holoscript on top of the default configuration, future updates to the default configuration will automatically be picked up, as long as holo apply is run after the system update.

When detecting these files, to know which suffixes to look for, holo-files inspects ID and ID_LIKE in os-release(5) to determine which family the operating system belongs to, and thus which package manager is used. It currently recognizes alpine, arch, debian, fedora and suse.

Handling package removal

If there exist target bases below /var/lib/holo/files for which there are no corresponding resource files below /usr/share/holo/files, these target bases are considered orphaned.

This usually occurs because a package has been removed from the system, or because a different package version were installed that do not contain the resource files in question anymore.

There are two subcases to consider, if only configuration packages were deleted, holo apply will restore the target base (as installed by the application package):

Scrubbing file:/etc/resourcefile-deleted.conf (all repository files were deleted)
  restore /var/lib/holo/files/base/etc/resourcefile-deleted.conf

If the application package (to whom the target file belongs) has also been deleted, the target base will be deleted instead of restored:

Scrubbing file:/etc/targetfile-deleted.conf (target was deleted)
   delete /var/lib/holo/files/base/etc/targetfile-deleted.conf

This algorithm ensures that after any number of package installation and removal operations, a single holo apply will converge all old and new target files to the desired state.

Dealing manual changes

holo apply will refuse to work on target files that have been modified by the user or another program, unless --force is given:

$ sudo rm /etc/pacman.conf
$ sudo vim /etc/ssh/sshd_config
$ sudo holo apply

Working on file:/etc/pacman.conf
  store at /var/lib/holo/files/base/etc/pacman.conf
     apply /usr/share/holo/files/01-base/etc/pacman.conf

!! skipping target: file has been deleted by user (use --force to restore)

Working on file:/etc/ssh/sshd_config
  store at /var/lib/holo/files/base/etc/ssh/sshd_config
     apply /usr/share/holo/files/10-openssh/etc/ssh/sshd_config

!! skipping target: file has been modified by user (use --force to restore)

The holo diff command can be used to produce a diff between the last provisioned and the current state of the target files. holo apply --force can be used to reset the target files to their defined state.


holo(8) provides the user interface for using this plugin.



Stefan Majewsky

Further documentation is available at the project homepage:

Please report any issues and feature requests at GitHub: