Page 1 sur 1

[btrfs, snapshot, systemd] unit qui fait tout (en cours)

Publié : jeu. 31 juil. 2014, 12:17
par Moviuro
Plop,

Dans ma quête de stabilité, il faut que j'arrive à mettre en place des snapshots bien avec rétention cyclique et être capable de booter sur un vieux snapshot (ça, c'est prévu dans le wiki).
Pour les snapshots, grosse marrade : c'est pas facile si on veut le faire à la mode systemd.

Il y a dans ce post des informations qui touchent à BTRFS qui ne sont pas nécessaires à la résolution de mon problème.

Je suppose que les sous-volumes sont répartis ainsi (compréhension non nécessaire à la résolution de mon problème) :

Code : Tout sélectionner

Subvolid 5
* dossier home/
** sous-volume __active/
** sous-volume __snapshot.0/
** sous-volume <etc...>
* dossier var/
** sous-volume __active/
** idem
* <etc...>
Problème :
Je veux une unit simple, propre qui permette de gérer finement les snapshots de mes sous-volumes. (si vous avez une solution entièrement différente je suis preneur !!)


Ma solution :
Voilà mon unit actuelle et j'aiemrais l'améliorer puisqu'elle initialise mal (ça plante) :

Code : Tout sélectionner

snap@.service
[Unit]
Description=Snapshot management of the %f subvolume

[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
Environment=BTRFS_ROOT=/mnt/btrfs
Environment=ACTIVE="__active"
Environment=MAX_NUM=5
Type=oneshot
ExecStart=/usr/bin/bash -c 'btrfs subvolume delete ${BTRFS_ROOT}/%f.${MAX_NUM}; for (( NUM=$((${MAX_NUM}-1)); NUM >= 0; NUM-- )); do mv ${BTRFS_ROOT}/%f.$NUM ${BTRFS_ROOT}/%f.$(($NUM+1)); done; btrfs subvolume snapshot ${BTRFS_ROOT}/%f.1/../${ACTIVE} ${BTRFS_ROOT}/%f.0'
La commande suivante va lancer les snapshots sur home avec le nom custom :

Code : Tout sélectionner

# systemctl start snap@home-__custom.service
Ça va :
  • Dégager le sous-volume home/__custom.5 s'il existe btrfs subvolume delete ${BTRFS_ROOT}/%f.${MAX_NUM};
  • déplacer tous les snapshots pour incrémenter leur numéro (__custom.0 -> __custom.1) for (( NUM=$((${MAX_NUM}-1)); NUM >= 0; NUM-- )); do mv ${BTRFS_ROOT}/%f.$NUM ${BTRFS_ROOT}/%f.$(($NUM+1)); done
  • Snapshot-ter home/__active vers home/__custom.0 btrfs subvolume snapshot ${BTRFS_ROOT}/%f.1/../${ACTIVE} ${BTRFS_ROOT}/%f.0
Le gros problème est sur le dernier point: pour atteindre home/__active, je passe par home/__custom.1 (dans le code : ${BTRFS_ROOT}/%f.1/../${ACTIVE} = /mnt/btrfs/home/__custom.1/../__active = /mnt/btrfs/home/__active).

Y aurait-il donc moyen de changer ce comportement ? (à l'aide de systemd ou d'une commande à insérer dans ma ligne de bash)

Re: [btrfs, snapshot, systemd] unit magique qui fait tout

Publié : ven. 01 août 2014, 15:19
par Moviuro
Voilà, j'ai trouvé :)

Code : Tout sélectionner

/etc/systemd/system/snap@.service
[Unit]
Description=Snapshot management of the %f subvolume
After=multi-user.target

[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
Environment=BTRFS_ROOT=/mnt/btrfs
Environment=ACTIVE=__active
Environment=MAX_NUM=5
Type=oneshot
ExecStart=/usr/local/bin/snap.sh ${BTRFS_ROOT} ${ACTIVE} ${MAX_NUM} %f

[Install]
WantedBy=multi-user.target

Code : Tout sélectionner

/usr/local/bin/snap.sh
#!/bin/bash
BTRFS_ROOT=$1
ACTIVE=$2
MAX_NUM=$3
VOLUME=$4

# Remove oldest snapshot
echo "Removing oldest snapshot: ${BTRFS_ROOT}/${VOLUME}.${MAX_NUM}"
btrfs subvolume delete ${BTRFS_ROOT}/${VOLUME}.${MAX_NUM}

# Increment snapshot's number
for (( NUM=$((${MAX_NUM}-1)); NUM >= 0; NUM-- ));
do
        echo "Moving snapshot: ${BTRFS_ROOT}/${VOLUME}.$NUM"
        mv ${BTRFS_ROOT}/${VOLUME}.$NUM ${BTRFS_ROOT}/${VOLUME}.$(($NUM+1));
done;

# New snapshot
echo "Taking snapshot: ${BTRFS_ROOT}/`dirname ${VOLUME}`/${ACTIVE}"
btrfs subvolume snapshot ${BTRFS_ROOT}/`dirname ${VOLUME}`/${ACTIVE} ${BTRFS_ROOT}/${VOLUME}.0

Code : Tout sélectionner

# systemctl start snap@home-__hourly.service
# ls /mnt/btrfs/home
__active/  __hourly.0/
# systemctl start snap@home-__hourly.service
# ls /mnt/btrfs/home
__active/  __hourly.0/  __hourly.1/
# [...] et avec un peu de conf en plus...
# ls /mnt/btrfs/home/ 
__active/  __daily.0/  __hourly.0/  __hourly.1/  __hourly.2/  __hourly.3/  __hourly.4/  __hourly.5/  __hourly.6/
Unit à mettre dans un timer, donc (https://wiki.archlinux.fr/Systemd/cron) ou à enable (systemctl enable snap@root-__successful_boot.service).
C'est magique, ça fait tout :D (et c'est relativement configurable ;) )
++

Re: [btrfs, snapshot, systemd] unit qui fait tout (en cours)

Publié : jeu. 28 août 2014, 00:32
par Moviuro
Bon, après avoir le le Bash scripting guide, compris comment utiliser intelligemment les sous-volumes BTRFS, voilà ce que j'ai pondu :

/usr/local/bin/btrfs-snap.sh

Code : Tout sélectionner

#!/usr/bin/env bash
# Author Moviuro (<echo bW92aXVybytnaXRodWJAZ21haWwuY29tCg== | base64 -d>)

#set -xv

bold=$(tput bold)
normal=$(tput sgr0)
current=".current"
max_num="5"
snap_name="__snapshot"
readonly="0"
change_fstab="0"
manual="0"
verbosity="0"
debug0="${bold}DEBUG0${normal}:"
error="${bold}ERROR${normal}:"
critical_error="${bold}CRITICAL ERROR${normal}:"

usage="BTRFS-snap is a short bash script that implements simple cyclical retention of
BTRFS snapshots.

Usage:
btrfs-snap [-mrv] [-f ${bold}file${normal} -p ${bold}path${normal}] [-n ${bold}number${normal}] ${bold}subvolume${normal} ${bold}destination${normal} [${bold}name${normal}]
btrfs-snap [-h]

Options:
-h               Display this help dialog
-m               Manual: do not check for a $current file in ${bold}subvolume${normal}
-r               Read-only: the final snapshot will be ro
-v               Increase verbosity
-f ${bold}file${normal} -p ${bold}path${normal}  If ${bold}subvolume${normal} contains the fstab at ${bold}subvolume${normal}/${bold}path${normal}, it will be
                 replaced by ${bold}file${normal}. ${bold}file${normal} is mostly your current fstab with some
                 '${bold}@snap_name@${normal}' strings that will be replaced by btrfs-snap.
-n ${bold}number${normal}        Indicate how many snapshots are to be kept. If there are
                 already more snapshots than the indicated number, the ones
                 with bigger numbers will be kept.
                 Defaults to $max_num

Arguments:
${bold}subvolume${normal}        Absolute path of the subvolume to snapshot
${bold}destination${normal}      Absolute path of the destination folder of the snapshot
[${bold}name${normal}]           Name of the snapshot.
                 Defaults to $snap_name"

show_usage() {
  echo "$usage"
  exit 0
}

fail() {
  echo "$usage" >&2
  exit 1
}

need_root() {
  (( verbosity )) && echo "$debug0 Checking if I'm root..."
  if (( UID )); then
    echo "$error Sorry, I need to be root to take snapshots, aborting..." >&2
    exit 2
  fi
}

check_fstab() {
  (( verbosity )) && echo "$debug0 Checking if fstab is available and can be changed..."
  if (( change_fstab )); then
    if [[ ! -f "$subvolume/$fstab_path" ]]; then
      echo "$error There is no fstab to be changed at $subvolume/$fstab_path, aborting..." >&2
      exit 31
    fi
    if [[ ! -f $fstab_file ]]; then
      echo "$error There is no fstab to use at $fstab_file, aborting..." >&2
      exit 32
    fi
  fi
}

check_current() {
  (( verbosity )) && (( ! manual )) && echo "$debug0 Checking if the $current file exists..."
  if [[ ! -f "$subvolume/$current" ]] && (( ! manual )); then
    echo "$error $subvolume has no $current file, aborting..." >&2
    exit 4
  fi
}

check_directory() {
  (( verbosity )) && echo "$debug0 Checking if $1 exists and is a directory..."
  if [[ ! -d $1 ]]; then
    echo "$error Argument $1 is not a directory, aborting..." >&2
    exit 5
  fi
}

check_name() {
  (( verbosity )) && echo "$debug0 Checking if $1 is an acceptable name for the snapshot..."
  case "$1" in
    .|..|*/*|*\\*|*\&*|*\<*|*\>*|*\|*|*$'\n'*)
      echo "$error $1 is not an acceptable name for a snapshot, aborting..." >&2
      exit 6
      ;;
  esac
}

check_commands() {
  (( verbosity )) && echo "$debug0 Checking if all commands are available..."
  if ! hash btrfs; then
    echo "$error btrfs is nowhere to be found, please make sure it is installed." >&2
    exit 7
  fi
}

btrfs_() {
  btrfs "$@" || { status="$?" ; echo "$critical_error btrfs failed; $destination might be dirty and everything might be f*cked up, aborting..." >&2 ; exit "$status" ; }
}

exists() {
  [[ -e $1 ]]
}

check_clean() {
  (( verbosity )) && echo "$debug0 Checking if $destination is clean of any $snap_name*.tmp..."
  if exists "$destination/$snap_name"*.tmp; then
    echo "$error $destination is not clean, aborting..." >&2
    exit 8
  fi
}

check_number() {
  case $1 in
    *[!0-9]*|'')
      echo "$error -n requires a number; $1 does not appear to be one..." >&2
      exit 9
      ;;
    *)
      max_num=$1
      ;;
  esac
}

check_only_instance() {
  (( verbosity )) && echo "$debug0 Checking if btrfs-snap can safely run its round..."
  [[ -f "$destination/$snap_name" ]] && echo "$error btrfs-snap is already running OR (way worse) the last session failed, aborting...
If you are ${bold}absolutely sure${normal} that btrfs-snap is not running and that everything is clean, remove the $destination/$snap_name file." >&2 && exit 10
  touch "$destination/$snap_name"
}

clean_only_instance() {
  (( verbosity )) && echo "$debug0 Removing the lock at $destination/$snap_name..."
  rm "$destination/$snap_name"
}

clean_current() {
  (( ! manual )) && (( verbosity )) && echo "$debug0 Cleaning $destination/$snap_name.tmp/$current"
  (( ! manual )) && rm "$destination/$snap_name.tmp/$current"
}

update_fstab() {
  #usage: update_fstab word_to_put_in_the_fstab name_of_the_volume_where_the_fstab_must_be_changed
  (( verbosity )) && (( change_fstab )) && echo "$debug0 Updating fstab in $destination/$2/$fstab_path..."
  (( change_fstab )) && sed "s/@snap_name@/$1/g" "$fstab_file" > "$destination/$2/$fstab_path"
}

snap_as_ro_or_rw() {
  if (( readonly )); then
    btrfs_ subvolume snapshot -r "$1" "$2"
  else
    btrfs_ subvolume snapshot    "$1" "$2"
  fi
}

while getopts "f:hvmn:p:r" opt; do
  case "$opt" in
    m)
      ((manual++))
      ;;
    r)
      ((readonly++))
      ;;
    f)
      ((change_fstab++))
      fstab_file="$OPTARG"
      ;;
    p)
      fstab_path="$OPTARG"
      ;;
    h)
      show_usage
      ;;
    n)
      check_number "$OPTARG"
      ;;
    v)
      ((verbosity++))
      ;;
    \?)
      fail
      ;;
  esac
done

(( verbosity )) && echo "$debug0 Done parsing options..."

shift "$((OPTIND-1))" # Shift off the options and optional --.

check_commands

need_root

subvolume="$1"
destination="$2"

check_directory "$subvolume"
check_directory "$destination"

if [[ -n "$3" ]]; then
  snap_name="$3"
fi

check_name "$snap_name"

check_fstab

check_current

check_only_instance

check_clean

## create snapshot of subvolume in destination/name.tmp
btrfs_ subvolume snapshot "$subvolume" "$destination/$snap_name.tmp"

## clean up the files that indicate that the subvolume is currently active and some other links
clean_current

## change fstab in the temporary snapshot
update_fstab "$snap_name.0" "$snap_name.tmp"

## move all older snapshots; optionnaly update their fstab too
if [[ -d "$destination/$snap_name.$max_num" ]]; then
  btrfs_ subvolume delete "$destination/$snap_name.$max_num"
fi

# case where we have to change the fstab
if (( change_fstab )); then
  for (( num = max_num - 1 ; num >= 0 ; num-- ))
  do
    if [[ -d "$destination/$snap_name.$num" ]];then
      # snapshot as rw, update fstab
      btrfs_ subvolume snapshot "$destination/$snap_name.$num" "$destination/$snap_name.$((num+1)).tmp"
      update_fstab "$snap_name.$((num+1))" "$snap_name.$((num+1)).tmp"
      snap_as_ro_or_rw "$destination/$snap_name.$((num+1)).tmp" "$destination/$snap_name.$((num+1))"
      #clean
      btrfs_ subvolume delete "$destination/$snap_name.$num" "$destination/$snap_name.$((num+1)).tmp"
    fi
  done
  #no fstab to change
  else
    for (( num= max_num - 1 ; num >= 0; num-- ))
    do
      if [[ -d "$destination/$snap_name.$num" ]];then
        snap_as_ro_or_rw "$destination/$snap_name.$num" "$destination/$snap_name.$((num+1))"
        #clean
        btrfs_ subvolume delete "$destination/$snap_name.$num"
      fi
  done
fi

## snapshot the tmp snapshot into its final destination with (or without ro)
snap_as_ro_or_rw "$destination/$snap_name.tmp" "$destination/$snap_name.0"
btrfs_ subvolume delete "$destination/$snap_name.tmp"
clean_only_instance
(( verbosity )) && echo "$debug0 Successfully ran a cyclical snapshot round of $subvolume in $destination under name $snap_name with $max_num snapshots..."
(( ! verbosity )) && echo "Successful round of the $name btrfs-snap on $subvolume."
exit 0
et /etc/systemd/system/mark-current@.service Attention, c'est FAUX pour le moment, mais l'idée est là

Code : Tout sélectionner

[Unit]
Description=Add a file to %f to specify it is the one currently in use
After=multi-user.target

[Service]
Environment=current=.current
ExecStart=/usr/bin/touch %f/${current}
ExecStop=/usr/bin/rm %f/${current}

[Install]
WantedBy=multi-user.target
Il faut alors par exemple enable mark-current@-home.service et utiliser un timer qui se lance toutes les heures avec :

Code : Tout sélectionner

/usr/local/bin/btrfs-snap.sh -rv -n24 /mnt/btrfs/home/__active /mnt/btrfs/home __hourly
Autre exemple :

Code : Tout sélectionner

btrfs-snap.sh -vmrf /root/fstab -p etc/fstab -n3 /mnt/btrfs/root/__active /mnt/btrfs/root __test
Je mettrai ça dans le thread des créations et autres scripts d'ici peu, et aussi, je pousserai tout ça sur github et AUR... :D

Re: [btrfs, snapshot, systemd] unit qui fait tout (en cours)

Publié : jeu. 28 août 2014, 18:29
par Moviuro

Code : Tout sélectionner

#!/usr/bin/env bash
# Author Moviuro (<echo bW92aXVybytnaXRodWJAZ21haWwuY29tCg== | base64 -d>)

#set -xv

bold=$(tput bold)
normal=$(tput sgr0)
active="__active"
max_num="5"
snap_name="__snapshot"
readonly="0"
change_fstab="0"
fstab_file="/usr/local/etc/btrfs-snap/fstab"
fstab_path="etc/fstab"
manual="0"
verbosity="0"
debug0="${bold}DEBUG0${normal}:"
error="${bold}ERROR${normal}:"
critical_error="${bold}CRITICAL ERROR${normal}:"

usage="BTRFS-snap is a short bash script that implements simple cyclical retention of
BTRFS snapshots.

Usage:
btrfs-snap [-mrv] [-a ${bold}active${normal}] [-f ${bold}file${normal}] [-p ${bold}path${normal}] [-n ${bold}number${normal}] ${bold}subvolume${normal} ${bold}destination${normal} [${bold}name${normal}]
btrfs-snap [-h]

Options:
-a ${bold}active${normal}        Specify the name of the active (current) subvolume. If ${bold}active${normal}
                 does not appear in the mount information, the script will
                 abort.
                 -m overrides this behavior.
                 Defaults to $active
-f ${bold}file${normal} -p ${bold}path${normal}  If ${bold}subvolume${normal} contains the fstab at ${bold}subvolume${normal}/${bold}path${normal}, it will be
                 replaced by ${bold}file${normal}. ${bold}file${normal} is mostly your active fstab with some
                 '${bold}@snap_name@${normal}' strings that will be replaced by btrfs-snap.
                 ${bold}file${normal} defaults to $fstab_file
                 ${bold}path${normal} defaults to $fstab_path
-h               Display this help dialog and exit
-m               Manual: do not check for a $active subvolume in the mount
                 information
-n ${bold}number${normal}        Indicate how many snapshots are to be kept. If there are
                 already more snapshots than the indicated number, the ones
                 with bigger numbers will be kept.
                 Defaults to $max_num
-r               Read-only: the final snapshot will be ro
-v               Increase verbosity

Arguments:
${bold}subvolume${normal}        Absolute path of the subvolume to snapshot
${bold}destination${normal}      Absolute path of the destination folder of the snapshot
[${bold}name${normal}]           Name of the snapshot.
                 Defaults to $snap_name"

show_usage() {
  echo "$usage"
  exit 0
}

fail() {
  echo "$usage" >&2
  exit 1
}

need_root() {
  (( verbosity )) && echo "$debug0 Checking if I'm root..."
  if (( UID )); then
    echo "$error Sorry, I need to be root to take snapshots, aborting..." >&2
    exit 2
  fi
}

check_fstab() {
  (( verbosity )) && echo "$debug0 Checking if fstab is available and can be changed..."
  if [[ -f "$subvolume/$fstab_path" ]]; then
    (( verbosity )) && echo "$debug0 I found a fstab at $subvolume/${fstab_path}..."
    if [[ -f $fstab_file ]]; then
      (( verbosity )) && echo "$debug0 There is a fstab to use at ${fstab_file}..."
      ((change_fstab++))
      (( verbosity )) && echo "$debug0 I will replace $subvolume/${fstab_path} with ${fstab_file}..."
    fi
  fi
  (( ! change_fstab )) && (( verbosity )) && echo "$debug0 I will not replace any fstab (didn't find one)..."
}

check_active() {
  (( verbosity )) && (( ! manual )) && echo "$debug0 Checking if $subvolume is an $active subvolume..."
  if (( ! manual )) && ! findmnt -noFSROOT $subvolume | grep -q $active ; then
    echo "$error $subvolume is not an $active subvolume, aborting..." >&2
    exit 4
  fi
}

check_directory() {
  (( verbosity )) && echo "$debug0 Checking if $1 exists and is a directory..."
  if [[ ! -d $1 ]]; then
    echo "$error Argument $1 is not a directory, aborting..." >&2
    exit 5
  fi
}

check_name() {
  (( verbosity )) && echo "$debug0 Checking if $1 is an acceptable name for a directory..."
  case "$1" in
    .|..|*/*|*\\*|*\&*|*\<*|*\>*|*\|*|*$'\n'*)
      echo "$error $1 is not an acceptable name for a snapshot, aborting..." >&2
      exit 6
      ;;
  esac
}

check_commands() {
  (( verbosity )) && echo "$debug0 Checking if all commands are available..."
  for cmd in btrfs findmnt; do
    if ! hash btrfs; then
      echo "$error $cmd is nowhere to be found, please make sure it is installed." >&2
      exit 7
    fi
  done
}

btrfs_() {
  btrfs "$@" || { status="$?" ; echo "$critical_error btrfs failed; $destination might be dirty and everything might be f*cked up, aborting..." >&2 ; exit "$status" ; }
}

exists() {
  [[ -e $1 ]]
}

check_clean() {
  (( verbosity )) && echo "$debug0 Checking if $destination is clean of any $snap_name*.tmp..."
  if exists "$destination/$snap_name"*.tmp; then
    echo "$error $destination is not clean, aborting..." >&2
    exit 8
  fi
}

check_number() {
  case $1 in
    *[!0-9]*|'')
      echo "$error -n requires a number; $1 does not appear to be one..." >&2
      exit 9
      ;;
    *)
      max_num=$1
      ;;
  esac
}

check_only_instance() {
  (( verbosity )) && echo "$debug0 Checking if btrfs-snap can safely run its round..."
  [[ -f "$destination/$snap_name" ]] && echo "$error btrfs-snap is already running OR (way worse) the last session failed, aborting...
If you are ${bold}absolutely sure${normal} that btrfs-snap is not running and that everything is clean, remove the $destination/$snap_name file." >&2 && exit 10
  touch "$destination/$snap_name"
}

clean_only_instance() {
  (( verbosity )) && echo "$debug0 Removing the lock at $destination/$snap_name..."
  rm "$destination/$snap_name"
}

touch_created() {
  (( verbosity )) && echo "$debug0 Creating the timestamp file on the new snapshot..."
  touch "$destination/$snap_name.tmp/created_by_btrfs-snap"
}

update_fstab() {
  #usage: update_fstab word_to_put_in_the_fstab name_of_the_volume_where_the_fstab_must_be_changed
  (( verbosity )) && (( change_fstab )) && echo "$debug0 Updating fstab in $destination/$2/$fstab_path..."
  (( change_fstab )) && sed "s/@snap_name@/$1/g" "$fstab_file" > "$destination/$2/$fstab_path"
}

snap_as_ro_or_rw() {
  (( verbosity )) && echo "$debug0 Final snapshotting into $2..."
  if (( readonly )); then
    btrfs_ subvolume snapshot -r "$1" "$2"
  else
    btrfs_ subvolume snapshot    "$1" "$2"
  fi
}

while getopts "a:f:hvmn:p:r" opt; do
  case "$opt" in
    a)
      check_name "$OPTARG"
      active="$OPTARG"
      ;;
    m)
      ((manual++))
      ;;
    r)
      ((readonly++))
      ;;
    f)
      fstab_file="$OPTARG"
      ;;
    p)
      fstab_path="$OPTARG"
      ;;
    h)
      show_usage
      ;;
    n)
      check_number "$OPTARG"
      ;;
    v)
      ((verbosity++))
      ;;
    \?)
      fail
      ;;
  esac
done

(( verbosity )) && echo "$debug0 Done parsing options..."

shift "$((OPTIND-1))" # Shift off the options and optional --.

check_commands

need_root

subvolume="$1"
destination="$2"

check_directory "$subvolume"
check_directory "$destination"

if [[ -n "$3" ]]; then
  snap_name="$3"
fi

check_name "$snap_name"

check_fstab

check_active

check_only_instance

check_clean

## create snapshot of subvolume in destination/name.tmp
btrfs_ subvolume snapshot "$subvolume" "$destination/$snap_name.tmp"
touch_created

## change fstab in the temporary snapshot
update_fstab "$snap_name.0" "$snap_name.tmp"

## move all older snapshots; optionnaly update their fstab too
if [[ -d "$destination/$snap_name.$max_num" ]]; then
  (( verbosity )) && echo "$debug0 Removing oldest snapshot: $destination/$snap_name.$max_num..."
  btrfs_ subvolume delete "$destination/$snap_name.$max_num"
fi

# case where we have to change the fstab
if (( change_fstab )); then
  for (( num = max_num - 1 ; num >= 0 ; num-- ))
  do
    if [[ -d "$destination/$snap_name.$num" ]];then
      # snapshot as rw, update fstab
      btrfs_ subvolume snapshot "$destination/$snap_name.$num" "$destination/$snap_name.$((num+1)).tmp"
      update_fstab "$snap_name.$((num+1))" "$snap_name.$((num+1)).tmp"
      snap_as_ro_or_rw "$destination/$snap_name.$((num+1)).tmp" "$destination/$snap_name.$((num+1))"
      #clean
      btrfs_ subvolume delete "$destination/$snap_name.$num" "$destination/$snap_name.$((num+1)).tmp"
    fi
  done
  #no fstab to change
  else
    for (( num= max_num - 1 ; num >= 0; num-- ))
    do
      if [[ -d "$destination/$snap_name.$num" ]];then
        snap_as_ro_or_rw "$destination/$snap_name.$num" "$destination/$snap_name.$((num+1))"
        #clean
        btrfs_ subvolume delete "$destination/$snap_name.$num"
      fi
  done
fi

## snapshot the tmp snapshot into its final destination with (or without ro)
snap_as_ro_or_rw "$destination/$snap_name.tmp" "$destination/$snap_name.0"
btrfs_ subvolume delete "$destination/$snap_name.tmp"
clean_only_instance
(( verbosity )) && echo "$debug0 Successfully ran a cyclical snapshot round of $subvolume in $destination under name $snap_name with $max_num snapshots..."
(( ! verbosity )) && echo "Successful round of the $name btrfs-snap on $subvolume."
exit 0
Petite MAJ du code, et surtout les unit systemd:

Code : Tout sélectionner

[Unit]
Description=Daily snapshot management of the %f subvolume
After=multi-user.target

[Service]
Nice=19
IOSchedulingClass=idle
IOSchedulingPriority=7
Environment=fstab_file=/usr/local/etc/btrfs-snap/fstab
Environment=fstab_path=etc/fstab
Environment=active=__active
Environment=max_num=15
Environment=destination=/mnt/btrfs%f
Environment=name=__daily
Type=oneshot
ExecStart=/usr/local/bin/btrfs-snap.sh -rv -f ${fstab_file} -p ${fstab_path} -a ${active} -n ${max_num} %f ${destination} ${name}

[Install]
WantedBy=multi-user.target
(copier-coller en remplaçant daily par hourly ou weekly...)

Et avec un peu de conf, ça passe :D