DEBOPS.PERSISTENT_PATHS(5)

NAME
debops.persistent_paths - Ensure paths are stored on persistent storage

SYNOPSIS

debops service/persistent_paths [--limit group,host,...] [--diff] [--check] [--tags tag1,tag2,...] [--skip-tags tag1,tag2,...] [<ansible-playbook options>] ...

DESCRIPTION

This role provides a generic mechanism to declare which files/directories are required to be persistent. How this information is used can then be defined in this role.

On Qubes OS <https://en.wikipedia.org/wiki/Qubes_OS>, all work gets done in AppVMs which are typically based on TemplateVMs. Only a few paths in such TemplateBasedVM will persist a reboot, mainly /home and /rw. Package installation and the like is supposed to happen in TemplateVMs only but configuration can happen in either VM type as desired. If changes should be made in a TemplateBasedVM however it needs to be made sure that they are persistent.

Since Qubes OS R3.2 the bind-dirs <https://www.qubes-os.org/doc/bind-dirs/> script and related configuration can be used to easily make additional paths persistent by bind mounting them from /rw/bind-dirs/ to the desired path.

debops.persistent_paths allows other Ansible roles to interact with bind-dirs <https://www.qubes-os.org/doc/bind-dirs/> by using this role as a dependency role. An example which does this is debops.cryptsetup.

The role can also be used by the system administrator to manage bind-dirs <https://www.qubes-os.org/doc/bind-dirs/> using the Ansible inventory.

GETTING STARTED

  Example inventory

To manage persistence of paths on a TemplateBasedVM it should be included in the debops_service_persistent_paths Ansible inventory group:

[debops_service_persistent_paths]
hostname

The role can also run against a TemplateVM to prepare paths which will then be persistent in AppVMs based on the TemplateVM.

If the role is used as a dependency role, you as user of the main role do not need to do anything with this role except from having it installed and using the appropriate playbook provided by the main role.

  Example playbook

If you are using this role without DebOps, here's an example Ansible playbook that uses the debops.persistent_paths role:

---
- name: Ensure paths are stored on persistent storage
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_service_persistent_paths' ]
  become: True
  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'
  roles:
    - role: persistent_paths
      tags: [ 'role::persistent_paths', 'skip::persistent_paths' ]

  Qubes OS

The qubes-core-agent package needs to be installed in the TemplateVM which is the default for the official Debian templates <https://www.qubes-os.org/doc/templates/debian/>.

Note that currently you will need an unreleased version of bind-dirs.sh <https://github.com/QubesOS/qubes-core-agent-linux/blob/master/vm-systemd/bind-dirs.sh> in place for some roles which use debops.persistent_paths to work correctly (ref: bind-dirs: Create ro if bind target exists <https://github.com/QubesOS/qubes-core-agent-linux/pull/42>).

Refer to bind-dirs <https://www.qubes-os.org/doc/bind-dirs/> for more details and limitations.

  Ansible tags

You can use Ansible --tags or --skip-tags parameters to limit what tasks are performed during Ansible run. This can be used after a host was first configured to speed up playbook execution, when you are sure that most of the configuration is already in the desired state.

Available role tags:

role::persistent_paths
    Main role tag, should be used in the playbook to execute all of the role tasks as well as role dependencies.

role::persistent_paths:qubes_os
    Tasks related to Qubes OS.

USAGE GUIDES

Role authors who want to support platforms like Qubes OS <https://en.wikipedia.org/wiki/Qubes_OS> and other environments where persistence is not the default can do so by using this role as a dependency role, either has hard or soft dependency (DebOps default).

The general mode of operation looks like this:

1.  Your service role is run as usual writing to non-persistent paths.

2.  debops.persistent_paths is run to ensure that paths specified by the service role are persistent.

    To make this happen, you would typically include a default variable like role_name__persistent_paths__dependent_paths in your service role like this one:

    # .. envvar:: role_name__persistent_paths__dependent_paths [[[
    #
    # Configuration for the debops.persistent_paths_ Ansible role.
    role_name__persistent_paths__dependent_paths:
      '50_role_owner_role_name':
        by_role: 'role_owner.role_name'
        paths:
          - '/etc/example1'
          - '/etc/example2'
                                                                       # ]]]

    And then pass this to debops.persistent_paths when calling the role:

    - role: role_owner.role_name
      tags: [ 'role::role_name' ]
    - role: persistent_paths
      tags: [ 'role::persistent_paths' ]
      persistent_paths__dependent_paths: '{{ role_name__persistent_paths__dependent_paths }}'

    Note that as Qubes OS <https://en.wikipedia.org/wiki/Qubes_OS> and similar platforms are not the main target platforms of DebOps, an additional playbook which features debops.persistent_paths support should be included in roles instead of extending the default role playbook. User can then select the role playbook they want to run using Ansible groups as needed.

    Examples of roles which use/support debops.persistent_paths:

•   debops.cryptsetup

•   debops.dnsmasq

•   debops.tinc

  Templating or updating persistent files

Qubes OS supports persistent files or directories in TemplateBasedVM using bind mounts. The files and directories marked for persistent storage are copied to a separate directory and mounted over the original files.

Note that bind mounted files (and directories) don’t allow rename nor unlinkat sys calls. This means that once a file has been made persistent by bind mounting it, updates to the file needs to be done using the unsafe_writes parameter which many file related Ansible modules support.

Refer to the debops.core usage guide <https://docs.debops.org/en/latest/ansible/roles/core/guides.html#global-unsafe-writes> for details.

DEFAULT VARIABLE DETAILS

Some of debops.persistent_paths default variables have more extensive configuration than simple strings or lists, here you can find documentation and examples for them.

  persistent_paths__paths

persistent_paths__paths and similar dictionary variables can be used to manage the persistence of paths.

The dictionary key should be used to bundle different paths together which are needed to achieve one goal. This allows to mask/overwrite them later in the hierarchy as defined by persistent_paths__combined_paths. For use as dependency role, the key should be {{ weight }}_{{ role_owner }}_{{ role_name }}{{ optional_tags }} where weight should be a two-digit number. For DebOps roles, the weight 50 should be used. For direct use, the key could be 70_local_mlocate for example.

Each dictionary value is a dictionary by itself with the following supported options:

paths
    Required, list of strings. Paths to make persistent. The same path can be required to be persistent by multiple parties.

state
    Optional, string. Defaults to present. Options:

present
    The paths should be persistent.

absent
    The paths are not required to be persistent. A possibly existing persistent state is not removed by this. Note that other parties might still require paths to be persistent which is not effected by setting one entry to absent.

by_role
    Optional, string. Name of the Ansible role in the format {{ role_owner }}.{{ role_name }} which is responsable for the entry. This option probably only makes sense in the use as dependency role.

  Examples

---
persistent_paths__dependent_paths:
  '50_debops_cryptsetup':
    by_role: 'debops.cryptsetup'
    paths:
      - '/etc/fstab'
      - '/etc/crypttab'
      - '/var/local/keyfiles'
      - '/var/backups/luks_header_backup'
      - '/media'
persistent_paths__group_paths:
  '70_local_mlocate':
    paths:
      - '/var/lib/mlocate'

AUTHOR
Robin Schneider

COPYRIGHT
2014-2022, Maciej Delmanowski, Nick Janetakis, Robin Schneider and others