ffae48c1bece695bcd2462f4bcc33e4929d34783
[matthijs/upstream/backupninja.git] / handlers / dup.in
1 # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
2 # vim: set filetype=sh sw=3 sts=3 expandtab autoindent:
3 #
4 # duplicity script for backupninja
5 # requires duplicity
6 #
7
8 getconf options
9 getconf testconnect yes
10 getconf nicelevel 0
11 getconf tmpdir
12
13 setsection gpg
14 getconf password
15 getconf sign no
16 getconf encryptkey
17 getconf signkey
18
19 setsection source
20 getconf include
21 getconf vsnames all
22 getconf vsinclude
23 getconf exclude
24
25 setsection dest
26 getconf incremental yes
27 getconf keep 60
28 getconf desturl
29 getconf awsaccesskeyid
30 getconf awssecretaccesskey
31 getconf sshoptions
32 getconf bandwidthlimit 0
33 getconf desthost
34 getconf destdir
35 getconf destuser
36 destdir=${destdir%/}
37
38 ### SANITY CHECKS ##############################################################
39
40 [ -n "$desturl" -o -n "$destdir" ]  || fatal "The destination directory (destdir) must be set when desturl is not used."
41 [ -n "$include" -o -n "$vsinclude" ]  || fatal "No source includes specified"
42 [ -n "$password" ] || fatal "The password option must be set."
43 if [ "`echo $desturl | @AWK@ -F ':' '{print $1}'`" == "s3+http" ]; then
44    [ -n "$awsaccesskeyid" -a -n "$awssecretaccesskey" ]  || fatal "AWS access keys must be set for S3 backups."
45 fi
46
47 ### VServers
48 # If vservers are configured, check that the ones listed in $vsnames do exist.
49 local usevserver=no
50 if [ $vservers_are_available = yes ]; then
51    if [ "$vsnames" = all ]; then
52       vsnames="$found_vservers"
53    else
54       if ! vservers_exist "$vsnames" ; then
55             fatal "At least one of the vservers listed in vsnames ($vsnames) does not exist."
56       fi
57    fi
58    if [ -n "$vsinclude" ]; then
59       info "Using vservers '$vsnames'"
60       usevserver=yes
61    fi
62 else
63    [ -z "$vsinclude" ] || warning 'vservers support disabled in backupninja.conf, vsincludes configuration lines will be ignored'
64 fi
65
66 ### See if we can login on $desthost
67 if [ "$testconnect" == "yes" ]; then
68    if [ -n "$desturl" ]; then
69       warning 'testconnect can not be used when desturl is set'
70    else
71       debug "ssh $sshoptions -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'"
72       if [ ! $test ]; then
73          result=`ssh $sshoptions -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'`
74          if [ "$result" != "1" ]; then
75             fatal "Can't connect to $desthost as $destuser."
76          else
77             debug "Connected to $desthost as $destuser successfully"
78          fi
79       fi
80    fi
81 fi
82
83 ### COMMAND-LINE MANGLING ######################################################
84
85 ### initialize $execstr*
86 execstr_command=
87 execstr_options="$options --no-print-statistics"
88 execstr_source=
89 if [ -n "$desturl" ]; then
90    [ -z "$destuser" ] || warning 'the configured destuser is ignored since desturl is set'
91    [ -z "$desthost" ] || warning 'the configured desthost is ignored since desturl is set'
92    [ -z "$destdir" ] || warning 'the configured destdir is ignored since desturl is set'
93    execstr_serverpart="$desturl"
94 else
95    execstr_serverpart="scp://$destuser@$desthost/$destdir"
96 fi
97
98 ### duplicity version
99 duplicity_version="`duplicity --version | @AWK@ '{print $2}'`"
100 duplicity_major="`echo $duplicity_version | @AWK@ -F '.' '{print $1}'`"
101 duplicity_minor="`echo $duplicity_version | @AWK@ -F '.' '{print $2}'`"
102 duplicity_sub="`echo $duplicity_version | @AWK@ -F '.' '{print $3}'`"
103
104 ### ssh/scp/sftp options
105 # 1. duplicity >= 0.4.2 needs --sftp-command
106 #    (NB: sftp does not support the -l option)
107 # 2. duplicity 0.4.3 to 0.4.9 replace --ssh-command with --ssh-options, which is
108 #    passed to scp and sftp commands by duplicity. We don't use it: since this
109 #    version does not use the ssh command anymore, we keep compatibility with
110 #    our previous config files by passing $sshoptions to --scp-command and
111 #    --sftp-command ourselves
112
113 scpoptions="$sshoptions"
114 if [ "$bandwidthlimit" != 0 ]; then
115    [ -z "$desturl" ] || warning 'The bandwidthlimit option is not used when desturl is set.'
116    scpoptions="$scpoptions -l $bandwidthlimit"
117 fi
118
119 # < 0.4.2 : only uses ssh and scp
120 if [ "$duplicity_major" -le 0 -a "$duplicity_minor" -le 4 -a "$duplicity_sub" -lt 2 ]; then
121    execstr_options="${execstr_options} --scp-command 'scp $scpoptions' --ssh-command 'ssh $sshoptions'"
122 # >= 0.4.2 : also uses sftp, --sftp-command option is now supported
123 else
124    sftpoptions="$sshoptions"
125    # == 0.4.2 : uses ssh, scp and sftp
126    if [ "$duplicity_major" -eq 0 -a "$duplicity_minor" -eq 4 -a "$duplicity_sub" -eq 2 ]; then
127       execstr_options="${execstr_options} --scp-command 'scp $scpoptions' --sftp-command 'sftp $sftpoptions' --ssh-command 'ssh $sshoptions'"
128    # >= 0.4.3 : uses only scp and sftp, --ssh-command option is not supported anymore
129    else
130       execstr_options="${execstr_options} --scp-command 'scp $scpoptions' --sftp-command 'sftp $sftpoptions'"
131    fi
132 fi
133
134 ### Symmetric or asymmetric (public/private key pair) encryption
135 if [ -n "$encryptkey" ]; then
136    execstr_options="${execstr_options} --encrypt-key $encryptkey"
137    debug "Data will be encrypted with the GnuPG key $encryptkey."
138 else
139    debug "Data will be encrypted using symmetric encryption."
140 fi
141
142 ### Data signing (or not)
143 if [ "$sign" == yes ]; then
144    # duplicity is not able to sign data when using symmetric encryption
145    [ -n "$encryptkey" ] || fatal "The encryptkey option must be set when signing."
146    # if needed, initialize signkey to a value that is not empty (checked above)
147    [ -n "$signkey" ] || signkey="$encryptkey"
148    execstr_options="${execstr_options} --sign-key $signkey"
149    debug "Data will be signed will the GnuPG key $signkey."
150 else
151    debug "Data won't be signed."
152 fi
153
154 ### Incremental or full backup mode
155 # If incremental==yes, use the default duplicity behaviour: perform an
156 # incremental backup if old signatures can be found, else switch to
157 # full backup.
158 # If incremental==no, force a full backup anyway.
159 if [ "$incremental" == "no" ]; then
160    # before 0.4.4, full was an option and not a command
161    if [ "$duplicity_major" -le 0 -a "$duplicity_minor" -le 4 -a "$duplicity_sub" -lt 4 ]; then
162       execstr_options="${execstr_options} --full"
163    else
164       execstr_command="full"
165    fi
166 fi
167
168 ### Temporary directory
169 precmd=
170 if [ -n "$tmpdir" ]; then
171    if [ ! -d "$tmpdir" ]; then
172       info "Temporary directory ($tmpdir) does not exist, creating it."
173       mkdir -p "$tmpdir"
174       [ $? -eq 0 ] || fatal "Could not create temporary directory ($tmpdir)."
175       chmod 0700 "$tmpdir"
176    fi
177    info "Using $tmpdir as TMPDIR"
178    precmd="${precmd}TMPDIR=$tmpdir "
179 fi
180
181 ### Cleanup old backup sets (or not)
182 if [ "$keep" != "yes" ]; then
183    if [ "`echo $keep | tr -d 0-9`" == "" ]; then
184       keep="${keep}D"
185    fi
186    # before 0.4.4, remove-older-than was an option and not a command
187    if [ "$duplicity_major" -le 0 -a "$duplicity_minor" -le 4 -a "$duplicity_sub" -lt 4 ]; then
188       execstr_options="${execstr_options} --remove-older-than $keep"
189    fi
190 fi
191
192 ### Source
193
194 set -o noglob
195
196 # excludes
197 SAVEIFS=$IFS
198 IFS=$(echo -en "\n\b")
199 for i in $exclude; do
200    str="${i//__star__/*}"
201    execstr_source="${execstr_source} --exclude '$str'"
202 done
203 IFS=$SAVEIFS
204
205 # includes
206 SAVEIFS=$IFS
207 IFS=$(echo -en "\n\b")
208 for i in $include; do
209    [ "$i" != "/" ] || fatal "Sorry, you cannot use 'include = /'"
210    str="${i//__star__/*}"
211    execstr_source="${execstr_source} --include '$str'"
212 done
213 IFS=$SAVEIFS
214
215 # vsincludes
216 if [ $usevserver = yes ]; then
217    for vserver in $vsnames; do
218       SAVEIFS=$IFS
219       IFS=$(echo -en "\n\b")
220       for vi in $vsinclude; do
221          str="${vi//__star__/*}"
222          str="$VROOTDIR/$vserver$str"
223          execstr_source="${execstr_source} --include '$str'"
224       done
225       IFS=$SAVEIFS
226    done
227 fi
228
229 set +o noglob
230
231 ### EXECUTE ####################################################################
232
233 execstr_source=${execstr_source//\\*/\\\\\\*}
234
235 ### If desturl is an S3 URL export the AWS environment variables
236 if [ "`echo $desturl | @AWK@ -F ':' '{print $1}'`" == "s3+http" ]; then
237    export AWS_ACCESS_KEY_ID="$awsaccesskeyid"
238    export AWS_SECRET_ACCESS_KEY="$awssecretaccesskey"
239 fi
240
241 ### Cleanup commands (duplicity >= 0.4.4)
242
243 # cleanup
244 if [ "$duplicity_major" -ge 0 -a "$duplicity_minor" -ge 4 -a "$duplicity_sub" -ge 4 ]; then
245    debug "$precmd duplicity cleanup --force $execstr_options $execstr_serverpart"
246    if [ ! $test ]; then
247       export PASSPHRASE=$password
248       output=`nice -n $nicelevel \
249          su -c \
250          "$precmd duplicity cleanup --force $execstr_options $execstr_serverpart 2>&1"`
251       exit_code=$?
252       if [ $exit_code -eq 0 ]; then
253          debug $output
254          info "Duplicity cleanup finished successfully."
255       else
256          debug $output
257          warning "Duplicity cleanup failed."
258       fi
259    fi
260 fi
261
262 # remove-older-than
263 if [ "$keep" != "yes" ]; then
264    if [ "$duplicity_major" -ge 0 -a "$duplicity_minor" -ge 4 -a "$duplicity_sub" -ge 4 ]; then
265       debug "$precmd duplicity remove-older-than $keep --force $execstr_options $execstr_serverpart"
266       if [ ! $test ]; then
267          export PASSPHRASE=$password
268          output=`nice -n $nicelevel \
269                    su -c \
270                       "$precmd duplicity remove-older-than $keep --force $execstr_options $execstr_serverpart 2>&1"`
271          exit_code=$?
272          if [ $exit_code -eq 0 ]; then
273             debug $output
274             info "Duplicity remove-older-than finished successfully."
275          else
276             debug $output
277             warning "Duplicity remove-older-than failed."
278          fi
279       fi
280    fi
281 fi
282
283 ### Backup command
284 debug "$precmd duplicity $execstr_command $execstr_options $execstr_source --exclude '**' / $execstr_serverpart"
285 if [ ! $test ]; then
286    outputfile=`maketemp backupout`
287    export PASSPHRASE=$password
288    output=`nice -n $nicelevel \
289              su -c \
290                 "$precmd duplicity $execstr_command $execstr_options $execstr_source --exclude '**' / $execstr_serverpart >$outputfile 2>&1"`
291    exit_code=$?
292    debug $output
293    cat $outputfile | (while read output ; do
294                          info $output
295                       done
296    )
297    if [ $exit_code -eq 0 ]; then
298       info "Duplicity finished successfully."
299    else
300       fatal "Duplicity failed."
301    fi
302    rm $outputfile
303 fi
304
305 return 0