mysql: No longer prepend vroot to the backupdir.
[matthijs/upstream/backupninja.git] / handlers / mysql.in
1 # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
2 #
3 # mysql handler script for backupninja
4 #
5
6 getconf backupdir /var/backups/mysql
7 getconf databases all
8 getconf ignores
9 getconf nodata
10 getconf dbhost localhost
11 getconf hotcopy no
12 getconf sqldump no
13 getconf sqldumpoptions "--lock-tables --complete-insert --add-drop-table --quick --quote-names"
14 getconf compress yes
15 getconf vsname
16 getconf vsnames
17
18 # authentication:
19 getconf user
20 getconf dbusername
21 getconf dbpassword
22 getconf configfile /etc/mysql/debian.cnf
23
24
25 # Decide if the handler should operate on a vserver or on the host.
26 # In the former case, check that $vsname exists and is running.
27 local usevserver=no
28 local vroot
29
30 if [ -n "$vsname" ]; then
31    if [ -z "$vsnames" ]; then
32       warning "Using deprecated 'vsname' configuration variable"
33       vsnames="$vsname"
34       info "Prepending '%v' to backupdir to emulate legacy behaviour"
35       backupdir="%v/$backupdir"
36    else
37       warning "Ignoring (deprecated) vsname configuration variable, since vsnames is given"
38    fi
39 fi
40
41 if [ $vservers_are_available = yes -a -n "$vsnames" ]; then
42    if [ "$vsnames" = all ]; then
43       vsnames="$found_vservers"
44    else
45       if ! vservers_exist "$vsnames" ; then
46          fatal "At least one of the vservers listed in vsnames ($vsnames) does not exist."
47       fi
48    fi
49    info "Using vservers '$vsnames'"
50    usevserver=yes
51 else
52    [ -z "$vsnames" ] || warning 'vservers support disabled in backupninja.conf, vsnames configuration line will be ignored'
53 fi
54
55 ## Prepare ignore part of the command
56 ## This only works for mysqldump at the moment
57
58 ignore=''
59 for i in $ignores $nodata; do
60    ignore="$ignore --ignore-table=$i"
61 done
62
63 function make_backup() {
64    vsname="$1"
65    if [ -z "$vsname" ]; then
66       info "Running on host"
67       vroot=""
68       vexec=""
69    else
70       if ! vservers_running "$vsname"; then
71          error "vserver $vsname is not running!"
72          return 1
73       fi
74       info "Running on vserver $vsname"
75       vroot="$VROOTDIR/$vsname"
76       vexec="$VSERVER $vsname exec"
77    fi
78
79    interpolated=`interpolate "$backupdir" "$vsname"`
80
81    # create backup dirs
82    [ -d $interpolated ] || mkdir -p $interpolated
83    [ -d $interpolated ] || fatal "Failed to create backup directory '$interpolated'"
84
85    hotdir="$interpolated/hotcopy"
86    dumpdir="$interpolated/sqldump"
87
88    [ "$sqldump" == "no" -o -d $dumpdir ] || mkdir -p $dumpdir
89    [ "$hotcopy" == "no" -o -d $hotdir ] || mkdir -p $hotdir
90
91    #######################################################################
92    ## AUTHENTICATION
93
94    #
95    # one of three authentication methods:
96    # 1. setting the user, so that /home/user/.my.cnf is used.
97    # 2. specifying the user and password in the handler config,
98    #    which generates a temporary .my.cnf in /root/.my.cnf
99    # 3. specify the config file with --defaults-extra-file
100    #    (this option DOESN'T WORK WITH MYSQLHOTCOPY)
101    #
102
103    # create .my.cnf
104    # only if dbusername and dbpassword specified.
105    # we create a tmp file because we don't want to
106    # specify the password on the command line.
107
108    defaultsfile=""
109
110    if [ "$dbusername" != "" -a "$dbpassword" != "" ]
111    then
112       vhome=`$vexec getent passwd "root" | @AWK@ -F: '{print $6}'`
113       home=$vroot$vhome
114
115       [ -d $home ] || fatal "Can't find root's home directory ($home)."
116
117       mycnf="$home/.my.cnf"
118
119       if [ -f $mycnf ]
120       then
121          # rename temporarily
122          tmpcnf="$home/my.cnf.disable"
123          debug "mv $mycnf $tmpcnf"
124          mv $mycnf $tmpcnf
125       fi
126
127       oldmask=`umask`
128       umask 077
129       cat > $mycnf <<EOF
130    # auto generated backupninja mysql conf
131    [mysql]
132    host=$dbhost
133    user=$dbusername
134    password="$dbpassword"
135
136    [mysqldump]
137    host=$dbhost
138    user=$dbusername
139    password="$dbpassword"
140
141    [mysqlhotcopy]
142    host=$dbhost
143    user=$dbusername
144    password="$dbpassword"
145 EOF
146       umask $oldmask
147       defaultsfile="--defaults-extra-file=$vhome/.my.cnf"
148    fi
149
150    # if a user is not set, use $configfile, otherwise use $mycnf
151    if [ "$user" == "" ]; then
152       user=root;
153       defaultsfile="--defaults-extra-file=$configfile"
154    else
155       userset=true;
156       if [ $usevserver = yes ]
157       then
158          vuserhome=`$vexec getent passwd "$user" | @AWK@ -F: '{print $6}'`
159          if [ $? -eq 2 ]
160          then
161             fatal "User $user not found in /etc/passwd"
162          fi
163          userhome="$vroot$vuserhome"
164       fi
165
166       debug "User home set to: $userhome"
167       [ -f $userhome/.my.cnf ] || fatal "Can't find config file in $userhome/.my.cnf"
168       defaultsfile="--defaults-extra-file=$vuserhome/.my.cnf"
169       debug "using $defaultsfile"
170    fi
171
172    #######################################################################
173    ## HOT COPY
174
175    if [ "$hotcopy" == "yes" ]
176    then
177       if starts_with "$hotdir" "$vroot"; then
178          info "Initializing hotcopy method"
179          vhotdir=`strip_prefix "$hotdir" "$vroot"`
180          if [ "$databases" == "all" ]
181          then
182             info "dbhost: $dbhost"
183             execstr="$vexec $MYSQLHOTCOPY -h $dbhost --quiet --allowold --regexp /.\*/./.\*/ $vhotdir"
184
185             debug "su $user -c \"$execstr\""
186             if [ ! $test ]
187             then
188                output=`su $user -c "$execstr" 2>&1`
189                code=$?
190                if [ "$code" == "0" ]
191                then
192                     debug $output
193                     info "Successfully finished hotcopy of all mysql databases"
194                else
195                     warning $output
196                     warning "Failed to hotcopy all mysql databases"
197                fi
198             fi
199          else
200             for db in $databases
201             do
202                execstr="$vexec $MYSQLHOTCOPY -h $dbhost --allowold $db $vhotdir"
203
204                debug 'su $user -c \"$execstr\"'
205                if [ ! $test ]
206                then
207                   output=`su $user -c "$execstr" 2>&1`
208                   code=$?
209                   if [ "$code" == "0" ]
210                   then
211                      debug $output
212                      info "Successfully finished hotcopy of mysql database $db"
213                   else
214                      warning $output
215                      warning "Failed to hotcopy mysql database $db"
216                   fi
217                fi
218             done
219          fi
220       else
221          error "hotcopy method can only be used when the backupdir ($hotdir) is within the vserver ($vroot)"
222       fi
223    fi
224
225    ##########################################################################
226    ## SQL DUMP
227
228    if [ "$sqldump" == "yes" ]
229    then
230        info "Initializing SQL dump method"
231        if [ "$databases" == "all" ]
232        then
233            debug "$vexec su $user -c \"$MYSQL $defaultsfile -N -B -e 'show databases'\" | sed 's/|//g;/\+----/d'"
234            # -N removes the column title and -B should remove the ASCII table borders, but doesn't always so we use sed to make sure.
235            databases=`$vexec su $user -c "$MYSQL $defaultsfile -N -B -e 'show databases'" | sed 's/|//g;/\+----/d'`
236            if [ $? -ne 0 ]
237            then
238                fatal "Authentication problem, maybe user/password is wrong or mysqld is not running?"
239            fi
240        fi
241
242            for db in $databases
243            do
244               DUMP_BASE="$MYSQLDUMP $defaultsfile $sqldumpoptions"
245
246               # Dumping structure and data
247               DUMP="$DUMP_BASE $ignore $db"
248
249               # If requested, dump only the table structure for this database
250               if echo "$nodata" | grep -E '(^|[[:space:]])'"$db\." >/dev/null
251               then
252                  # Get the structure of the tables, without data
253                  DUMP_STRUCT="$DUMP_BASE --no-data $db"
254                  for qualified_table in $nodata
255                  do
256                     table=$( expr match "$qualified_table" "$db\.\([^\w]*\)" )
257                     DUMP_STRUCT="$DUMP_STRUCT $table"
258                  done
259                  DUMP="( $DUMP; $DUMP_STRUCT )"
260               fi
261                    # Test to make sure mysqld is running, if it is not sqldump will not work
262                    $vexec su $user -c "$MYSQLADMIN $defaultsfile ping"
263                    if [ $? -ne 0 ]; then
264                       fatal "Either you have an authentication problem, or mysqld doesn't appear to be running!"
265                    fi
266                    if [ "$compress" == "yes" ]; then
267                       execstr="$vexec $DUMP | $GZIP > $dumpdir/${db}.sql.gz"
268                    else
269                       execstr="$vexec $DUMP -r $dumpdir/${db}.sql"
270                    fi
271
272                    debug "su $user -c \"$execstr\""
273                    if [ ! $test ]
274                    then
275                            output=`su $user -c "$execstr" 2>&1`
276                            code=$?
277                            if [ "$code" == "0" ]
278                            then
279                                    debug $output
280                                    info "Successfully finished dump of mysql database $db"
281                            else
282                                    warning $output
283                                    warning "Failed to dump mysql databases $db"
284                            fi
285                    fi
286            done
287    fi
288
289    # clean up tmp config file
290    if [ "$dbusername" != "" -a "$dbpassword" != "" ]
291    then
292            ## clean up tmp config file
293            debug "rm $mycnf"
294            rm $mycnf
295            if [ -f "$tmpcnf" ]
296            then
297                    debug "mv $tmpcnf $mycnf"
298                    mv $tmpcnf $mycnf
299            fi
300    fi
301 }
302
303 if [ $usevserver = yes ]; then
304    for vserver in $vsnames; do
305       make_backup "$vserver"
306    done
307 else
308    make_backup ""
309 fi
310
311 return 0