commit 969e19e14af5aeb11b16bfef49d0368d5f0befd6 Author: Antoine Martin Date: Mon May 1 14:46:00 2023 -0400 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..4471a86 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# bacoid + +## Purpose +Sends incremental backups using syncoid and zfs config variables + +## How to use + * Set target machine with `zfs set syncoid:target_a=user@backup.com:22 rpool` + * Set target pool with `zfs set syncoid:pool_a=bkppool rpool` + * Set current machine with `zfs set syncoid:machine=hal rpool` + +Due to zfs setting these values recursively, bacoid will then go down the +pool and send whatever matches using the configured settings. In the last +example, this means that syncoid will send `rpool` and all of its children +to `user@backup.com:bkppool/user/hal/rpool` + +If you want to certain children to be skipped, you can do the following: + * `zfs set syncoid:pool_a='' rpool/skip-me` + +## Dependencies + * bash diff --git a/bacoid.sh b/bacoid.sh new file mode 100644 index 0000000..f551ea8 --- /dev/null +++ b/bacoid.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +subvolArray=($(zfs get syncoid:pool_a -H -o name,value | grep -v '@' | awk '{if($2 != "-" && $2 != "") print $1}')) + +COUNT=1 +for subvol in ${subvolArray[@]}; do + targetArray[$COUNT]="$(zfs get syncoid:target_a ${subvol} | grep -v 'NAME' | awk '{print $3}')" + COUNT=$(( ${COUNT} + 1 )) +done +targetArray=($(printf '%s\n' ${targetArray[@]} | awk '!a[$0]++')) + + +for target in ${targetArray[@]}; do + [[ ${target} != *@* ]] && continue + echo "Testing SSH connection to ${target}" + USERHOST="$(sed 's|:.*||' <<< ${target})" + HOST="$(sed 's|.*@||' <<< ${USERHOST})" + USER="$(sed 's|@.*||' <<< ${USERHOST})" + PORT="$(sed 's|.*:||' <<< ${target})" + if [[ ! -f "${HOME}/.ssh/bkp_rsa" ]]; then + echo "Generating bkp_rsa key" + ssh-keygen -N "" -f "${HOME}/.ssh/bkp_rsa" + fi + + ssh -i "${HOME}/.ssh/bkp_rsa" \ + -p ${PORT} \ + -o ControlPath=none \ + -o LogLevel=INFO \ + -o PreferredAuthentications=publickey \ + -o IdentitiesOnly=yes ${USERHOST} exit + [[ $? -ne 0 ]] && ssh-copy-id -p ${PORT} -i "${HOME}/.ssh/bkp_rsa" ${USERHOST} +done + + +for subvol in ${subvolArray[@]}; do + TARGET="$(zfs get syncoid:target_a ${subvol} | grep -v NAME | awk '{print $3}')" + if [[ ${target} != "-" ]]; then + USERHOST="$(sed 's|:.*||' <<< ${TARGET})" + HOST="$(sed 's|.*@||' <<< ${USERHOST})" + USER="$(sed 's|@.*||' <<< ${USERHOST})" + PORT="$(sed 's|.*:||' <<< ${TARGET})" + MACHINE="$(zfs get syncoid:machine ${subvol} | grep -v NAME | awk '{print $3}')" + [[ ${MACHINE} == '-' ]] && { echo "syncoid:machine not set for ${subvol}"; continue; } + POOL="$(zfs get syncoid:pool_a ${subvol} | grep -v NAME | awk '{print $3}')" + [[ ${POOL} == '-' ]] && { echo "syncoid:pool_a not set for ${subvol}"; continue; } + echo "Sending ${subvol} to ${USERHOST}:${POOL}/$USER/$MACHINE/$subvol" + syncoid --sendoptions="w" --recvoptions="u" --sshport=${PORT} --sshkey="${HOME}/.ssh/bkp_rsa" --no-sync-snap --no-privilege-elevation ${subvol} ${USERHOST}:${POOL}/${USER}/${MACHINE}/${subvol} + else + MACHINE="$(zfs get syncoid:machine ${subvol} | grep -v NAME | awk '{print $3}')" + [[ ${MACHINE} == '-' ]] && { echo "syncoid:machine not set for ${subvol}"; continue; } + POOL="$(zfs get syncoid:pool_a ${subvol} | grep -v NAME | awk '{print $3}')" + [[ ${POOL} == '-' ]] && { echo "syncoid:pool_a not set for ${subvol}"; continue; } + echo "Sending ${subvol} to ${POOL}/$MACHINE/$subvol" + syncoid --sendoptions="w" --recvoptions="u" --no-sync-snap ${subvol} ${POOL}/${MACHINE}/${subvol} + fi +done