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