snap-sync: enable snapper to admin snap-sync backups on target
- create and verify snapper compatible structure on target host - create snapper config (snap-$selected_config) on target host if not already available. use a snap-sync template. - change userdata for snapper listings on target config subvolid, uuid and hostname reflact the values from the source system - introduce a snapper template (/etc/snapper/config-templates/snap-sync) - adapt Makefile to support an initial snap-sync template per default, this templates excludes snap-sync backup configs from timeline and cleanup tasks Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
This commit is contained in:
2
Makefile
2
Makefile
@@ -18,6 +18,7 @@
|
|||||||
PKGNAME = snap-sync
|
PKGNAME = snap-sync
|
||||||
PREFIX ?= /usr
|
PREFIX ?= /usr
|
||||||
SNAPPER_CONFIG ?= /etc/sysconfig/snapper
|
SNAPPER_CONFIG ?= /etc/sysconfig/snapper
|
||||||
|
SNAPPER_TEMPLATES ?= /etc/snapper/config-templates
|
||||||
|
|
||||||
BIN_DIR = $(DESTDIR)$(PREFIX)/bin
|
BIN_DIR = $(DESTDIR)$(PREFIX)/bin
|
||||||
SYSTEMD_DIR = $(DESTDIR)$(PREFIX)/lib/systemd/system
|
SYSTEMD_DIR = $(DESTDIR)$(PREFIX)/lib/systemd/system
|
||||||
@@ -27,3 +28,4 @@ SYSTEMD_DIR = $(DESTDIR)$(PREFIX)/lib/systemd/system
|
|||||||
install:
|
install:
|
||||||
@./find_snapper_config || sed -i 's@^SNAPPER_CONFIG.*@SNAPPER_CONFIG='$(SNAPPER_CONFIG)'@g' bin/$(PKGNAME)
|
@./find_snapper_config || sed -i 's@^SNAPPER_CONFIG.*@SNAPPER_CONFIG='$(SNAPPER_CONFIG)'@g' bin/$(PKGNAME)
|
||||||
@install -Dm755 bin/* -t $(BIN_DIR)/
|
@install -Dm755 bin/* -t $(BIN_DIR)/
|
||||||
|
@install -Dm644 ./$(SNAPPER_TEMPLATES)/* -t $(SNAPPER_TEMPLATES)/
|
||||||
|
|||||||
@@ -28,9 +28,10 @@
|
|||||||
progname="`basename v$0`"
|
progname="`basename v$0`"
|
||||||
version="0.4.4"
|
version="0.4.4"
|
||||||
|
|
||||||
# The following line is modified by the Makefile or
|
# The following lines are modified by the Makefile or
|
||||||
# find_snapper_config script
|
# find_snapper_config script
|
||||||
SNAPPER_CONFIG=/etc/conf.d/snapper
|
SNAPPER_CONFIG=/etc/conf.d/snapper
|
||||||
|
SNAPPER_TEMPLATES=/etc/snapper/config-templates
|
||||||
|
|
||||||
TMPDIR=$(mktemp -d)
|
TMPDIR=$(mktemp -d)
|
||||||
PIPE=$TMPDIR/$progname.out
|
PIPE=$TMPDIR/$progname.out
|
||||||
@@ -88,6 +89,7 @@ get_disk_infos () {
|
|||||||
|
|
||||||
# get mounted BTRFS infos
|
# get mounted BTRFS infos
|
||||||
if [ "$(findmnt --noheadings --nofsroot --target / --output FSTYPE)" = "btrfs" ]; then
|
if [ "$(findmnt --noheadings --nofsroot --target / --output FSTYPE)" = "btrfs" ]; then
|
||||||
|
# root filesystem is never seen as valid target location
|
||||||
exclude_uuid=$(findmnt --noheadings --nofsroot --types btrfs --target / --output UUID)
|
exclude_uuid=$(findmnt --noheadings --nofsroot --types btrfs --target / --output UUID)
|
||||||
disk_uuids=$($ssh findmnt --noheadings --nofsroot --types btrfs --output UUID,TARGET --list | grep -v $exclude_uuid | awk '{print $1}')
|
disk_uuids=$($ssh findmnt --noheadings --nofsroot --types btrfs --output UUID,TARGET --list | grep -v $exclude_uuid | awk '{print $1}')
|
||||||
disk_targets=$($ssh findmnt --noheadings --nofsroot --types btrfs --output UUID,TARGET --list | grep -v $exclude_uuid | awk '{print $2}')
|
disk_targets=$($ssh findmnt --noheadings --nofsroot --types btrfs --output UUID,TARGET --list | grep -v $exclude_uuid | awk '{print $2}')
|
||||||
@@ -394,9 +396,9 @@ run_config () {
|
|||||||
|
|
||||||
if [ "$verbose" ]; then
|
if [ "$verbose" ]; then
|
||||||
if [ -n "$ssh" ];then
|
if [ -n "$ssh" ];then
|
||||||
printf "Backup-Path on remote %s: %s/%s\n" "$remote" "$backup_root" "$backupdir"
|
printf "Backup-Path on remote %s: %s\n" "$remote" "$backup_root"
|
||||||
else
|
else
|
||||||
printf "Backup-Path: %s/%s\n" "$backup_root" "$backupdir"
|
printf "Backup-Path: %s\n" "$backup_root"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -409,16 +411,17 @@ run_config () {
|
|||||||
sync
|
sync
|
||||||
else
|
else
|
||||||
printf "dryrun: Creating new snapshot with snapper config '%s' ...\n" "$selected_config" | tee $PIPE
|
printf "dryrun: Creating new snapshot with snapper config '%s' ...\n" "$selected_config" | tee $PIPE
|
||||||
|
snapper_new_id="<new_snapper_id>"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# if we want to use snapper on the target to supervise the synced snapshots
|
# if we want to use snapper on the target to supervise the synced snapshots
|
||||||
# the backup_location needs to be in a subvol ".snapshots" inside $selected_config (hardcoded in snapper)
|
# the backup_location needs to be in a subvol ".snapshots" inside $selected_config (hardcoded in snapper)
|
||||||
snapper_target_subvol=.snapshots
|
snapper_target_subvol="snap-$selected_config"
|
||||||
snapper_target_snapshot=$backup_root/$selected_config/$snapper_target_subvol/$snapper_new_id
|
snapper_target_snapshots=$backup_root/$snapper_target_subvol/.snapshots/$snapper_new_id
|
||||||
if [ -z "$ssh" ]; then
|
if [ -z "$ssh" ]; then
|
||||||
printf "Will backup %s to %s\n" "$snapper_new_snapshot" "$snapper_target_snapshot/snapshot" | tee $PIPE
|
printf "Will backup %s to %s\n" "$snapper_new_snapshot" "$snapper_target_snapshots/snapshot" | tee $PIPE
|
||||||
else
|
else
|
||||||
printf "Will backup %s to %s\n" "$snapper_new_snapshot" "$remote":"$snapper_target_snapshot/snapshot" | tee $PIPE
|
printf "Will backup %s to %s\n" "$snapper_new_snapshot" "$remote":"$snapper_target_snapshots/snapshot" | tee $PIPE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# save in config specific infos in pseudo Arrays
|
# save in config specific infos in pseudo Arrays
|
||||||
@@ -427,7 +430,7 @@ run_config () {
|
|||||||
eval "snapper_new_info_$i='$snapper_new_info'"
|
eval "snapper_new_info_$i='$snapper_new_info'"
|
||||||
eval "snapper_config_$i='$selected_config'"
|
eval "snapper_config_$i='$selected_config'"
|
||||||
eval "snapper_target_subvol_$i='$snapper_target_subvol'"
|
eval "snapper_target_subvol_$i='$snapper_target_subvol'"
|
||||||
eval "snapper_target_snapshot_$i='$snapper_target_snapshot'"
|
eval "snapper_target_snapshots_$i='$snapper_target_snapshots'"
|
||||||
|
|
||||||
cont_backup="K"
|
cont_backup="K"
|
||||||
eval "snapper_activate_$i=yes"
|
eval "snapper_activate_$i=yes"
|
||||||
@@ -510,7 +513,7 @@ run_backup () {
|
|||||||
snapper_new_snapshot=$(eval echo \$snapper_new_snapshot_$i)
|
snapper_new_snapshot=$(eval echo \$snapper_new_snapshot_$i)
|
||||||
snapper_new_info=$(eval echo \$snapper_new_info_$i)
|
snapper_new_info=$(eval echo \$snapper_new_info_$i)
|
||||||
snapper_target_subvol=$(eval echo \$snapper_target_subvol_$i)
|
snapper_target_subvol=$(eval echo \$snapper_target_subvol_$i)
|
||||||
snapper_target_snapshot=$(eval echo \$snapper_target_snapshot_$i)
|
snapper_target_snapshots=$(eval echo \$snapper_target_snapshots_$i)
|
||||||
|
|
||||||
if [ ! "$dryrun" ]; then
|
if [ ! "$dryrun" ]; then
|
||||||
verify_snapper_structure $backup_root $snapper_config $snapper_target_subvol $snapper_new_id
|
verify_snapper_structure $backup_root $snapper_config $snapper_target_subvol $snapper_new_id
|
||||||
@@ -520,16 +523,16 @@ run_backup () {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$snapper_sync_id" ]; then
|
if [ -z "$snapper_sync_id" ]; then
|
||||||
cmd="btrfs send $snapper_new_snapshot | $ssh btrfs receive $snapper_target_snapshot"
|
cmd="btrfs send $snapper_new_snapshot | $ssh btrfs receive $snapper_target_snapshots"
|
||||||
printf "Sending first snapshot for snapper config '%s' ...\n" "$selected_config" | tee $PIPE
|
printf "Sending first snapshot for snapper config '%s' ...\n" "$selected_config" | tee $PIPE
|
||||||
if [ "$verbose" ]; then
|
if [ "$verbose" ]; then
|
||||||
echo "btrfs send $snapper_new_snapshot | $ssh btrfs receive $snapper_target_snapshot"
|
echo "btrfs send $snapper_new_snapshot | $ssh btrfs receive $snapper_target_snapshots"
|
||||||
cmd="btrfs send -v $snapper_new_snapshot | $ssh btrfs receive -v $snapper_target_snapshot"
|
cmd="btrfs send -v $snapper_new_snapshot | $ssh btrfs receive -v $snapper_target_snapshots"
|
||||||
fi
|
fi
|
||||||
if [ ! "$dryrun" ]; then
|
if [ ! "$dryrun" ]; then
|
||||||
btrfs send "$snapper_new_snapshot" | $ssh btrfs receive "$snapper_target_snapshot" &>/dev/null
|
btrfs send "$snapper_new_snapshot" | $ssh btrfs receive "$snapper_target_snapshots" &>/dev/null
|
||||||
else
|
else
|
||||||
cmd="btrfs send -v $snapper_new_snapshot | $ssh btrfs receive -v $snapper_target_snapshot"
|
cmd="btrfs send -v $snapper_new_snapshot | $ssh btrfs receive -v $snapper_target_snapshots"
|
||||||
printf "dryrun: %s\n" "$cmd"
|
printf "dryrun: %s\n" "$cmd"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -540,7 +543,7 @@ run_backup () {
|
|||||||
# location where it can get its data. This helps speed up the transfer.
|
# location where it can get its data. This helps speed up the transfer.
|
||||||
verbose_flag="-v"
|
verbose_flag="-v"
|
||||||
if [ ! "$dryrun" ]; then
|
if [ ! "$dryrun" ]; then
|
||||||
btrfs send "$verbose_flag" -c "$snapper_sync_snapshot" "$snapper_new_snapshot" | $ssh btrfs receive "$verbose_flag" "$snapper_target_snapshot"
|
btrfs send "$verbose_flag" -c "$snapper_sync_snapshot" "$snapper_new_snapshot" | $ssh btrfs receive "$verbose_flag" "$snapper_target_snapshots"
|
||||||
if [ "$verbose" ]; then
|
if [ "$verbose" ]; then
|
||||||
printf "Deleting sync snapshot for %s ...\n" "$selected_config" | tee $PIPE
|
printf "Deleting sync snapshot for %s ...\n" "$selected_config" | tee $PIPE
|
||||||
fi
|
fi
|
||||||
@@ -548,23 +551,23 @@ run_backup () {
|
|||||||
else
|
else
|
||||||
printf "dryrun: btrfs send %s -c %s %s | %s btrfs receive %s %s\n" \
|
printf "dryrun: btrfs send %s -c %s %s | %s btrfs receive %s %s\n" \
|
||||||
"$verbose_flag" "$snapper_sync_snapshot" "$snapper_new_snapshot" \
|
"$verbose_flag" "$snapper_sync_snapshot" "$snapper_new_snapshot" \
|
||||||
"$ssh" "$verbose_flag" "$snapper_target_snapshot"
|
"$ssh" "$verbose_flag" "$snapper_target_snapshots"
|
||||||
printf "dryrun: snapper -c %s delete %a\n" "$selected_config" "$snapper_sync_id"
|
printf "dryrun: snapper -c %s delete %a\n" "$selected_config" "$snapper_sync_id"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$ssh" ]; then
|
if [ -z "$ssh" ]; then
|
||||||
if [ ! "$dryrun" ]; then
|
if [ ! "$dryrun" ]; then
|
||||||
cp "$snapper_new_info" "$snapper_target_snapshot"
|
cp "$snapper_new_info" "$snapper_target_snapshots"
|
||||||
else
|
else
|
||||||
cmd="cp $snapper_new_info $snapper_target_snapshot"
|
cmd="cp $snapper_new_info $snapper_target_snapshots"
|
||||||
printf "dryrun: %s\n" "$cmd"
|
printf "dryrun: %s\n" "$cmd"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [ ! "$dryrun" ]; then
|
if [ ! "$dryrun" ]; then
|
||||||
rsync -avzq "$snapper_new_info" "$remote":"$snapper_target_snapshot"
|
rsync -avzq "$snapper_new_info" "$remote":"$snapper_target_snapshots"
|
||||||
else
|
else
|
||||||
cmd="rsync -avzq $snapper_new_info $remote:$snapper_target_snapshot"
|
cmd="rsync -avzq $snapper_new_info $remote:$snapper_target_snapshots"
|
||||||
printf "dryrun: %s\n" "$cmd"
|
printf "dryrun: %s\n" "$cmd"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -574,14 +577,22 @@ run_backup () {
|
|||||||
# This is how we find the parent.
|
# This is how we find the parent.
|
||||||
|
|
||||||
userdata="backupdir=$backup_dir, subvolid=$selected_subvol, uuid=$selected_uuid"
|
userdata="backupdir=$backup_dir, subvolid=$selected_subvol, uuid=$selected_uuid"
|
||||||
|
src_host=$(eval cat /etc/hostname)
|
||||||
|
src_uuid=$(eval findmnt --noheadings --output UUID $SUBVOLUME)
|
||||||
|
src_subvolid=$(eval findmnt --noheadings --output OPTIONS $SUBVOLUME | sed -e 's/.*subvolid=\([0-9]*\).*/\1/')
|
||||||
|
target_description="snap-sync backup"
|
||||||
|
target_userdata="subvolid=$src_subvolid, uuid=$src_uuid, host=$src_host"
|
||||||
|
|
||||||
# Tag new snapshot as the latest
|
# Tag new snapshot as the latest
|
||||||
printf "Tagging new snapshot as latest backup for '%s' ...\n" "$selected_config" | tee $PIPE
|
printf "Tagging new snapshot as latest backup for '%s' ...\n" "$selected_config" | tee $PIPE
|
||||||
if [ ! "$dryrun" ]; then
|
if [ ! "$dryrun" ]; then
|
||||||
snapper -v -c "$selected_config" modify -d "$description" -u "$userdata" "$snapper_new_id"
|
snapper -v -c "$selected_config" modify -d "$description" -u "$userdata" "$snapper_new_id"
|
||||||
|
$ssh snapper -v -c "$snapper_target_subvol" modify -d \"$target_description\" -u \"$target_userdata\" "$snapper_new_id"
|
||||||
else
|
else
|
||||||
cmd="snapper -v -c $selected_config modify -d $description -u $userdata $snapper_new_id"
|
cmd="snapper -v -c $selected_config modify -d $description -u $userdata $snapper_new_id"
|
||||||
printf "dryrun: %s\n" "$cmd"
|
printf "dryrun: %s\n" "$cmd"
|
||||||
|
cmd="$ssh snapper -v -c $snapper_target_subvol modify -d $target_description -u $target_userdata $snapper_new_id"
|
||||||
|
printf "dryrun: %s\n" "$cmd"
|
||||||
fi
|
fi
|
||||||
printf "Backup complete for snapper configuration '%s'.\n" "$selected_config" > $PIPE
|
printf "Backup complete for snapper configuration '%s'.\n" "$selected_config" > $PIPE
|
||||||
done
|
done
|
||||||
@@ -731,38 +742,41 @@ verify_snapper_structure () {
|
|||||||
local snapper_subvol=$3
|
local snapper_subvol=$3
|
||||||
local snapper_id=$4
|
local snapper_id=$4
|
||||||
|
|
||||||
|
local snapper_snapshots=".snapshots"
|
||||||
|
|
||||||
if [ "$verbose" ]; then
|
if [ "$verbose" ]; then
|
||||||
echo "Verify snapper filesystem structure on target ..."
|
echo "Verify snapper filesystem structure on target ..."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# if not accessible, create backup-path
|
# if not accessible, create backup-path
|
||||||
if $ssh [ ! -d $backup_root/$snapper_config ]; then
|
if $ssh [ ! -d $backup_root ]; then
|
||||||
if [ "$verbose" ]; then
|
if [ "$verbose" ]; then
|
||||||
echo "Create backup-path $backup_root/$snapper_config"
|
echo "Create backup-path $backup_root ..."
|
||||||
fi
|
fi
|
||||||
$ssh mkdir --mode=0700 --parents $backup_root/$snapper_config
|
$ssh mkdir --mode=0700 --parents $backup_root
|
||||||
|
fi
|
||||||
|
if $ssh [ ! -d $backup_root/$snapper_subvol ]; then
|
||||||
|
if $ssh [ ! -f $SNAPPER_TEMPLATES/snap-sync ]; then
|
||||||
|
die "A snapper template %s to configure the snapper subvolume %s is missing in %s. Did you miss to install the package default template?\n" "snap-sync" "$snapper_config" "$SNAPPER_TEMPLATES"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# if not accessible, create subvolume to hold snappers snapshot structure
|
|
||||||
create_subvol="btrfs subvolume create $backup_root/$snapper_config/$snapper_subvol"
|
|
||||||
|
|
||||||
# check if given snapper_subvol is a subvol
|
|
||||||
if $ssh [ ! -d $backup_root/$snapper_config/$snapper_subvol ]; then
|
|
||||||
if [ "$verbose" ]; then
|
if [ "$verbose" ]; then
|
||||||
echo "Create new subvolume $backup_root/$snapper_config/$snapper_subvol"
|
printf "Create new snapper capable subvolume in '%s' ...\n" "$backup_root/$snapper_subvol"
|
||||||
fi
|
fi
|
||||||
|
create_subvol="btrfs subvolume create $backup_root/$snapper_subvol"
|
||||||
$ssh $create_subvol || die "BTRFS subvolume %s to hold snapshots for config %s could not be created in directory on %s.\n" "$snapper_subvol" "$snapper_config" "$backup_root"
|
$ssh $create_subvol || die "BTRFS subvolume %s to hold snapshots for config %s could not be created in directory on %s.\n" "$snapper_subvol" "$snapper_config" "$backup_root"
|
||||||
|
$ssh snapper --config $snapper_subvol create-config --template snap-sync $backup_root/$snapper_subvol
|
||||||
|
$ssh chmod --mode=0700 $backup_root/$snapper_config
|
||||||
else
|
else
|
||||||
if $ssh [ `stat --format=%i $backup_root/$snapper_config/$snapper_subvol` -ne 256 ]; then
|
if $ssh [ `stat --format=%i $backup_root/$snapper_subvol` -ne 256 ]; then
|
||||||
die "%s needs to be a BTRFS subvolume. But given %s is just a directory.\n" "$snapper_subvol" "$backup_root/$snapper_config/$snapper_subvol"
|
die "%s needs to be a BTRFS subvolume. But given %s is just a directory.\n" "$snapper_subvol" "$backup_root/$snapper_subvol"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if $ssh [ ! -d $backup_root/$snapper_config/$snapper_subvol/$snapper_id ]; then
|
if $ssh [ ! -d $backup_root/$snapper_subvol/$snapper_snapshots/$snapper_id ]; then
|
||||||
if [ "$verbose" ]; then
|
if [ "$verbose" ]; then
|
||||||
echo "Create backup-path $backup_root/$snapper_config/$snapper_subvol/$snapper_id"
|
echo "Create backup-path $backup_root/$snapper_subvol/$snapper_snapshots/$snapper_id"
|
||||||
fi
|
fi
|
||||||
$ssh mkdir --mode=0700 $backup_root/$snapper_config/$snapper_subvol/$snapper_id
|
$ssh mkdir --mode=0700 $backup_root/$snapper_subvol/$snapper_snapshots/$snapper_id
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
58
etc/snapper/config-templates/snap-sync
Normal file
58
etc/snapper/config-templates/snap-sync
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
###
|
||||||
|
# snapper template for snap-sync handling
|
||||||
|
###
|
||||||
|
|
||||||
|
# subvolume to snapshot
|
||||||
|
SUBVOLUME="/var/lib/snap-sync"
|
||||||
|
|
||||||
|
# filesystem type
|
||||||
|
FSTYPE="btrfs"
|
||||||
|
|
||||||
|
|
||||||
|
# users and groups allowed to work with config
|
||||||
|
ALLOW_USERS=""
|
||||||
|
ALLOW_GROUPS="adm"
|
||||||
|
|
||||||
|
# sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
|
||||||
|
# directory
|
||||||
|
SYNC_ACL="yes"
|
||||||
|
|
||||||
|
|
||||||
|
# start comparing pre- and post-snapshot in background after creating
|
||||||
|
# post-snapshot
|
||||||
|
BACKGROUND_COMPARISON="yes"
|
||||||
|
|
||||||
|
|
||||||
|
# run daily number cleanup
|
||||||
|
NUMBER_CLEANUP="no"
|
||||||
|
|
||||||
|
# limit for number cleanup
|
||||||
|
NUMBER_MIN_AGE="1800"
|
||||||
|
NUMBER_LIMIT="50"
|
||||||
|
NUMBER_LIMIT_IMPORTANT="10"
|
||||||
|
|
||||||
|
# "no": we will use systemd.timer
|
||||||
|
TIMELINE_CREATE="no"
|
||||||
|
|
||||||
|
# create cron based cleanup entries
|
||||||
|
# "no": we will use systemd.timer
|
||||||
|
TIMELINE_CLEANUP="no"
|
||||||
|
|
||||||
|
# snap-sync: timeline settings
|
||||||
|
TIMELINE_MIN_AGE="1800"
|
||||||
|
TIMELINE_LIMIT_HOURLY="1"
|
||||||
|
TIMELINE_LIMIT_DAILY="2"
|
||||||
|
TIMELINE_LIMIT_MONTHLY="1"
|
||||||
|
TIMELINE_LIMIT_YEARLY="1"
|
||||||
|
|
||||||
|
|
||||||
|
# cleanup empty pre-post-pairs
|
||||||
|
EMPTY_PRE_POST_CLEANUP="yes"
|
||||||
|
|
||||||
|
# limits for empty pre-post-pair cleanup
|
||||||
|
EMPTY_PRE_POST_MIN_AGE="1800"
|
||||||
|
|
||||||
|
# uncomment to exclude this subvol when calling
|
||||||
|
# snap-sync as timer unit
|
||||||
|
# SNAP_SUNC_EXCLUDE="yes"
|
||||||
|
|
||||||
Reference in New Issue
Block a user