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