From c4e9125a719c84bc457eae9897ebb51d22378cbc Mon Sep 17 00:00:00 2001 From: Ben <ben@wainei.net> Date: Fri, 12 Jan 2018 17:52:45 -0500 Subject: [PATCH] [borg] added a borg helper --- handlers/borg.helper.in | 358 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 handlers/borg.helper.in diff --git a/handlers/borg.helper.in b/handlers/borg.helper.in new file mode 100644 index 0000000..f48cfe7 --- /dev/null +++ b/handlers/borg.helper.in @@ -0,0 +1,358 @@ +# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*- +# vim: set filetype=sh sw=3 sts=3 expandtab autoindent: + +# +# TODO: encryption support +# + +HELPERS="$HELPERS borg:deduplicated_archive_based_backup" + +declare -a borg_includes +declare -a borg_excludes + +# FUNCTIONS + +do_borg_host_includes() { + set -o noglob + # choose the files to backup + REPLY= + while [ -z "$REPLY" ]; do + formBegin "$borg_title - host system: includes" + for ((i=0; i < ${#borg_includes[@]} ; i++)); do + formItem include ${borg_includes[$i]} + done + formItem include + formItem include + formItem include + formItem include + formItem include + formItem include + formItem include + formItem include + formDisplay + [ $? = 0 ] || return + unset borg_includes + borg_includes=($REPLY) + done + set +o noglob +} + +do_borg_excludes() { + set -o noglob + formBegin "$borg_title: host system: excludes" + for ((i=0; i < ${#borg_excludes[@]} ; i++)) + do + formItem exclude ${borg_excludes[$i]} + done + formItem exclude + formItem exclude + formItem exclude + formItem exclude + formItem exclude + formItem exclude + formItem exclude + formItem exclude + formDisplay + [ $? = 0 ] || return + unset borg_excludes + borg_excludes=($REPLY) + set +o noglob +} + +do_borg_src() { + do_borg_host_includes + [ $? = 0 ] || return 1 + + do_borg_excludes + [ $? = 0 ] || return 1 + + _src_done="(DONE)" + setDefault dest +} + +do_borg_dest() { + declare -a tmp_array + + set -o noglob + REPLY= + while [ -z "$REPLY" -o -z "$borg_directory" -o -z "$borg_host" -o -z "$borg_user" -o -z "$borg_archive" -o -z "$borg_compression" ] + do + formBegin "$borg_title - destination" + formItem "directory" "$borg_directory" + formItem "host" "$borg_host" + formItem "user" "$borg_user" + formItem "archive_name" "$borg_archive" + formItem "compression" "$borg_compression" + formDisplay + [ $? = 0 ] || return + tmp_array=($REPLY) + borg_directory=${tmp_array[0]} + borg_host=${tmp_array[1]} + borg_user=${tmp_array[2]} + borg_archive=${tmp_array[3]} + borg_compression=${tmp_array[4]} + done + set +o noglob + + _dest_done="(DONE)" + setDefault conn +} + + +do_borg_local_dir() { + local dir_status="ok" + + IFS=$' \t\n' + if [ "$_dest_done" = "" ]; then + msgBox "$borg_title: error" "You must first configure the destination." + return 1 + fi + + echo "Testing to see if the borg backup directory exists and is writable" + test -d $borg_directory + if [ $? = 0 ]; then + test -w $borg_directory + if [ $? != 0 ]; then + msgBox "destination directory is not writable!" "The destination directory is not writable by the user you specified. Please fix the permissions on the directory and then try again." + dir_status=failed + fi + else + booleanBox "Destination does not exist" "The destination backup directory does not exist, do you want me to create it for you?" + if [ $? = 0 ]; then + mkdir -p $borg_directory + result=$? + case $result in + 0) msgBox "$borg_title: success" "Creation of the destination directory was a success!";; + 1) msgBox "$borg_title: error" "Creation of the destination directory failed, check the directory permissions." + dir_status=failed;; + esac + fi + fi + + [ "$dir_status" = "ok" ] || return 1 +} + +do_borg_ssh_con() { + local remote_status="ok" + + IFS=$' \t\n' + if [ "$_dest_done" = "" ]; then + msgBox "$borg_title: error" "You must first configure the destination." + return 1 + elif [ "$borg_user" = "" ]; then + msgBox "$borg_title: error" "You must first configure the destination user." + return 1 + elif [ "$borg_host" = "" ]; then + msgBox "$borg_title: error" "You must first configure the destination host." + return 1 + else + booleanBox "$borg_title" "This step will create a ssh key for the local root user with no passphrase (if one does not already exist), and attempt to copy root's public ssh key to authorized_keys file of $borg_user@$borg_host. This will allow the local root to make unattended backups to $borg_user@$borg_host.\n\n\nAre you sure you want to continue?" + [ $? = 0 ] || return 1 + fi + + if [ ! -f /root/.ssh/id_dsa.pub -a ! -f /root/.ssh/id_rsa.pub ]; then + echo "Creating local root's ssh key" + ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa -N "" + echo "Done. hit return to continue" + read + fi + + ssh -o PreferredAuthentications=publickey $borg_host -l $borg_user "exit" 2> /dev/null + if [ $? -ne 0 ]; then + echo "Copying root's public ssh key to authorized_keys of $borg_user@$borg_host. When prompted, specify the password for user $borg_user@$borg_host." + ssh-copy-id -i /root/.ssh/id_[rd]sa.pub $borg_user@$borg_host + if [ $? -ne 0 ]; then + echo "FAILED: Couldn't copy root's public ssh key to authorized_keys of $borg_user@$borg_host." + ssh $borg_user@$borg_host 'test -w .ssh || test -w .' + result=$? + echo "Hit return to continue." + read + case $result in + 0 ) msgBox "$borg_title: error" "Directories are writable: Probably just a typo the first time." ;; + 1 ) msgBox "$borg_title: error" "Connected successfully to $borg_user@$borg_host, but unable to write. Check ownership and modes of ~$borg_user on $borg_host." ;; + 255 ) msgBox "$borg_title: error" "Failed to connect to $borg_user@$borg_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host." ;; + * ) msgBox "$borg_title: error" "Unexpected error." ;; + esac + return + else + echo "Done. hit return to continue" + read + fi + else + echo "root@localhost is already in authorized_keys of $borg_user@$borg_host." + echo "Hit return to continue." + read + fi + + # test to see if the remote borg backup directory exists and is writable + echo "Testing to see if remote borg backup directory exists and is writable" + ssh $borg_user@$borg_host "test -d ${borg_directory}" + if [ $? = 0 ]; then + ssh $borg_user@$borg_host "test -w $borg_directory" + if [ $? != 0 ]; then + msgBox "destination directory is not writable!" "The remote destination directory is not writable by the user you specified. Please fix the permissions on the directory and then try again." + remote_status=failed + fi + else + booleanBox "Remote directory does not exist" "The destination backup directory does not exist, do you want me to create it for you?" + if [ $? = 0 ]; then + ssh $borg_user@$borg_host "mkdir -p ${borg_directory}" + result=$? + case $result in + 0) msgBox "$borg_title: success" "Creation of the remote destination directory was a success!";; + 1) msgBox "$borg_title: error" "Connected successfully to $borg_user@$borg_host, but was unable to create the destination directory, check the directory permissions." + remote_status=failed;; + 255) msgBox "$borg_title: error" "Failed to connect to $borg_user@$borg_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host." + remote_status=failed;; + *) msgBox "$borg_title: error" "Unexpected error." + remote_status=failed;; + esac + fi + fi + + [ "$remote_status" = "ok" ] || return 1 +} + +do_borg_con() { + echo "Checking for local install of borg" + which borg + if [ $? != 0 ]; then + msgBox "$borg_title: error" "borg executable not found, please install borg ($borg_docs/installation.html)." + return + fi + + if [ "$borg_host" != "localhost"]; then + do_borg_ssh_con + else + do_borg_local_dir + fi + + [ $? = 0 ] || return + + echo "SUCCESS: Everything looks good!" + echo "Hit return to continue." + read + + _con_done="(DONE)" + setDefault finish +} + +do_borg_prune() { + declare -a tmp_array + + set -o noglob + REPLY= + formBegin "$borg_title - pruning (how many backups to keep)" + formItem "daily" "$borg_keepdaily" + formItem "weekly" "$borg_keepweekly" + formItem "monthly" "$borg_keepmonthly" + formDisplay + + [ $? = 0 ] || return + tmp_array=($REPLY) + borg_keepdaily=${tmp_array[0]} + borg_keepweekly=${tmp_array[1]} + borg_keepmonthly=${tmp_array[2]} + + set +o noglob + + _prune_done="(DONE)" +} + +do_borg_finish() { + get_next_filename $configdirectory/90.borg + cat > $next_filename <<EOF +## for more options see +## - example.borg +## - $borg_docs + +[source] +EOF + ## includes ## + set -o noglob + for ((i=0; i < ${#borg_includes[@]} ; i++)); do + echo "include = ${borg_includes[$i]}" >> $next_filename + done + set +o noglob + + ## excludes ## + set -o noglob + for ((i=0; i < ${#borg_excludes[@]} ; i++)); do + echo exclude = ${borg_excludes[$i]} >> $next_filename + done + set +o noglob + cat >> $next_filename <<EOF + +## for more info see : borg prune -h +keepdaily = $borg_keepdaily +keepweekly = $borg_keepweekly +keepmonthly = $borg_keepmonthly + +[dest] +directory = $borg_directory +host = $borg_host +user = $borg_user +compression = $borg_compression +archive = $borg_archive +EOF + + chmod 600 $next_filename +} + +borg_main_menu() { + while true; do + srcitem="choose files to include & exclude $_src_done" + destitem="configure backup destination $_dest_done" + conitem="test connection and destination dir $_con_done" + pruneitem="configure pruning (optional) $_prune_done" + menuBox "$borg_title" "choose a step:" \ + src "$srcitem" \ + dest "$destitem" \ + conn "$conitem" \ + prune "$pruneitem" \ + finish "finish and create config file" + [ $? = 0 ] || return + result="$REPLY" + case "$result" in + "src") do_borg_src;; + "dest") do_borg_dest;; + "conn") do_borg_con;; + "prune") do_borg_prune;; + "finish") + if [[ "$_con_done$_dest_done$_src_done" != "(DONE)(DONE)(DONE)" ]]; then + msgBox "$borg_title" "You cannot create the configuration file until mandatory steps are completed." + else + do_borg_finish + return + fi + ;; + esac + done +} + +borg_wizard() { + # Global variables + borg_title="borg action wizard" + borg_docs="http://borgbackup.readthedocs.io/en/stable" + + _src_done= + _dest_done= + _con_done= + + borg_directory=/backup/`hostname` + borg_user=root + borg_host=localhost + borg_compression=lz4 + borg_archive='{now:%Y-%m-%d}' + borg_keepdaily=7 + borg_keepweekly=4 + borg_keepmonthly=-1 + + # Global variables whose '*' shall not be expanded + set -o noglob + borg_includes=(/var/spool/cron/crontabs /var/backups /etc /root /home /usr/local/*bin) + borg_excludes=(/home/*/.gnupg /home/*/.local/share/Trash /home/*/.Trash /home/*/.thumbnails) + set +o noglob + + borg_main_menu +} -- GitLab