source: src-sh/lpreserver/backend/functions.sh @ cb8f638

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3
Last change on this file since cb8f638 was cb8f638, checked in by Kris Moore <kris@…>, 13 months ago

Add "lpreserver status" command, which will show last snapshot / replication for all datasets

  • Property mode set to 100755
File size: 10.3 KB
Line 
1#!/bin/sh
2# Functions / variables for lpreserver
3######################################################################
4# DO NOT EDIT
5
6# Source external functions
7. /usr/local/share/pcbsd/scripts/functions.sh
8
9# Installation directory
10PROGDIR="/usr/local/share/lpreserver"
11
12# Location of settings
13DBDIR="/var/db/lpreserver"
14if [ ! -d "$DBDIR" ] ; then mkdir -p ${DBDIR} ; fi
15
16CMDLOG="${DBDIR}/lp-lastcmdout"
17CMDLOG2="${DBDIR}/lp-lastcmdout2"
18REPCONF="${DBDIR}/replication"
19LOGDIR="/var/log/lpreserver"
20REPLOGSEND="${LOGDIR}/lastrep-send-log"
21REPLOGRECV="${LOGDIR}/lastrep-recv-log"
22MSGQUEUE="${DBDIR}/.lpreserver.msg.$$"
23export DBDIR LOGDIR PROGDIR CMDLOG REPCONF REPLOGSEND REPLOGRECV MSGQUEUE
24
25# Create the logdir
26if [ ! -d "$LOGDIR" ] ; then mkdir -p ${LOGDIR} ; fi
27
28#Set our Options
29setOpts() {
30  if [ -e "${DBDIR}/recursive-off" ] ; then
31    export RECURMODE="OFF"
32  else
33    export RECURMODE="ON"
34  fi
35
36  if [ -e "${DBDIR}/emaillevel" ] ; then
37    export EMAILMODE="`cat ${DBDIR}/emaillevel`"
38  fi
39
40  if [ -e "${DBDIR}/duwarn" ] ; then
41    export DUWARN="`cat ${DBDIR}/duwarn`"
42  else
43    export DUWARN=85
44  fi
45
46  case $EMAILMODE in
47      ALL|WARN|ERROR) ;;
48        *) export EMAILMODE="WARN";;
49  esac
50
51  if [ -e "${DBDIR}/emails" ] ; then
52    export EMAILADDY="`cat ${DBDIR}/emails`"
53  fi
54
55}
56setOpts
57
58
59# Check if a directory is mounted
60isDirMounted() {
61  mount | grep -q "on $1 ("
62  return $?
63}
64
65mkZFSSnap() {
66  if [ "$RECURMODE" = "ON" ] ; then
67     flags="-r"
68  else
69     flags="-r"
70  fi
71  zdate=`date +%Y-%m-%d-%H-%M-%S`
72  zfs snapshot $flags ${1}@$2${zdate} >${CMDLOG} 2>${CMDLOG}
73  return $?
74}
75
76listZFSSnap() {
77  zfs list -t snapshot | grep -e "^NAME" -e "^${1}@"
78}
79
80rmZFSSnap() {
81  `zfs list -t snapshot | grep -q "^$1@$2 "` || exit_err "No such snapshot!"
82  if [ "$RECURMODE" = "ON" ] ; then
83     flags="-r"
84  else
85     flags="-r"
86  fi
87  zfs destroy -r ${1}@${2} >${CMDLOG} 2>${CMDLOG}
88  return $?
89}
90
91revertZFSSnap() {
92  # Make sure this is a valid snapshot
93  `zfs list -t snapshot | grep -q "^$1@$2 "` || exit_err "No such snapshot!"
94
95  # Rollback the snapshot
96  zfs rollback -R -f ${1}@$2
97}
98
99enable_cron()
100{
101   cronscript="${PROGDIR}/backend/runsnap.sh"
102
103   # Make sure we remove any old entries for this dataset
104   cat /etc/crontab | grep -v " $cronscript $1" > /etc/crontab.new
105   mv /etc/crontab.new /etc/crontab
106   if [ "$2" = "OFF" ] ; then
107      return
108   fi
109
110   case $2 in
111       daily) cLine="0       $4      *       *       *" ;;
112      hourly) cLine="0       *       *       *       *" ;;
113       30min) cLine="0,30    *       *       *       *" ;;
114       10min) cLine="*/10    *       *       *       *" ;;
115        5min) cLine="*/5     *       *       *       *" ;;
116          *) exit_err "Invalid time specified" ;;
117   esac
118
119   echo -e "$cLine\troot    ${cronscript} $1 $3" >> /etc/crontab
120}
121
122enable_watcher()
123{
124   cronscript="${PROGDIR}/backend/zfsmon.sh"
125
126   # Check if the zfs monitor is already enabled
127   grep -q " $cronscript" /etc/crontab
128   if [ $? -eq 0 ] ; then return; fi
129
130   cLine="*/30    *       *       *       *"
131
132   echo -e "$cLine\troot    ${cronscript}" >> /etc/crontab
133}
134
135snaplist() {
136  zfs list -t snapshot | grep "^${1}@" | cut -d '@' -f 2 | awk '{print $1}'
137}
138
139echo_log() {
140   echo "`date`: $@" >> ${LOGDIR}/lpreserver.log
141}
142
143# E-Mail a message to the set addresses
144# 1 = subject tag
145# 2 = Message
146email_msg() {
147   if [ -z "$EMAILADDY" ] ; then return ; fi
148   echo -e "$2"  | mail -s "$1 - `hostname`" $EMAILADDY
149}
150
151queue_msg() {
152  echo -e "$1" >> ${MSGQUEUE}
153  if [ -n "$2" ] ; then
154    cat $2 >> ${MSGQUEUE}
155  fi
156}
157
158echo_queue_msg() {
159  if [ ! -e "$MSGQUEUE" ] ; then return ; fi
160  cat ${MSGQUEUE}
161  rm ${MSGQUEUE}
162}
163
164add_rep_task() {
165  # add freenas.8343 backupuser 22 tank1/usr/home/kris tankbackup/backups sync
166  HOST=$1
167  USER=$2
168  PORT=$3
169  LDATA=$4
170  RDATA=$5
171  TIME=$6
172
173  case $TIME in
174     [0-9][0-9]|sync)  ;;
175     *) exit_err "Invalid time: $TIME"
176  esac
177 
178  echo "Adding replication task for local dataset $LDATA"
179  echo "----------------------------------------------------------"
180  echo "   Remote Host: $HOST" 
181  echo "   Remote User: $USER" 
182  echo "   Remote Port: $PORT" 
183  echo "Remote Dataset: $RDATA" 
184  echo "          Time: $TIME" 
185  echo "----------------------------------------------------------"
186  echo "Don't forget to ensure that this user / dataset exists on the remote host"
187  echo "with the correct permissions!"
188
189  rem_rep_task "$LDATA"
190  echo "$LDATA:$TIME:$HOST:$USER:$PORT:$RDATA" >> ${REPCONF}
191
192  if [ "$TIME" != "sync" ] ; then
193    cronscript="${PROGDIR}/backend/runrep.sh"
194    cLine="0    $TIME       *       *       *"
195    echo -e "$cLine\troot    ${cronscript} ${LDATA}" >> /etc/crontab
196  fi
197}
198
199rem_rep_task() {
200  if [ ! -e "$REPCONF" ] ; then return ; fi
201  cat ${REPCONF} | grep -v "^${1}:" > ${REPCONF}.tmp
202  mv ${REPCONF}.tmp ${REPCONF}
203
204  # Make sure we remove any old replication entries for this dataset
205  cronscript="${PROGDIR}/backend/runrep.sh"
206  cat /etc/crontab | grep -v " $cronscript $1" > /etc/crontab.new
207  mv /etc/crontab.new /etc/crontab
208}
209
210list_rep_task() {
211  if [ ! -e "$REPCONF" ] ; then return ; fi
212
213  echo "Scheduled replications:"
214  echo "---------------------------------"
215
216  while read line
217  do
218     LDATA=`echo $line | cut -d ':' -f 1`
219     TIME=`echo $line | cut -d ':' -f 2`
220     HOST=`echo $line | cut -d ':' -f 3`
221     USER=`echo $line | cut -d ':' -f 4`
222     PORT=`echo $line | cut -d ':' -f 5`
223     RDATA=`echo $line | cut -d ':' -f 6`
224
225     echo "$LDATA -> $USER@$HOST[$PORT]:$RDATA Time: $TIME"
226
227  done < ${REPCONF}
228}
229
230check_rep_task() {
231  export DIDREP=0
232  if [ ! -e "$REPCONF" ] ; then return 0; fi
233
234  repLine=`cat ${REPCONF} | grep "^${1}:"`
235  if [ -z "$repLine" ] ; then return 0; fi
236
237  # We have a replication task for this dataset, lets check if we need to do it now
238  LDATA="$1"
239  TIME=`echo $repLine | cut -d ':' -f 2`
240
241  # Export the replication variables we will be using
242  export REPHOST=`echo $repLine | cut -d ':' -f 3`
243  export REPUSER=`echo $repLine | cut -d ':' -f 4`
244  export REPPORT=`echo $repLine | cut -d ':' -f 5`
245  export REPRDATA=`echo $repLine | cut -d ':' -f 6`
246
247  # If we are checking for a sync task, and the rep isn't marked as sync we can return
248  if [ "$2" = "sync" -a "$TIME" != "sync" ] ; then return 0; fi
249
250  # Is this a sync-task we do at the time of a snapshot?
251  if [ "$2" = "sync" -a "$TIME" = "sync" ] ; then
252     export DIDREP=1
253     echo_log "Starting replication SYNC task on ${DATASET}: ${REPLOGSEND}"
254     queue_msg "`date`: Starting replication SYNC task on ${DATASET}\n"
255     start_rep_task "$LDATA"
256     return $?
257  else
258     # Ready to do a scheduled replication
259     export DIDREP=1
260     echo_log "Starting replication SCHEDULED task on ${DATASET}: ${REPLOGSEND}"
261     queue_msg "`date`: Starting replication SCHEDULED task on ${DATASET}\n"
262     start_rep_task "$LDATA"
263     return $?
264  fi
265}
266
267start_rep_task() {
268  LDATA="$1"
269  hName=`hostname`
270
271  # Check for the last snapshot marked as replicated already
272  lastSEND=`zfs get -r backup:lpreserver ${LDATA} | grep LATEST | awk '{$1=$1}1' OFS=" " | tail -1 | cut -d '@' -f 2 | cut -d ' ' -f 1`
273
274  # Lets get the last snapshot for this dataset
275  lastSNAP=`zfs list -t snapshot -d 1 -H ${LDATA} | tail -1 | awk '{$1=$1}1' OFS=" " | cut -d '@' -f 2 | cut -d ' ' -f 1`
276 
277  if [ "$lastSEND" = "$lastSNAP" ] ; then
278     queue_msg "`date`: Last snapshot $lastSNAP is already marked as replicated!"
279     return 1
280  fi
281
282  # Starting replication, first lets check if we can do an incremental send
283  if [ -n "$lastSEND" ] ; then
284     zFLAGS="-Rv -I $lastSEND $LDATA@$lastSNAP"
285  else
286     zFLAGS="-Rv $LDATA@$lastSNAP"
287
288     # This is a first-time replication, lets create the new target dataset
289     ssh -p ${REPPORT} ${REPUSER}@${REPHOST} zfs create ${REPRDATA}/${hName} >${CMDLOG} 2>${CMDLOG}
290  fi
291
292  zSEND="zfs send $zFLAGS"
293  zRCV="ssh -p ${REPPORT} ${REPUSER}@${REPHOST} zfs receive -dvuF ${REPRDATA}/${hName}"
294
295  queue_msg "Using ZFS send command:\n$zSEND | $zRCV\n\n"
296
297  # Start up our process
298  $zSEND 2>${REPLOGSEND} | $zRCV >${REPLOGRECV} 2>${REPLOGRECV}
299  zStatus=$?
300  queue_msg "ZFS SEND LOG:\n--------------\n" "${REPLOGSEND}"
301  queue_msg "ZFS RCV LOG:\n--------------\n" "${REPLOGRECV}"
302
303  if [ $zStatus -eq 0 ] ; then
304     # SUCCESS!
305     # Lets mark our new latest snapshot and unmark the last one
306     if [ -n "$lastSEND" ] ; then
307       zfs set backup:lpreserver=' ' ${LDATA}@$lastSEND
308     fi
309     zfs set backup:lpreserver=LATEST ${LDATA}@$lastSNAP
310     echo_log "Finished replication task on ${DATASET}"
311     save_rep_props
312     zStatus=$?
313  else
314     # FAILED :-(
315     # Lets save the output for us to look at later
316     FLOG=${LOGDIR}/lpreserver_failed.log
317     echo "Failed with command:\n$zSEND | $zRCV\n" > ${FLOG}
318     echo "\nSending log:\n" >> ${FLOG}
319     cat ${REPLOGSEND} >> ${FLOG}
320     echo "\nRecv log:\n" >> ${FLOG}
321     cat ${REPLOGRECV} >> ${FLOG}
322     echo_log "FAILED replication task on ${DATASET}: LOGFILE: $FLOG"
323  fi
324
325  return $zStatus
326}
327
328save_rep_props() {
329  # If we are not doing a recursive backup / complete dataset we can skip this
330  if [ "$RECURMODE" != "ON" ] ; then return 0; fi
331  if [ "`basename $DATASET`" != "$DATASET" ] ; then return 0; fi
332
333  echo_log "Saving dataset properties for: ${DATASET}"
334  queue_msg "`date`: Saving dataset properties for: ${DATASET}\n"
335
336  # Lets start by building a list of props to keep
337  rProp=".lp-props-`echo ${REPRDATA}/${hName} | sed 's|/|#|g'`"
338
339  zfs get -r all $DATASET | grep ' local$' | awk '{$1=$1}1' OFS=" " | sed 's| local$||g' \
340        | ssh -p ${REPPORT} ${REPUSER}@${REPHOST} "cat > $rProp"
341  if [ $? -eq 0 ] ; then
342    echo_log "Successful save of dataset properties for: ${DATASET}"
343    queue_msg "`date`: Successful save of dataset properties for: ${DATASET}\n"
344    return 0
345  else
346    echo_log "Failed saving dataset properties for: ${DATASET}"
347    queue_msg "`date`: Failed saving dataset properties for: ${DATASET}\n"
348    return 1
349  fi
350}
351
352listStatus() {
353
354  for i in `grep "${PROGDIR}/backend/runsnap.sh" /etc/crontab | awk '{print $8}'`
355  do
356    echo -e "DATASET - SNAPSHOT - REPLICATION"
357    echo "------------------------------------------"
358
359    lastSEND=`zfs get -r backup:lpreserver ${i} | grep LATEST | awk '{$1=$1}1' OFS=" " | tail -1 | cut -d '@' -f 2 | cut -d ' ' -f 1`
360    lastSNAP=`zfs list -t snapshot -d 1 -H ${i} | tail -1 | awk '{$1=$1}1' OFS=" " | cut -d '@' -f 2 | cut -d ' ' -f 1`
361
362    if [ -z "$lastSEND" ] ; then lastSEND="NONE"; fi
363    if [ -z "$lastSNAP" ] ; then lastSNAP="NONE"; fi
364
365    echo "$i - $lastSNAP - $lastSEND"
366  done
367}
Note: See TracBrowser for help on using the repository browser.