Backups, systemd, mounts and noauto

btrbk can create snapshots of a btrfs subvolume. I learned about this module from a blog by Solène Rapenne. The NixOS module for btrbk creates a timer to run backups at regular time. The times when the backup runs are given with the onCalendar option for systemd. It is combined with Persistent = True, so that if the backup did not run because the timer was not activate, it will start the backup immediately when the timer is activated (e.g. at boot).

This works great for volumes that get mounted on boot, but fails when the volume is mounted later. When the volume is mounted later, the timer has already triggered and failed.

This can even happen when the btrkb timer starts before the mount. Currently, there is no RequiresMountsFor in the timer unit.

The systemd option BindsTo makes sure that a unit is not active when the other unit is not active.

I tried to configure the use of BindsTo for the btrbk unit like this:

  services.btrbk.instances.mydisk = {
    onCalendar = "daily";
    settings = {
      ssh_identity = "/etc/btrbk_key";
      ssh_user = "btrbk";
      volume = {
        "ssh://somehost/mnt/backups_toplvl" = {
          snapshot_dir = "btrbk/backups/remote";
          subvolume = "backups";
          target = "/mnt/backups/btrbk/backups";
        };
      };
    };
  };

  systemd.timers.btrbk-mydisk.unitConfig = {
    ConditionPathIsReadWrite = "/mnt/backups/btrbk";
    After = "mnt-backups.mount";
    BindsTo = "mnt-backups.mount";
  };

The After and BindsTo are placed in the [Unit] section of the timer. The After makes sure that the timer stops when the drive is (manually) unmounted.

This works the first time the volume is mounted. When the volume is unmounted and mounted again, the timer unit stays inactive. This can be seen with systemctl list-timers --all.

So some statements are missing. I tried adding WantedBy, but that gets added to the [Unit] section instead of the [Install] section of the timer unit.

What statement is missing from the systemd unit to make sure the backup runs when the volume is mounted?

@oxalica @symphorien @Solene

1 Like

You want systemd.timers.<name>.wantedBy (no unitConfig).

Note that there are also options for after and bindsTo at the top level.

2 Likes

Ah indeed! That fixes it. The timer is now activated on mount and deactivated on umount. Here is the working snippet for the systemd part:

  systemd.timers.btrbk-mydisk = {      
    unitConfig = {
      ConditionPathIsReadWrite = "/mnt/backups/btrbk";
      After = "mnt-backups.mount";
      BindsTo = "mnt-backups.mount";                    
    };
    wantedBy = [ "mnt-backups.mount" ];
  };
1 Like

and when using the top level options for after and bindsTo:

  systemd.timers.btrbk-mydisk = {      
    unitConfig.ConditionPathIsReadWrite = "/mnt/backups/btrbk";  
    after = [ "mnt-backups.mount" ];
    bindsTo = [ "mnt-backups.mount" ];
    wantedBy = [ "mnt-backups.mount" ];
  };
1 Like