r261@crapouille: intrigeri | 2005-12-28 20:59:01 +0100
[matthijs/upstream/backupninja.git] / handlers / rdiff.helper
1 # -*- mode: sh; sh-basic-offset: 8; 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
8 # FUNCTIONS
9
10 do_rdiff_host_includes() {
11    set -o noglob
12    # choose the files to backup
13    REPLY=
14    while [ -z "$REPLY" ]
15    do
16      formBegin "$rdiff_title - host system: includes"
17          for ((i=0; i < ${#rdiff_includes[@]} ; i++))
18          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          
49          formItem include ""
50          formItem include ""
51          formItem include ""
52          formDisplay
53       [ $? = 0 ] || return 1
54       rdiff_vsincludes="$REPLY"
55    done
56    
57    set +o noglob
58 }
59
60 do_rdiff_excludes() {
61    set -o noglob
62    formBegin "$rdiff_title: excludes" 
63      for ((i=0; i < ${#rdiff_excludes[@]} ; i++))
64      do
65        formItem exclude ${rdiff_excludes[$i]}
66      done
67      
68      formItem exclude 
69      formItem exclude 
70      formDisplay
71    
72    [ $? = 0 ] || return
73    unset rdiff_excludes
74    rdiff_excludes="$REPLY"
75    set +o noglob
76 }
77
78 do_rdiff_src() {
79    choose_host_or_vservers_or_both "$rdiff_title"
80    [ $? = 0 ] || return 1
81    case $host_or_vservers in
82         'host')
83                do_rdiff_host_includes
84                [ $? = 0 ] || return 1
85                ;;
86         'vservers')
87                do_rdiff_vserver
88                [ $? = 0 ] || return 1
89                ;;
90         'both')
91                do_rdiff_host_includes
92                [ $? = 0 ] || return 1
93                do_rdiff_vserver
94                [ $? = 0 ] || return 1
95                ;;
96         *)
97                return 1
98                ;;
99         esac
100         do_rdiff_excludes
101         [ $? = 0 ] || return 1
102         _src_done="(DONE)"
103         setDefault dest
104 }
105
106 do_rdiff_dest() {
107    
108    local replyconverted
109    local thereply
110    
111    set -o noglob
112    REPLY=
113    while [ -z "$REPLY" -o -z "$rdiff_directory" -o -z "$rdiff_host" -o -z "$rdiff_user" ] 
114    do
115      formBegin "$rdiff_title - destination: last three items are required"
116         formItem "keep" "$rdiff_keep"
117         formItem "dest_directory" "$rdiff_directory"
118         formItem "dest_host" "$rdiff_host"
119         formItem "dest_user" "$rdiff_user"
120         formDisplay
121      [ $? = 0 ] || return
122
123      IFS=$''
124      replyconverted=`echo $REPLY | tr '\n' :`
125      IFS=$':'
126      thereply=($replyconverted)
127      IFS=$' \t\n'
128   
129      rdiff_keep=${thereply[0]}
130      rdiff_directory=${thereply[1]}
131      rdiff_host=${thereply[2]}
132      rdiff_user=${thereply[3]}
133   
134   done
135   set +o noglob
136   
137   _dest_done="(DONE)"
138   setDefault conn
139 }
140         
141 do_rdiff_ssh_con() {
142   IFS=$' \t\n'
143   if [ "$_dest_done" = "" ]; then
144     msgBox "$rdiff_title: error" "You must first configure the destination."
145     return
146   elif [ "$rdiff_user" = "" ]; then
147     msgBox "$rdiff_title: error" "You must first configure the destination user."
148     return
149   elif [ "$rdiff_host" = "" ]; then
150     msgBox "$rdiff_title: error" "You must first configure the destination host."
151     return
152   else
153     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?"
154     [ $? = 0 ] || return
155   fi
156
157   if [ ! -f /root/.ssh/id_dsa.pub -a ! -f /root/.ssh/id_rsa.pub ]; then
158     echo "Creating local root's ssh key"
159     ssh-keygen -t dsa -f /root/.ssh/id_dsa -N ""
160     echo "Done. hit return to continue"
161     read
162   fi
163   
164   ssh -o PreferredAuthentications=publickey $rdiff_host -l $rdiff_user "exit" 2> /dev/null
165   if [ $? -ne 0 ]; then
166     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."
167     ssh-copy-id -i /root/.ssh/id_[rd]sa.pub $rdiff_user@$rdiff_host
168     if [ $? -ne 0 ]; then
169       echo "FAILED: Couldn't copy root's public ssh key to authorized_keys of $rdiff_user@$rdiff_host."
170       ssh $rdiff_user@$rdiff_host 'test -w .ssh || test -w .'
171       result=$?
172       echo "Hit return to continue."
173       read
174       case $result in
175         0 )   msgBox "$rdiff_title: error" "Directories are writable: Probably just a typo the first time." ;;
176         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." ;;
177         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." ;;
178         * )   msgBox "$rdiff_title: error" "Unexpected error." ;;
179       esac 
180       return
181     else
182       echo "Done. hit return to continue"
183       read
184     fi
185   else
186     echo "root@localhost is already in authorized_keys of $rdiff_user@$rdiff_host."
187     echo "Hit return to continue."
188     read
189   fi
190   # test to see if the remote rdiff backup directory exists and is writable
191   echo "Testing to see if remote rdiff backup directory exists and is writable"
192   ssh $rdiff_user@$rdiff_host "test -d ${rdiff_directory}"
193   if [ $? -eq 0 ]
194   then
195         ssh $rdiff_user@$rdiff_host "test -w $rdiff_directory"
196         if [ $? -ne 0 ]
197         then
198                 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."
199                 remote_status=1
200         else
201                 remote_status=0
202         fi
203   else
204         booleanBox "Remote directory does not exist" "The destination backup directory does not exist, do you want me to create it for you?"
205         if [ $? = 0 ]
206         then
207                 ssh $rdiff_user@$rdiff_host "mkdir -p ${rdiff_directory}"
208                 result=$?
209                 echo "Hit return to continue."
210                 read
211                 case $result in
212                         0)   
213                                 msgBox "$rdiff_title: success" "Creation of the remote destination directory was a success!" 
214                                 remote_status=0
215                         ;;
216                         1)   
217                                 msgBox "$rdiff_title: error" "Connected successfully to $rdiff_user@$rdiff_host, but was unable to create the destination directory, check the directory permissions." 
218                                 remote_status=1
219                         ;;
220                         255) 
221                                 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." 
222                                 remote_status=1
223                         ;;
224                         *)   
225                                 msgBox "$rdiff_title: error" "Unexpected error." 
226                                 remote_status=1
227                         ;;
228                         esac 
229                         return
230           fi
231   fi
232   
233   if [ $remote_status -ne 1 ]
234   then
235         do_rdiff_con
236   fi
237 }
238
239 do_rdiff_con() {
240   echo "Testing to make sure destination has rdiff-backup installed and is compatible."
241   remote_result=`/usr/bin/rdiff-backup --test-server $rdiff_user@$rdiff_host::/ 2>&1 >&-`
242   if [ $? -ne 0 ]
243   then
244         echo $remote_result | grep -q "command not found"
245         if [ $? -eq 0 ]
246         then
247                 if [ "$rdiff_user" = "root" ]
248                 then
249                         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?"
250                         if [ $? = 0 ] 
251                         then
252                                 ssh $rdiff_user@$rdiff_host 'apt-get install rdiff-backup'
253                                 result=$?
254                                 echo "Hit return to continue."
255                                 read
256                                 case $result in
257                                         0)   
258                                                 msgBox "$rdiff_title: success" "Installation of rdiff-backup was a success!" 
259                                                 do_rdiff_con
260                                         ;;
261                                         1)   
262                                                 msgBox "$rdiff_title: error" "Connected successfully to $rdiff_user@$rdiff_host, but was unable to install the package for some reason." 
263                                         ;;
264                                         255) 
265                                                 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." 
266                                         ;;
267                                         *)   
268                                                 msgBox "$rdiff_title: error" "Unexpected error." 
269                                         ;;
270                                 esac 
271                                 return
272                         fi
273                 else
274                         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?"
275                         if [ $? = 0 ]
276                         then
277                                 do_rdiff_con
278                         else
279                                 return
280                         fi
281                 fi
282         else
283                 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?"
284                 if [ $? = 0 ]
285                 then
286                         do_rdiff_con
287                 else
288                         return
289                 fi
290         fi
291    else
292         echo "SUCCESS: Everything looks good!"
293         echo "Hit return to continue."
294         read
295    fi
296
297   _con_done="(DONE)"
298   setDefault finish
299 }
300
301 do_rdiff_finish() {
302    get_next_filename $configdirectory/90.rdiff
303    cat > $next_filename <<EOF
304 # options = --force
305 # when = everyday at 02
306
307 [source]
308 type = local
309 keep = $rdiff_keep
310 EOF
311
312    if [ "$host_or_vservers" == host -o "$host_or_vservers" == both ]
313    then
314        set -o noglob
315        
316        for ((i=0; i < ${#rdiff_includes[@]} ; i++))
317        do
318          echo "include = ${rdiff_includes[$i]}" >> $next_filename
319        done
320        
321        set +o noglob
322    fi
323
324    if [ "$host_or_vservers" == vservers -o "$host_or_vservers" == both ]
325    then      
326        cat >> $next_filename <<EOF
327 #
328 # If vservers = yes in /etc/backupninja.conf then the following variables can
329 # be used:
330 # vsnames = all | <vserver1> <vserver2> ... (default = all)
331 # vsinclude = <path>
332 # vsinclude = <path>
333 # ...
334 # Any path specified in vsinclude is added to the include list for each vserver
335 # listed in vsnames (or all if vsnames = all).
336 #
337 # For example, vsinclude = /home will backup the /home partition in every 
338 # vserver listed in vsnames. If you have vsnames = "foo bar baz", this
339 # vsinclude will add to the include list /vservers/foo/home, 
340 # /vservers/bar/home and /vservers/baz/home.
341 # Vserver paths are derived from $VROOTDIR.
342
343 EOF
344
345        set -o noglob
346        echo -e "vsnames = \"$selected_vservers\"\n" >> $next_filename
347        for i in $rdiff_vsincludes; do
348            echo "vsinclude = $i" >> $next_filename
349        done
350        set +o noglob
351    fi
352    
353    # excludes
354
355    for ((i=0; i < ${#rdiff_excludes[@]} ; i++))
356    do
357      echo exclude = ${rdiff_excludes[$i]} >> $next_filename
358    done
359    set +o noglob
360        cat >> $next_filename <<EOF
361
362 ######################################################
363 ## destination section
364 ## (where the files are copied to)
365   
366 [dest]
367 type = remote
368 directory = $rdiff_directory
369 host = $rdiff_host
370 user = $rdiff_user
371 EOF
372
373    chmod 600 $next_filename
374 }
375
376 rdiff_main_menu() {
377
378   while true; do
379     srcitem="choose files to include & exclude $_src_done"
380     destitem="configure backup destination $_dest_done"
381     conitem="set up ssh keys and test remote connection $_con_done"
382     advitem="edit advanced settings $_adv_done"
383     menuBox "$rdiff_title" "choose a step:" \
384         src "$srcitem" \
385         dest "$destitem" \
386         conn "$conitem" \
387         finish "finish and create config file"
388     [ $? = 0 ] || return
389     result="$REPLY"
390
391     case "$result" in
392        "src") do_rdiff_src;;
393        "dest") do_rdiff_dest;;
394        "conn") do_rdiff_ssh_con;;
395        "adv") do_rdiff_adv;;
396        "finish")
397           if [[ "$_con_done$_dest_done$_src_done" != "(DONE)(DONE)(DONE)" ]]; then
398             msgBox "$rdiff_title" "You cannot create the configuration file until the other steps are completed."
399           else
400             do_rdiff_finish
401             return
402           fi
403           ;;
404     esac
405
406   done
407 }
408
409 rdiff_wizard() {
410   require_packages rdiff-backup
411   
412   # Global variables
413   rdiff_title="rdiff-backup action wizard"
414   _src_done=
415   _dest_done=
416   _con_done=
417   _adv_done=
418   rdiff_keep=60D
419   rdiff_directory=/backup/`hostname`
420   rdiff_user=
421   rdiff_host=
422   
423   # Global variables whose '*' shall not be expanded
424   set -o noglob
425   rdiff_includes=(/var/spool/cron/crontabs /var/backups /etc /root /home /usr/local/*bin /var/lib/dpkg/status*)
426   rdiff_excludes=(/home/*/.gnupg)
427   rdiff_vsincludes=
428   set +o noglob
429   
430   rdiff_main_menu
431 }
432