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

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

Add ability to save a dataset properties during replication, this will allow
us to re-create / import data from a replicated dataset to a new system / disk.

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