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