rdiff.helper: fixed vsnames output syntax (currently unused by the rdiff handler...
[matthijs/upstream/backupninja.git] / handlers / rdiff.helper
1 # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
2
3 HELPERS="$HELPERS rdiff:incremental_remote_filesystem_backup"
4
5 declare -a rdiff_includes
6 declare -a rdiff_excludes
7 declare -a rdiff_vsincludes
8 declare -a rdiff_vsexcludes
9
10 # FUNCTIONS
11
12 do_rdiff_host_includes() {
13    set -o noglob
14    # choose the files to backup
15    REPLY=
16    while [ -z "$REPLY" ]; do
17       formBegin "$rdiff_title - host system: includes"
18          for ((i=0; i < ${#rdiff_includes[@]} ; i++)); do
19             formItem include ${rdiff_includes[$i]}
20          done
21          formItem include 
22          formItem include 
23          formItem include 
24       formDisplay
25       [ $? = 0 ] || return
26       unset rdiff_includes
27       rdiff_includes=($REPLY)
28    done
29    set +o noglob
30 }
31
32 do_rdiff_vserver() {
33    # choose the vservers to backup (into $selected_vservers)
34    choose_one_or_more_vservers "$rdiff_title"
35    [ $? = 0 ] || return 1
36
37    set -o noglob
38    # choose the files to backup
39    REPLY=
40
41    while [ -z "$REPLY" ]; do
42       formBegin "$rdiff_title - vsincludes (backup these directories from every vserver)"
43          [ -z "$rdiff_vsincludes" ] && rdiff_vsincludes="$rdiff_default_includes"
44    
45          for i in $rdiff_vsincludes; do
46             formItem include "$i"
47          done
48          formItem include ""
49          formItem include ""
50          formItem include ""
51       formDisplay
52       [ $? = 0 ] || return 1
53       rdiff_vsincludes=($REPLY)
54    done
55    
56    set +o noglob
57 }
58
59 do_rdiff_excludes() {
60    set -o noglob
61    formBegin "$rdiff_title: excludes" 
62      for ((i=0; i < ${#rdiff_excludes[@]} ; i++))
63      do
64        formItem exclude ${rdiff_excludes[$i]}
65      done
66      formItem exclude 
67      formItem exclude 
68    formDisplay
69    [ $? = 0 ] || return
70    unset rdiff_excludes
71    rdiff_excludes=($REPLY)
72    set +o noglob
73 }
74
75 do_rdiff_src() {
76    choose_host_or_vservers_or_both "$rdiff_title"
77    [ $? = 0 ] || return 1
78    case $host_or_vservers in
79       'host')
80          do_rdiff_host_includes
81          [ $? = 0 ] || return 1
82          ;;
83       'vservers')
84          do_rdiff_vserver
85          [ $? = 0 ] || return 1
86          ;;
87       'both')
88          do_rdiff_host_includes
89          [ $? = 0 ] || return 1
90          do_rdiff_vserver
91          [ $? = 0 ] || return 1
92          ;;
93       *)
94          return 1
95          ;;
96    esac
97    do_rdiff_excludes
98    [ $? = 0 ] || return 1
99    _src_done="(DONE)"
100    setDefault dest
101 }
102
103 do_rdiff_dest() {
104    declare -a tmp_array
105    
106    set -o noglob
107    REPLY=
108    while [ -z "$REPLY" -o -z "$rdiff_directory" -o -z "$rdiff_host" -o -z "$rdiff_user" ] 
109    do
110      formBegin "$rdiff_title - destination: last three items are required"
111         formItem "keep" "$rdiff_keep"
112         formItem "dest_directory" "$rdiff_directory"
113         formItem "dest_host" "$rdiff_host"
114         formItem "dest_user" "$rdiff_user"
115         formDisplay
116      [ $? = 0 ] || return
117      tmp_array=($REPLY)
118      rdiff_keep=${tmp_array[0]}
119      rdiff_directory=${tmp_array[1]}
120      rdiff_host=${tmp_array[2]}
121      rdiff_user=${tmp_array[3]}  
122   done
123   set +o noglob
124   
125   _dest_done="(DONE)"
126   setDefault conn
127 }
128
129 do_rdiff_ssh_con() {
130    local remote_status="ok"
131
132    IFS=$' \t\n'
133    if [ "$_dest_done" = "" ]; then
134       msgBox "$rdiff_title: error" "You must first configure the destination."
135       return
136    elif [ "$rdiff_user" = "" ]; then
137       msgBox "$rdiff_title: error" "You must first configure the destination user."
138       return
139    elif [ "$rdiff_host" = "" ]; then
140       msgBox "$rdiff_title: error" "You must first configure the destination host."
141       return
142    else
143       booleanBox "$rdiff_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 $rdiff_user@$rdiff_host. This will allow the local root to make unattended backups to $rdiff_user@$rdiff_host.\n\n\nAre you sure you want to continue?"
144       [ $? = 0 ] || return
145    fi
146
147    if [ ! -f /root/.ssh/id_dsa.pub -a ! -f /root/.ssh/id_rsa.pub ]; then
148       echo "Creating local root's ssh key"
149       ssh-keygen -t dsa -f /root/.ssh/id_dsa -N ""
150       echo "Done. hit return to continue"
151       read
152    fi
153   
154    ssh -o PreferredAuthentications=publickey $rdiff_host -l $rdiff_user "exit" 2> /dev/null
155    if [ $? -ne 0 ]; then
156       echo "Copying root's public ssh key to authorized_keys of $rdiff_user@$rdiff_host. When prompted, specify the password for user $rdiff_user@$rdiff_host."
157       ssh-copy-id -i /root/.ssh/id_[rd]sa.pub $rdiff_user@$rdiff_host
158       if [ $? -ne 0 ]; then
159          echo "FAILED: Couldn't copy root's public ssh key to authorized_keys of $rdiff_user@$rdiff_host."
160          ssh $rdiff_user@$rdiff_host 'test -w .ssh || test -w .'
161          result=$?
162          echo "Hit return to continue."
163          read
164          case $result in
165             0 )   msgBox "$rdiff_title: error" "Directories are writable: Probably just a typo the first time." ;;
166             1 )   msgBox "$rdiff_title: error" "Connected successfully to $rdiff_user@$rdiff_host, but unable to write. Check ownership and modes of ~$rdiff_user on $rdiff_host." ;;
167             255 ) msgBox "$rdiff_title: error" "Failed to connect to $rdiff_user@$rdiff_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host." ;;
168             * )   msgBox "$rdiff_title: error" "Unexpected error." ;;
169          esac 
170          return
171       else
172          echo "Done. hit return to continue"
173          read
174       fi
175    else
176       echo "root@localhost is already in authorized_keys of $rdiff_user@$rdiff_host."
177       echo "Hit return to continue."
178       read
179    fi
180
181    # test to see if the remote rdiff backup directory exists and is writable
182    echo "Testing to see if remote rdiff backup directory exists and is writable"
183    ssh $rdiff_user@$rdiff_host "test -d ${rdiff_directory}"
184    if [ $? = 0 ]; then
185       ssh $rdiff_user@$rdiff_host "test -w $rdiff_directory"
186       if [ $? != 0 ]; then
187          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."
188          remote_status=failed
189       fi
190    else
191       booleanBox "Remote directory does not exist" "The destination backup directory does not exist, do you want me to create it for you?"
192       if [ $? = 0 ]; then
193          ssh $rdiff_user@$rdiff_host "mkdir -p ${rdiff_directory}"
194          result=$?
195          case $result in
196             0) msgBox "$rdiff_title: success" "Creation of the remote destination directory was a success!";;
197             1) msgBox "$rdiff_title: error" "Connected successfully to $rdiff_user@$rdiff_host, but was unable to create the destination directory, check the directory permissions." 
198                remote_status=failed;;
199             255) msgBox "$rdiff_title: error" "Failed to connect to $rdiff_user@$rdiff_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host." 
200                remote_status=failed;;
201             *) msgBox "$rdiff_title: error" "Unexpected error." 
202                remote_status=failed;;
203          esac
204       fi
205    fi
206   
207    if [ "$remote_status" = "ok" ]; then
208       do_rdiff_con
209    fi
210 }
211
212 do_rdiff_con() {
213    echo "Checking for local install of rdiff-backup"
214    require_packages rdiff-backup
215
216    echo "Testing to make sure destination has rdiff-backup installed and is compatible."
217    remote_result=`/usr/bin/rdiff-backup --test-server $rdiff_user@$rdiff_host::/ 2>&1 >&-`
218    if [ $? -ne 0 ]; then
219       echo $remote_result | grep -q "command not found"
220       if [ $? -eq 0 ]; then
221          if [ "$rdiff_user" = "root" ]; then
222             booleanBox "install rdiff-backup?" "It seems like the remote machine does not have rdiff-backup installed, I can attempt to install rdiff-backup on the remote machine.\n\n\nDo you want me to attempt this now?"
223             if [ $? = 0 ]; then
224                ssh $rdiff_user@$rdiff_host 'apt-get install rdiff-backup'
225                result=$?
226                echo "Hit return to continue."
227                read
228                case $result in
229                   0) msgBox "$rdiff_title: success" "Installation of rdiff-backup was a success!" 
230                      do_rdiff_con;;
231                   1) msgBox "$rdiff_title: error" "Connected successfully to $rdiff_user@$rdiff_host, but was unable to install the package for some reason.";;
232                   255) msgBox "$rdiff_title: error" "Failed to connect to $rdiff_user@$rdiff_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host.";;
233                   *) msgBox "$rdiff_title: error" "Unexpected error.";;
234                esac 
235                return
236             fi
237          else
238             booleanBox "install rdiff-backup" "Please install rdiff-backup on the remote machine, this cannot be done automatically, as the remote user in your configuration is not root. \n\nIf you have installed rdiff-backup on the remote machine and you are getting this error, then there is a version incompatibility between that version and the local version.\n\nPlease resolve this problem and then try connecting again.\n\n\n\nTry connecting again?"
239             if [ $? = 0 ]; then
240                do_rdiff_con
241             else
242                return
243             fi
244          fi
245       else
246          msgBox "incompatible versions of rdiff-backup" "It looks like rdiff-backup is installed on the remote machine, but it may be an incompatible version with the one installed locally, or something else is amiss.\n\nPlease resolve this problem and then try connecting again.\n\n\nTry connecting again?"
247          if [ $? = 0 ]; then
248             do_rdiff_con
249          else
250             return
251          fi
252       fi
253    else
254         echo "SUCCESS: Everything looks good!"
255         echo "Hit return to continue."
256         read
257    fi
258
259    _con_done="(DONE)"
260    setDefault finish
261 }
262
263 do_rdiff_finish() {
264    get_next_filename $configdirectory/90.rdiff
265    cat > $next_filename <<EOF
266 # options = --force
267 # when = everyday at 02
268
269 [source]
270 type = local
271 keep = $rdiff_keep
272 EOF
273    ## includes ##
274    if [ "$host_or_vservers" == host -o "$host_or_vservers" == both ]; then
275       set -o noglob
276       for ((i=0; i < ${#rdiff_includes[@]} ; i++)); do
277          echo "include = ${rdiff_includes[$i]}" >> $next_filename
278       done       
279       set +o noglob
280    fi
281
282    if [ "$host_or_vservers" == vservers -o "$host_or_vservers" == both ]; then      
283       cat >> $next_filename <<EOF
284 #
285 # If vservers = yes in /etc/backupninja.conf then the following variables can
286 # be used:
287 # vsnames = all | <vserver1> <vserver2> ... (default = all)
288 # vsinclude = <path>
289 # vsinclude = <path>
290 # ...
291 # Any path specified in vsinclude is added to the include list for each vserver
292 # listed in vsnames (or all if vsnames = all).
293 #
294 # For example, vsinclude = /home will backup the /home directory in every
295 # vserver listed in vsnames. If you have 'vsnames = foo bar baz', this
296 # vsinclude will add to the include list /vservers/foo/home, /vservers/bar/home
297 # and /vservers/baz/home.
298 # Vservers paths are derived from $VROOTDIR.
299
300 EOF
301       set -o noglob
302       echo -e "vsnames = $selected_vservers\n" >> $next_filename
303       for i in $rdiff_vsincludes; do
304          echo "vsinclude = $i" >> $next_filename
305       done
306       set +o noglob
307    fi
308    
309    ## excludes ##
310    set -o noglob
311    for ((i=0; i < ${#rdiff_excludes[@]} ; i++)); do
312      echo exclude = ${rdiff_excludes[$i]} >> $next_filename
313    done
314    set +o noglob
315    cat >> $next_filename <<EOF
316
317 ######################################################
318 ## destination section
319 ## (where the files are copied to)
320   
321 [dest]
322 type = remote
323 directory = $rdiff_directory
324 host = $rdiff_host
325 user = $rdiff_user
326 EOF
327
328    chmod 600 $next_filename
329 }
330
331 rdiff_main_menu() {
332    while true; do
333       srcitem="choose files to include & exclude $_src_done"
334       destitem="configure backup destination $_dest_done"
335       conitem="set up ssh keys and test remote connection $_con_done"
336       advitem="edit advanced settings $_adv_done"
337       menuBox "$rdiff_title" "choose a step:" \
338          src "$srcitem" \
339          dest "$destitem" \
340          conn "$conitem" \
341          finish "finish and create config file"
342       [ $? = 0 ] || return
343       result="$REPLY"
344       case "$result" in
345          "src") do_rdiff_src;;
346          "dest") do_rdiff_dest;;
347          "conn") do_rdiff_ssh_con;;
348          "adv") do_rdiff_adv;;
349          "finish")
350             if [[ "$_con_done$_dest_done$_src_done" != "(DONE)(DONE)(DONE)" ]]; then
351                msgBox "$rdiff_title" "You cannot create the configuration file until the other steps are completed."
352             else
353                do_rdiff_finish
354                return
355             fi
356             ;;
357       esac
358    done
359 }
360
361 rdiff_wizard() {
362  
363    # Global variables
364    rdiff_title="rdiff-backup action wizard"
365    _src_done=
366    _dest_done=
367    _con_done=
368    _adv_done=
369    rdiff_keep=60D
370    rdiff_directory=/backup/`hostname`
371    rdiff_user=
372    rdiff_host=
373
374    # Global variables whose '*' shall not be expanded
375    set -o noglob
376    rdiff_includes=(/var/spool/cron/crontabs /var/backups /etc /root /home /usr/local/*bin /var/lib/dpkg/status*)
377    rdiff_excludes=(/home/*/.gnupg)
378    rdiff_vsincludes=
379    set +o noglob
380   
381    rdiff_main_menu
382 }
383