Compare commits
60 Commits
c08ac04879
...
main
Author | SHA1 | Date | |
---|---|---|---|
1ed851a388 | |||
4b09edb962 | |||
e90697ae59 | |||
da27f61fdb | |||
4b23888a13 | |||
2d18b32051 | |||
4cd065ab77 | |||
62e31fdfba | |||
2ab3bf7d29 | |||
1aad3d96fa | |||
a5c00566ce | |||
0084293ecb | |||
3ca035e59a | |||
b60f4011e2 | |||
a639bb05c2 | |||
98769cc028 | |||
b7e480db73 | |||
dd3a6a2fdc | |||
7c6728148c | |||
f5a852e48a | |||
15a0658903 | |||
7c5fd18c4e | |||
31d1843e88 | |||
4c49199a35 | |||
a4d8881971 | |||
14906d0645 | |||
75549baba6 | |||
b84b4ddfec | |||
6fde230d4d | |||
65c23b744a | |||
fec08d6873 | |||
2fcb72de5c | |||
2e9ae9c965 | |||
79aaa3a146 | |||
6f1f387e22 | |||
923aa36bec | |||
69dc859a97 | |||
fa6c2a0b12 | |||
dffd1037a2 | |||
d7eccfd4fc | |||
da25107a83 | |||
034431a935 | |||
120e057ea2 | |||
23247bcb9b | |||
221fd22ba5 | |||
6e1d973f61 | |||
a817abbe2d | |||
1e2343f908 | |||
ef67fc87b1 | |||
b645d1f106 | |||
af290e0fe9 | |||
aecb871de1 | |||
24483b08bb | |||
754243de52 | |||
4326841b46 | |||
682b3f107e | |||
5930637ded | |||
d3f5709b72 | |||
68ac6b7bca | |||
02e330de61 |
72
DOCUMENTATION_DE.md
Normal file
72
DOCUMENTATION_DE.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Konfiguration auf dem Zielserver
|
||||
|
||||
1. Öffnen Sie eine SSH-Verbindung zum Zielserver, entweder über die Befehlszeile oder ein SSH-Tool wie PuTTY.
|
||||
|
||||
2. Stellen Sie sicher, dass der Zielserver die erforderlichen Voraussetzungen erfüllt. Dazu gehören das Vorhandensein der benötigten Befehle (`zfs`, `ssh`, `grep`) und die korrekte Konfiguration der Pfade (`PATH`-Variable im Script).
|
||||
|
||||
3. Erstellen Sie eine Konfigurationsdatei für das Script. Standardmäßig wird die Datei `/etc/bashclub/zsync.conf` verwendet. Sie können jedoch einen anderen Pfad angeben, indem Sie den Parameter `-c` beim Aufruf des Scripts verwenden. Zusätzlich können Sie weitere Konfigurationsdateien erstellen, um unterschiedliche Replikationen einzurichten. Zum Beispiel: `/usr/bin/bashclub-zsync -c /pfad/zur/konfiguration1.conf`, `/usr/bin/bashclub-zsync -c /pfad/zur/konfiguration2.conf`
|
||||
|
||||
4. Öffnen Sie die Konfigurationsdatei mit einem Texteditor und passen Sie die folgenden Einstellungen an:
|
||||
|
||||
- `source`: Geben Sie den SSH-Adresse des Quellservers an, von dem die Daten repliziert werden sollen. Beispiel: `source=user@host`
|
||||
- `target`: Geben Sie die Pfad des Ziel-ZFS-Dateisystems auf dem Zielserver an, zu dem die Daten repliziert werden sollen. Beispiel: `target=pool/dataset`
|
||||
- `sshport`: Geben Sie den SSH-Port des Quellservers an. Standardmäßig ist dies `22`, aber Sie können ihn entsprechend anpassen.
|
||||
- `tag`: Geben Sie den ZFS-Tag an, der verwendet werden soll, um die zu replizierenden Dateisysteme oder Volumes zu identifizieren. Beispiel: `tag=bashclub:zsync`
|
||||
- `snapshot_filter`: Geben Sie eine Pipe-separierte Liste von Snapshot-Namenfiltern an, die bestimmen, welche Snapshots repliziert werden sollen. Beispiel: `snapshot_filter="hourly|daily|weekly|monthly"`
|
||||
- `min_keep`: Geben Sie die Mindestanzahl von Snapshots pro Filter an, die beibehalten werden sollen. Beispiel: `min_keep=3`
|
||||
- `zfs_auto_snapshot_keep`: Aktiviert das erzeugen eines Snapshots auf der Quelle vor der Replikation, gibt die Anzahl der Snapshots an, die behalten werden sollen. Beispiel: `zfs_auto_snapshot_keep=0` => Deaktiviert die Funktion, `zfs_auto_snapshot_keep=7` behält 7 Snapshots.
|
||||
- `zfs_auto_snapshot_label`: Definniert das Label des Snapshots, Default-Wert ist `backup` (ergibt: zfs-auto-snap_backup-YYYY-MM-dd-hhmm). Beispiel: `zfs_auto_snapshot_label=backup`
|
||||
|
||||
Wiederholen Sie diese Schritte für jede zusätzliche Konfigurationsdatei, um unterschiedliche Replikationen einzurichten.
|
||||
|
||||
5. Speichern Sie die Konfigurationsdateien.
|
||||
|
||||
6. Überprüfen Sie, ob der Zielserver die erforderlichen ZFS-Datasets oder Volumes enthält, auf die die Daten repliziert werden sollen. Stellen Sie sicher, dass die Namen der Datasets/Volumes dem ZFS-Tag entsprechen, den Sie in den Konfigurationsdateien festgelegt haben.
|
||||
|
||||
7. Um das Script automatisch auszuführen, erstellen Sie eine Cronjob-Konfigurationsdatei im Verzeichnis `/etc/cron.d/`. Öffnen Sie eine neue Datei mit einem Texteditor und geben Sie die gewünschte Ausführungszeit und den Befehl ein. Beispiel:
|
||||
|
||||
a) Erstellen Sie das Verzeichnis `/var/log/bashclub-zsync`, falls es noch nicht existiert. Verwenden Sie den Befehl:
|
||||
```plaintext
|
||||
sudo mkdir -p /var/log/bashclub-zsync
|
||||
```
|
||||
|
||||
b) Öffnen Sie die Cronjob-Konfigurationsdatei mit dem Befehl:
|
||||
```plaintext
|
||||
sudo nano /etc/cron.d/bashclub-zsync-cronjob
|
||||
```
|
||||
|
||||
c) Fügen Sie den folgenden Inhalt in die Datei ein:
|
||||
```plaintext
|
||||
SHELL=/bin/bash
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
0 * * * * root /usr/bin/bashclub-zsync -c /etc/bashclub/zsync.conf >> /var/log/bashclub-zsync/zsync.log 2>&1
|
||||
```
|
||||
|
||||
In diesem Beispiel wird das Script einmal pro Stunde ausgeführt. Der Befehl `/usr/bin/bashclub-zsync -c /etc/bashclub/zsync.conf` wird als root-Benutzer ausgeführt, und die Ausgabe wird in die Datei `/var/log/bashclub-zsync/zsync.log` umgeleitet.
|
||||
|
||||
d) Speichern Sie die Datei und schließen Sie den Texteditor.
|
||||
|
||||
Das Script wird nun automatisch gemäß dem angegebenen Intervall ausgeführt, und die Ausgabe wird im angegebenen Logfile gespeichert. Stellen Sie sicher, dass die Dateiberechtigungen für die Cronjob-Konfigurationsdatei korrekt sind, damit sie von Cron erkannt wird.
|
||||
|
||||
# Konfiguration auf dem Quellserver
|
||||
|
||||
Um ZFS-Dateisysteme und Volumes für die Replikation mit dem bashclub-zsync-Script zu markieren, verwenden Sie das ZFS-Attribut "bashclub:zsync" auf dem Quellserver. Dieses Attribut kann mit dem Parameter "value" konfiguriert werden, der die Werte "subvols", "all" oder "exclude" haben kann.
|
||||
|
||||
Hier ist eine Anleitung zur Konfiguration auf dem Quellserver:
|
||||
|
||||
1. Identifizieren Sie das ZFS-Dateisystem oder Volume, das Sie für die Replikation markieren möchten.
|
||||
|
||||
2. Setzen Sie das ZFS-Attribut "bashclub:zsync" mit dem gewünschten Value-Parameter-Wert. Verwenden Sie den Befehl:
|
||||
```plaintext
|
||||
zfs set bashclub:zsync=<value> <datensatz>
|
||||
```
|
||||
Ersetzen Sie `<value>` durch einen der folgenden Werte: "subvols", "all" oder "exclude". Ersetzen Sie `<datensatz>` durch den Namen des ZFS-Datensatzes.
|
||||
|
||||
- "subvols": Markiert nur Volumes und Dateisysteme in der Hierarchie unterhalb des Datensatzes, für den das Attribut gesetzt ist (schließt den Wurzel-Datensatz aus).
|
||||
- "all": Markiert alle Volumes und Dateisysteme im ZFS-Datensatz einschließlich des Wurzel-Datensatzes.
|
||||
- "exclude": Schließt Volumes und Dateisysteme im ZFS-Datensatz aus, für den das Attribut gesetzt ist.
|
||||
|
||||
Durch die Markierung mit dem Attribut "bashclub:zsync" wird das betreffende ZFS-Dateisystem oder -Volume für die Replikation mit dem bashclub-zsync-Script berücksichtigt.
|
||||
|
||||
Bitte beachten Sie, dass die genaue Syntax und Verwendung des Befehls je nach dem von Ihnen verwendeten Betriebssystem oder der ZFS-Version variieren kann. Stellen Sie sicher, dass Sie über ausreichende Berechtigungen verfügen, um die Konfiguration auf dem Quellserver vorzunehmen.
|
||||
Um mehrere Replikationen zu unterschiedlichen Hosts mit dem bashclub-zsync-Script auf dem Zielserver zu ermöglichen, können Sie den Namen des ZFS-Attributs "bashclub:zsync" in der Scriptkonfiguration mit dem Parameter "tag" anpassen. Dadurch können Sie verschiedene Replikationen zu unterschiedlichen Hosts einrichten und steuern. Öffnen Sie das bashclub-zsync-Script auf dem Zielserver, suchen Sie nach dem "tag"-Parameter und ändern Sie den Wert in den gewünschten Namen für das ZFS-Attribut. Speichern Sie das Script nach der Änderung. Stellen Sie sicher, dass Sie über ausreichende Berechtigungen verfügen, um das Script zu bearbeiten und die Konfiguration auf dem Zielserver vorzunehmen.
|
72
README.md
72
README.md
@ -1,7 +1,71 @@
|
||||
---- THIS IS A CLONE OF THE ORIGINAL REPOSITORY ON git.bashclub.org ----
|
||||
|
||||
# zsync
|
||||
|
||||
ZFS replication script by Thorsten Spille <thorsten@spille-edv.de>
|
||||
- replicates ZFS filesystems/volumes with user parameter bashclub:zsync configured
|
||||
- mirrored replication with existing snapshots
|
||||
- pull replication only
|
||||
- creates full path on target pool
|
||||
- replicates ZFS filesystems/volumes with user parameter bashclub:zsync (or custom name) configured
|
||||
- creates optional snapshot before replication (required zfs-auto-znapshot)
|
||||
- parameter setting uses zfs hierarchy on source
|
||||
- mirrored replication with existing snapshots (filtered by snapshot_filter)
|
||||
- pull/local replication only
|
||||
- auto creates full path on target pool, enforce com.sun:auto-snapshot=false, inherits mountpoint and sets canmount=noauto
|
||||
- raw replication
|
||||
- tested on Proxmox VE 7.x/8.x
|
||||
- ssh cipher auto selection
|
||||
|
||||
## Installation
|
||||
|
||||
#### Download and make executable
|
||||
~~~
|
||||
wget -q --no-cache -O /usr/bin/bashclub-zsync https://git.bashclub.org/bashclub/zsync/raw/branch/dev/bashclub-zsync/usr/bin/bashclub-zsync
|
||||
chmod +x /usr/bin/bashclub-zsync
|
||||
bashclub-zsync
|
||||
~~~
|
||||
|
||||
## Configuration
|
||||
After first execution adjust the default config file `/etc/bashclub/zsync.conf`:
|
||||
|
||||
~~~
|
||||
# target path on local machine
|
||||
target=backup/px1
|
||||
|
||||
# source host
|
||||
source=user@host
|
||||
|
||||
# source host ssh port
|
||||
sshport=22
|
||||
|
||||
# tag to mark source filesystem
|
||||
tag=bashclub:zsync
|
||||
|
||||
# snapshot name filter
|
||||
snapshot_filter="hourly|daily|weekly|monthly"
|
||||
|
||||
# number of minimum snapshots to keep (per snapshot filter)
|
||||
min_keep=3
|
||||
|
||||
# number of zfs snapshots to keep on source (0 = snapshot function disabled)
|
||||
zfs_auto_snapshot_keep=0
|
||||
|
||||
# make snapshot via zfs-auto-snapshot before replication
|
||||
zfs_auto_snapshot_label="backup"
|
||||
|
||||
~~~
|
||||
|
||||
### Define a cronjob
|
||||
#### cron.d example
|
||||
File: /etc/cron.d/bashclub-zsync
|
||||
~~~
|
||||
00 23 * * * root /usr/bin/bashclub-zsync -c /etc/bashclub/zsync.conf > /var/log/bashclub-zsync/zsync.log
|
||||
~~~
|
||||
|
||||
#### cron.{hourly|daily|weekly|monthly}
|
||||
File: /etc/cron.hourly/bashclub-zsync
|
||||
~~~
|
||||
/usr/bin/bashclub-zsync -c /etc/bashclub/zsync.conf > /var/log/bashclub-zsync/zsync.log
|
||||
~~~
|
||||
|
||||
# Author
|
||||
|
||||
### Thorsten Spille
|
||||
[<img src="https://storage.ko-fi.com/cdn/brandasset/kofi_s_tag_dark.png" rel="Support me on Ko-Fi">](https://ko-fi.com/thorakel)
|
||||
|
9
bashclub-zsync/etc/logrotate.d/bashclub_zsync
Normal file
9
bashclub-zsync/etc/logrotate.d/bashclub_zsync
Normal file
@ -0,0 +1,9 @@
|
||||
/var/log/bashclub-zsync/*.log {
|
||||
weekly
|
||||
rotate 12
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 644 root root
|
||||
}
|
@ -8,6 +8,15 @@ PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
|
||||
prog="$(basename $0)"
|
||||
zfs=$(which zfs)
|
||||
ssh=$(which ssh)
|
||||
grep=$(which grep)
|
||||
uniq=$(which uniq)
|
||||
cut=$(which cut)
|
||||
tail=$(which tail)
|
||||
wc=$(which wc)
|
||||
tr=$(which tr)
|
||||
sed=$(which sed)
|
||||
zfs_auto_snapshot=$(which zfs-auto-snapshot)
|
||||
rc=0
|
||||
debug=
|
||||
|
||||
#### default config file, can be changed with parameter -c
|
||||
@ -26,12 +35,18 @@ sshport=22
|
||||
# zfs user parameter to identify filesystems/volumes to replicate
|
||||
tag=bashclub:zsync
|
||||
|
||||
# if $tag=subvols, which source to filter: "inherited" or "inherited|received"
|
||||
subvol_source="inherited|received"
|
||||
|
||||
# pipe separated list of snapshot name filters
|
||||
snapshot_filter="hourly|daily|weekly|monthly"
|
||||
|
||||
# minimum count of snapshots per filter to keep
|
||||
min_keep=3
|
||||
|
||||
# number of zfs snapshots to keep on source (0 or 1 = snapshot function disabled)
|
||||
zfs_auto_snapshot_keep=0
|
||||
|
||||
# make snapshot via zfs-auto-snapshot before replication
|
||||
zfs_auto_snapshot_label="backup"
|
||||
|
||||
usage() {
|
||||
cat >&2 <<-EOF
|
||||
usage: $prog [-h] [-d] [-c CONFIG]
|
||||
@ -56,91 +71,183 @@ while getopts "hdc:" opt; do
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
function log() {
|
||||
echo -e "$(date +'%b %d %T') $1"
|
||||
}
|
||||
|
||||
# load config file
|
||||
if [ -f $conf ]; then
|
||||
echo "Reading configuration $conf"
|
||||
log "[INFO] Reading configuration $conf"
|
||||
source $conf
|
||||
else
|
||||
mkdir -p $(dirname $conf)
|
||||
cat << EOF > $conf
|
||||
target=$target
|
||||
source=$source
|
||||
sshport=22
|
||||
sshport=$sshport
|
||||
tag=$tag
|
||||
subvol_source="$subvol_source"
|
||||
snapshot_filter="$snapshot_filter"
|
||||
min_keep=$min_keep
|
||||
zfs_auto_snapshot_keep=$zfs_auto_snapshot_keep
|
||||
zfs_auto_snapshot_label=$zfs_auto_snapshot_label
|
||||
EOF
|
||||
echo "Initial config file created. Please adjust and restart script. Exiting..."
|
||||
log "[INFO] Initial config file created. Please adjust and restart script. Exiting..."
|
||||
usage 0
|
||||
fi
|
||||
|
||||
if [[ $source == "" ]]; then
|
||||
echo "source is empty, switching to local mode."
|
||||
log "[INFO] source is empty, switching to local mode."
|
||||
ssh=
|
||||
sshport=
|
||||
echo -e "Configuration:\n\ttarget=$target\n\ttag=$tag\n\tsubvol_source=$subvol_source\n\tsnapshot_filter=$snapshot_filter\n"
|
||||
log "[INFO] Configuration:\n\ttarget=$target\n\ttag=$tag\n\tsnapshot_filter=$snapshot_filter\n\tmin_keep=$min_keep\nzfs_auto_snapshot_keep=$zfs_auto_snapshot_keep\nzfs_auto_snapshot_label=$zfs_auto_snapshot_label\n"
|
||||
else
|
||||
sshport=-p$sshport
|
||||
echo -e "Configuration:\n\ttarget=$target\n\tsource=$source\n\tsshport=$sshport\n\ttag=$tag\n\tsubvol_source=$subvol_source\n\tsnapshot_filter=$snapshot_filter\n"
|
||||
log "[INFO] Configuration:\n\ttarget=$target\n\tsource=$source\n\tsshport=$sshport\n\ttag=$tag\n\tsnapshot_filter=$snapshot_filter\n\tmin_keep=$min_keep\nzfs_auto_snapshot_keep=$zfs_auto_snapshot_keep\nzfs_auto_snapshot_label=$zfs_auto_snapshot_label\n"
|
||||
fi
|
||||
|
||||
# query source datasets/subvols to replicate
|
||||
local_os_id=$($grep -E "^ID=" /etc/os-release | $cut -d'=' -f2)
|
||||
remote_os_id=$($ssh $source $sshport "grep -E \"^ID=\" /etc/os-release | cut -d'=' -f2")
|
||||
|
||||
if [[ $local_os_id == "freebsd" ]]; then
|
||||
local_aes=$($grep -o AES /var/run/dmesg.boot | $uniq)
|
||||
else
|
||||
local_aes=$($grep -m1 -o aes /proc/cpuinfo | $uniq)
|
||||
fi
|
||||
|
||||
if [[ $remote_os_id == "freebsd" ]]; then
|
||||
remote_aes=$($ssh $source $sshport "grep -o AES /var/run/dmesg.boot | uniq")
|
||||
else
|
||||
remote_aes=$($ssh $source $sshport "grep -m1 -o aes /proc/cpuinfo | uniq")
|
||||
fi
|
||||
|
||||
if [[ $local_aes == "aes" ]] && [[ $remote_aes == "aes" ]]; then
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] Switching to cipher aes256-gcm@openssh.com"; fi
|
||||
sshcipher=-caes256-gcm@openssh.com
|
||||
else
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] Using default cipher chacha20-poly1305@openssh.com"; fi
|
||||
sshcipher=-cchacha20-poly1305@openssh.com
|
||||
fi
|
||||
|
||||
include_list="[INFO] Included datasets:\n"
|
||||
exclude_list="[INFO] Excluded datasets:\n"
|
||||
IFS=$'\n'
|
||||
for zvol in $($ssh $sshport $source "zfs get -H -o name,value,source -t filesystem,volume $tag"); do
|
||||
name=$(echo $zvol | cut -f1)
|
||||
if [[ "$(echo $zvol | cut -f2)" == "subvols" ]] && [[ $(echo $zvol | grep -E $subvol_source) ]]; then
|
||||
echo "Including $name"
|
||||
for zvol in $($ssh $sshcipher $sshport $source "zfs get -H -o name,value,source -t filesystem,volume $tag"); do
|
||||
name=$(echo $zvol | $cut -f1)
|
||||
if [[ "$(echo $zvol | $cut -f2)" == "subvols" ]] && [[ $(echo $zvol | $grep -vE "local|received") ]]; then
|
||||
include_list="${include_list}\t${name}\n"
|
||||
syncvols=("${syncvols[@]}" "$name")
|
||||
elif [[ "$(echo $zvol | cut -f2)" == "all" ]];then
|
||||
echo "Including $name"
|
||||
elif [[ "$(echo $zvol | $cut -f2)" == "all" ]] && [[ $(echo $zvol | $grep -v received) ]];then
|
||||
include_list="${include_list}\t${name}\n"
|
||||
syncvols=("${syncvols[@]}" "$name")
|
||||
else
|
||||
echo "Excluding $name"
|
||||
exclude_list="${exclude_list}\t${name}\n"
|
||||
fi
|
||||
done
|
||||
log "$include_list"
|
||||
log "$exclude_list"
|
||||
|
||||
if ! $zfs list $target > /dev/null 2>&1 ; then
|
||||
log "[DEBUG] $target does not exist. Creating..."
|
||||
$zfs create -o canmount=noauto -o com.sun:auto-snapshot=false $target
|
||||
else
|
||||
log "[DEBUG] $target exists, check auto-snapshot..."
|
||||
if [[ $($zfs get -H -o value,source com.sun:auto-snapshot $target) != "false local" ]]; then
|
||||
$zfs set com.sun:auto-snapshot=false $target
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $zfs_auto_snapshot_keep -gt 1 ]; then
|
||||
log "[DEBUG] Running zfs-auto-snapshot"
|
||||
$ssh $sshcipher $sshport $source "which zfs-auto-snapshot > /dev/null || exit 0 ; zfs-auto-snapshot --quiet --syslog --label=$zfs_auto_snapshot_label --keep=$zfs_auto_snapshot_keep //"
|
||||
if [[ $snapshot_filter == "" ]]; then
|
||||
snapshot_filter="$zfs_auto_snapshot_label"
|
||||
else
|
||||
snapshot_filter="$snapshot_filter|$zfs_auto_snapshot_label"
|
||||
fi
|
||||
fi
|
||||
|
||||
for name in "${syncvols[@]}"; do
|
||||
IFS=$' '
|
||||
if [ $($zfs list -H -s creation -t snapshot $target/$name > /dev/null 2>&1 ; echo $?) -gt 0 ]; then
|
||||
# create parent datasets
|
||||
prefix=""
|
||||
for part in $(echo $target/$(echo $name | cut -d'/' -f1) | sed "s/\// /g"); do
|
||||
if [ $($zfs list $prefix$part > /dev/null 2>&1 ; echo $?) -gt 0 ]; then
|
||||
echo "Creating $prefix$part"
|
||||
$zfs create -p $prefix$part
|
||||
fi
|
||||
prefix="$prefix$part/"
|
||||
done
|
||||
|
||||
# start initial replication
|
||||
IFS=$'\n'
|
||||
for snap in $($ssh $sshport $source "zfs list -H -t snapshot -o name -S creation $name | grep -E \"$snapshot_filter\" | tail -1"); do
|
||||
echo "Start initial replication: $snap => $target/$(echo $name | cut -d'/' -f1)"
|
||||
$ssh $sshport $source "zfs send -p $debug $snap" | $zfs receive -x mountpoint -x canmount -x $tag -x com.sun:auto-snapshot $debug -dF $target/$(echo $name | cut -d'/' -f1)
|
||||
done
|
||||
log "[INFO] Replicate $name"
|
||||
fstype=$($ssh $sshcipher $sshport $source zfs get -H -o value type $name)
|
||||
if [[ $fstype == "filesystem" ]]; then
|
||||
mp=-xmountpoint
|
||||
cm=-ocanmount=noauto
|
||||
else
|
||||
mp=
|
||||
cm=
|
||||
fi
|
||||
|
||||
# replicate incremental
|
||||
guid=$($zfs list -H -o guid -s creation -t snapshot $target/$name | tail -1)
|
||||
last=$($ssh $sshport $source "zfs list -H -o name,guid -t snapshot $name | grep $guid | tail -1 | cut -f1")
|
||||
IFS=$'\n'
|
||||
for snap in $($ssh $sshport $source "zfs list -H -o name,guid -s creation -t snapshot $name | grep -E \"$snapshot_filter\" | grep --after-context=200 $guid | grep -v $guid | cut -f1"); do
|
||||
echo "Replicating delta of $last <=> $snap to $target/$name"
|
||||
$ssh $sshport $source "zfs send $debug -i $last $snap" | zfs receive -x mountpoint -x canmount -x $tag -x com.sun:auto-snapshot -F $debug $target/$name
|
||||
last=$snap
|
||||
done
|
||||
if [[ $($ssh $sshcipher $sshport $source "zfs list -H -t snapshot -o name -S creation $name 2>/dev/null | grep -E \"@.*($snapshot_filter)\" | wc -l | tr -d ' '") -gt 0 ]]; then
|
||||
IFS=$' '
|
||||
if ! $zfs list -H $target/$name > /dev/null 2>&1 ; then
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $target/$name does not exist"; fi
|
||||
prefix=""
|
||||
for part in $(echo $target/$(echo $name | $cut -d'/' -f1) | $sed "s/\// /g"); do
|
||||
if [ $($zfs list $prefix$part > /dev/null 2>&1 ; echo $?) -gt 0 ]; then
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $prefix$part does not exist"; fi
|
||||
log "[INFO] Creating $prefix$part"
|
||||
$zfs create -o canmount=noauto $autosnap -p $prefix$part
|
||||
fi
|
||||
prefix="$prefix$part/"
|
||||
done
|
||||
|
||||
# cleanup old snapshots
|
||||
filter=$(echo -e $snapshot_filter | sed "s/|/ /g")
|
||||
IFS=$' '
|
||||
for interval in $filter ; do
|
||||
guid=$($ssh $sshport $source "zfs list -H -o guid,name -S creation -t snapshot $name | grep $interval | cut -f1 | tail -1")
|
||||
if [[ "$(echo -e "$guid" | sed 's/\n//g')" != "" ]]; then
|
||||
for snap in $($zfs list -H -o name,guid -S creation -t snapshot $target/$name | grep $interval | grep --after-context=200 $guid | grep -v $guid | cut -f1); do
|
||||
echo "Deleting $snap"
|
||||
$zfs destroy $debug $snap
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $name - Start initial replication"; fi
|
||||
IFS=$'\n'
|
||||
for snap in $($ssh $sshcipher $sshport $source "zfs list -H -t snapshot -o name -S creation $name | grep -E \"@.*($snapshot_filter)\" | tail -1"); do
|
||||
log "[INFO] Start initial replication: $snap => $target/$(echo $name | $cut -d'/' -f1)"
|
||||
$ssh $sshcipher $sshport $source "zfs send -w -p $debug $snap" | $zfs receive $mp $cm -x $tag -x com.sun:auto-snapshot $debug -dF $target/$(echo $name | $cut -d'/' -f1)
|
||||
if [ $? -gt $rc ]; then rc=1; log "[ERROR] initial replication to $target/$name failed."; fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $name - Start incremental replication"; fi
|
||||
guid=$($zfs list -H -o guid -s creation -t snapshot $target/$name | $tail -1)
|
||||
if [[ $guid != "" ]]; then
|
||||
last=$($ssh $sshcipher $sshport $source "zfs list -H -o name,guid -t snapshot $name | grep $guid | tail -1 | cut -f1")
|
||||
if [[ $last != "" ]]; then
|
||||
IFS=$'\n'
|
||||
if [[ $fstype == "filesystem" ]] && [[ $($zfs get -H -o value canmount $target/$name) != "noauto" ]]; then
|
||||
$zfs set canmount=noauto $target/$name
|
||||
fi
|
||||
for snap in $($ssh $sshcipher $sshport $source "zfs list -H -o name,guid -s creation -t snapshot $name | grep -E \"@.*($snapshot_filter)\" | grep --after-context=200 $guid | grep -v $guid | cut -f1"); do
|
||||
log "[INFO] Replicating delta of $last => $snap to $target/$name"
|
||||
$ssh $sshcipher $sshport $source "zfs send -w $debug -i $last $snap" | zfs receive -x $tag -x com.sun:auto-snapshot -F $debug $target/$name
|
||||
if [ $? -gt $rc ]; then rc=1; log "[ERROR] incremental replication to $target/$name failed."; fi
|
||||
last=$snap
|
||||
done
|
||||
else
|
||||
log "[ERROR] No matching snapshot (guid: $guid) found on source filesystem. This can be outdated snapshots on target or a previously deleted and new created dataset $name on the source filesystem."
|
||||
if [ $rc -eq 0 ]; then rc=1; fi
|
||||
fi
|
||||
else
|
||||
log "[ERROR] No snapshot found on $target/$name to add incremental snapshots to. The target dataset (with all children) needs to be deleted and recreated via replication."
|
||||
if [ $rc -eq 0 ]; then rc=1; fi
|
||||
fi
|
||||
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $name - Start deletion of old snapshots"; fi
|
||||
filter=$(echo -e $snapshot_filter | sed "s/|/\n/g")
|
||||
IFS=$'\n'
|
||||
for interval in $filter ; do
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $name - Checking interval $interval"; fi
|
||||
guid=$($ssh $sshcipher $sshport $source "zfs list -H -o guid,name -S creation -t snapshot $name | grep -E \"@.*$interval\" | cut -f1 | tail -1")
|
||||
if [[ "$(echo -e "$guid" | sed 's/\n//g')" != "" ]]; then
|
||||
snaps_to_delete=$($zfs list -H -o name,guid -S creation -t snapshot $target/$name | $grep -E "@.*$interval" | $grep --after-context=200 $guid | $grep -v $guid | $cut -f1)
|
||||
snap_count=$($zfs list -H -o name,guid -S creation -t snapshot $target/$name | $grep -E "@.*$interval" | $wc -l | $tr -d ' ')
|
||||
|
||||
for snap in $snaps_to_delete; do
|
||||
if [[ $snap_count -gt $min_keep ]]; then
|
||||
log "[INFO] Deleting $snap"
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $name - snap_count=$snap_count, min_keep=$min_keep"; fi
|
||||
$zfs destroy $debug $snap
|
||||
snap_count=$(expr $snap_count - 1)
|
||||
else
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $name - Skipping deletion of $snap. snap_count=$snap_count, min_keep=$min_keep"; fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
else
|
||||
if [[ $debug == "-v" ]]; then log "[DEBUG] $name - No snapshots found with filter $snapshot_filter"; fi
|
||||
fi
|
||||
done
|
||||
exit $rc
|
Reference in New Issue
Block a user