· 9 years ago · Jan 02, 2017, 11:58 AM
1#!/bin/sh
2#################################################################################
3# #
4# XSIBACKUP Automated Backups for ESXi 5.1, 5.5 & 6.0 #
5# By Daniel J. Garcia Fidalgo (33HOPS) daniel.garcia@33hops.com #
6# Copyright (C) 2013-2016 33HOPS, Sistemas de Información y Redes, S.L. #
7# ALL RIGHTS RESERVED #
8# #
9#################################################################################
10
11CURRDIR=$(dirname $0)
12
13if [ "${CURRDIR:0:1}" = "/" ]
14then
15 PWD="$CURRDIR"
16else
17 CURRDIR=${CURRDIR//./}
18 PWD="$PWD""$CURRDIR"
19fi
20
21APPNAM="XSIBACKUP-FREE"
22APPVER="6.0.11"
23APPCOM="(c) VMWARE ESXi Hypervisor"
24OLDIFS=$IFS
25newline=$'\012'
26backuproom=0
27xsidefaultpath="/vmfs/volumes/datastore1/xsi-dir"
28HOSTNAME=$(hostname -f)
29HOSTIP=$(esxcli network ip interface ipv4 get -i vmk0 | grep vmk0 | awk '{ print $2 }')
30HOSTMASK=$(esxcli network ip interface ipv4 get -i vmk0 | grep vmk0 | awk '{ print $3 }')
31REMOTEUSER="admin"
32
33xsib_shutdown(){
34 rm -rf "${PWD}/.ERR"* > /dev/null 2>&1
35 if [ -f "$PWD"/xsibackup-pid ]
36 then
37 pids=$( cat "$PWD"/xsibackup-pid )
38 IFS=$newline
39 for lin in $pids
40 do
41 pid=$( echo "$lin" | awk '{ print $1 }' | sed -e 's/^ *//g' -e 's/ *$//g' )
42 if [ "$pid" = "$$" ] || [ $( ps | grep $pid | wc -l ) -eq 0 ]
43 then
44 sed -i "/$pid/d" "$PWD"/xsibackup-pid > /dev/null 2>&1
45 if [ "$( ls -l "$PWD"/xsibackup-pid 2>&1 | awk '{print $5}' | sed -e 's/^ *//g' -e 's/ *$//g' )" = "0" ]
46 then
47 rm -rf "${PWD}"/xsibackup-pid > /dev/null 2>&1
48 fi
49 KX=$( sleep 2 && kill -9 $pid && wait $pid > /dev/null 2>&1 ) && /bin/sh
50 fi
51 done
52 IFS=$OLDIFS
53 fi
54 }
55
56pid_cleanup(){
57 if [ -f "$PWD"/xsibackup-pid ]
58 then
59 pids=$( cat "$PWD"/xsibackup-pid )
60 IFS=$newline
61 for lin in $pids
62 do
63 if [ -f "$PWD"/xsibackup-pid ]
64 then
65 pid=$( echo "$lin" | awk '{ print $1 }' | sed -e 's/^ *//g' -e 's/ *$//g' )
66 if [ "$pid" != "$$" ] && [ "$( ps | grep $pid | wc -l )" = "0" ]
67 then
68 sed -i "/$pid/d" "$PWD"/xsibackup-pid
69 if [ "$( ls -l "$PWD"/xsibackup-pid 2>&1 | awk '{print $5}' | sed -e 's/^ *//g' -e 's/ *$//g' )" = "0" ]
70 then
71 rm -rf "${PWD}"/xsibackup-pid > /dev/null 2>&1
72 fi
73 fi
74 fi
75 done
76 IFS=$OLDIFS
77 fi
78 }
79
80trap "echo \"\";echo -e \"\033[0;32mShutting down nicely...\033[0m\" ; xsib_shutdown " SIGINT SIGTERM
81
82DEBUGINFO=""
83
84keyvalstr="$@"
85keyvalstr=${keyvalstr//--/¨}
86
87IFS="¨"
88for block in $keyvalstr
89do
90 if [ ! -z "$block" ]
91 then
92 VARNAM=$( echo $block | awk -F "=" '{print $1}' | sed -e 's/^ *//g' -e 's/ *$//g' )
93 VARNAM=${VARNAM//-/}
94 VARVAL="$( echo $block | awk -F "=" '{print $2}' | sed -e 's/^ *//g' -e 's/ *$//g' )"
95 VARVAL="${VARVAL//"/\"}"
96 if [ "$VARNAM" != "smtppwd" -a "$VARNAM" != "backupvms" -a "$VARNAM" != "backuppoint" -a "$VARNAM" != "subject" ]
97 then
98 VARVAL=$( echo "$VARVAL" | awk '{print tolower($0)}' )
99 DEBUGINFO="${DEBUGINFO}<br />• ${VARNAM}: $VARVAL"
100 fi
101 eval $VARNAM=\""$VARVAL"\"
102 fi
103done
104IFS=$OLDIFS
105
106keyvalstr=${keyvalstr//¨/--}
107
108datedir=$( echo $datedir | awk '{print tolower($0)}' )
109
110DEBUGINFO="${DEBUGINFO}<br />• DATE DIR: $datedir"
111
112if [ "${CURRDIR:0:1}" = "/" ]
113then
114 PWD="$CURRDIR"
115else
116 CURRDIR=${CURRDIR//./}
117 PWD="$PWD""$CURRDIR"
118fi
119
120DEBUGINFO="${DEBUGINFO}<br />• XSIDIR: $PWD"
121
122# Find out if we are in interactive mode
123if [ -t 1 ]
124then
125 launched="user"
126else
127 launched="cron"
128fi
129
130DEBUGINFO="${DEBUGINFO}<br />• LAUNCHED BY: $launched"
131
132if [ "$backuphow" != "cold" ]
133then
134 backuphow="hot"
135fi
136
137if [ -z $from ] && [ "$launched" == "cron" ]
138then
139 if [ $( ps | grep xsibackup-rsync | wc -l ) -gt 0 ]
140 then
141 exit 0
142 fi
143 if [ "$exec" = "yes" ]
144 then
145 righttime=1
146 echo $$ "cron" >> "${PWD}/xsibackup-pid"
147 elif [ ! -z "${time}" ]
148 then
149 righttime=0
150 IFS="|"
151 for moment in $time
152 do
153 NOW="$( date +"%a %H:%M" | awk '{print tolower($0)}' )"
154 if [ "$moment" == "$NOW" ]
155 then
156 righttime=1
157 fi
158 done
159 IFS=$OLDIFS
160
161 if [ ${righttime} == 0 ]
162 then
163 exit 0
164 else
165 echo $$ "cron" >> "${PWD}/xsibackup-pid"
166 fi
167 else
168 exit 0
169 fi
170
171 #echo -ne "\033[1;36mAs a preventive measure XSIBackup will now restart the ESXi cron service:\033[0m"
172 #/bin/kill -9 $(cat /var/run/crond.pid) && /usr/lib/vmware/busybox/bin/busybox crond
173 #echo -e " \033[0;32mDONE\033[0m"
174
175elif [ "$launched" == "user" ]
176then
177 if [ -f "$PWD/EULA" ]
178 then
179 EULATEXT=$(cat "$PWD/EULA")
180 EULATEXT="$EULATEXT"
181 READEULA=$(cat "$PWD/EULA" | head -n1)
182 READEULA="$READEULA"
183 eval $READEULA
184 if [ "$read" == "0" ]
185 then
186 echo -e "$EULATEXT" | sed 1d | more
187 echo ""
188 read -p "I ACCEPT THE LICENSE AGREEMENT (y/n) " yn
189 case $yn in
190 [Yy]* )
191 sed -i 's/read=0/read=1/g' EULA
192 ;;
193 [Nn]* ) exit 0;;
194 * ) echo "Please answer (y)es or (n)o."; exit 0;;
195 esac
196 fi
197 if [ "$keyvalstr" != "" ]
198 then
199 echo $$ "user" >> "${PWD}/xsibackup-pid"
200 fi
201 else
202 echo -e "\033[1;31mCannot find the EULA. The license agreement file [$PWD/EULA] must be kept.\033[0m"
203 exit 0
204 fi
205fi
206
207checksrv(){
208 OLDIFS=$IFS
209 s=0
210 IFS=':'
211 for srvpart in $1
212 do
213 if [[ $s -eq 0 ]]
214 then
215 srvaddr=$srvpart
216 elif [[ $s -eq 1 ]]
217 then
218 srvport=$srvpart
219 fi
220 s=$(($s+1))
221 done
222 IFS=$OLDIFS
223
224 scanresp=$( nc $srvaddr $srvport -w 1 )
225
226 if [[ "${scanresp/$2/}" != "$scanresp" ]]
227 then
228 echo -n "1"
229 else
230 echo -e "\033[1;31mThe server $1 cannot be contacted\033[0m"
231 exit 1
232 fi
233 IFS=$OLDIFS
234}
235
236compHashes(){
237
238 r1=${1// /\ }
239 r2=${2// /\ }
240
241 if [ -f "$r1" ]
242 then
243 md5hash1=$( md5sum "$r1" | awk -F " " '{print $1}' )
244 else
245 md5hash1=""
246 echo "The file ${r1} does not exist"
247 exit 1
248 fi
249
250 if [ -f "$r2" ]
251 then
252 md5hash2=$( md5sum "$r2" | awk -F " " '{print $1}' )
253 else
254
255 IFS=":"
256 s=1
257 for spart in $r2
258 do
259 eval "srv"$s=\""$spart"\"
260 s=$(($s+1))
261 done
262 IFS=$OLDIFS
263
264 if [ $(eval ssh "$SSHOPTS" -p "$srv2" "$srv1" "ls -la \"${srv3// /\ }\" 2> /dev/null | wc -l") -eq 0 ]
265 then
266 md5hash2="null"
267 else
268 md5hash2=$(eval ssh "$SSHOPTS" -p "$srv2" "$srv1" "md5sum \"${srv3// /\ }\"")
269 md5hash2=$( echo "$md5hash2" | awk '{print $1}')
270 fi
271 fi
272
273 if [ $md5hash1 == $md5hash2 ]
274 then
275 echo "1"
276 else
277 echo "0"
278 fi
279}
280
281#SSHOPTS="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i \"$PWD/xsibackup_id_rsa\""
282SSHOPTS="-o StrictHostKeyChecking=no -i "$PWD"/xsibackup_id_rsa"
283
284DEBUGINFO="${DEBUGINFO}<br />• KEY: $SSHOPTS"
285
286backupConfig(){
287
288 vim-cmd hostsvc/firmware/backup_config 1>/dev/null
289 configPath=$( find /scratch/downloads -type f -name "*.tgz" -exec ls -1rt "{}" + | head -n1 )
290 if [ ! -f "$configPath" ]
291 then
292 echo "Could not find the generated ESXi config .tgz file. Returned path: $configPath">>"$errfileb"
293 fi
294 if [ "$SERVERTYPE" = "NET" ]
295 then
296 eval scp "$SSHOPTS" -P$baksrvport "$configPath" $REMOTEUSER@$baksrvaddr:"$baksrvdire"/${HOSTNAME}-${HOSTIP}-config.tgz && echo "1" || echo "0"
297 else
298 cp "$configPath" "$1"/${HOSTNAME}-${HOSTIP}-config.tgz && echo "1" || echo "0"
299 fi
300}
301
302if [ ! -z "$watch" ]
303then
304 if [ $( echo "$watch" | grep -oE "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" | wc -l ) -eq 0 ] && [ "$watch" != "localhost" ] && [ "$watch" != "this" ]
305 then
306 echo -e "\033[0;31mThe provided IP cannot evaluated as an IPv4 address. Use [localhost] or [this] to refer to this same server\033[0m"
307 exit 0
308 else
309 if [ "$watch" = "localhost" ] || [ "$watch" = "this" ] || [ -f "${PWD}/xsibackup-cron-${watch}.log" ]
310 then
311 echo -e "\033[0;32mMonitoring XSIBackup activity at ${watch}\033[0m"
312 echo -e "\033[0;32mYou can stop watching at any time by pressing [Control+C]\033[0m"
313 echo -e "\033[0;32mThe remote backup process will continue at ${watch}...\033[0m"
314 echo -e "\033[0;32m----------------------------------------------------------\033[0m"
315 if [ "$watch" = "localhost" ] || [ "$watch" = "this" ]
316 then
317 tail -n20 -f "${PWD}/xsibackup-cron.log"
318 else
319 if [ -f "${PWD}/xsibackup-cron-${watch}.log" ]
320 then
321 tail -n20 -f "${PWD}/xsibackup-cron-${watch}.log"
322 else
323 echo -e "\033[0;31mCannot find the log file ${PWD}/xsibackup-cron-${watch}.log\033[0m" && exit 0
324 fi
325 fi
326 else
327 echo -e "\033[0;31mNot a valid --watch value\033[0m" && exit 0
328 fi
329 fi
330fi
331
332if [ ! -z "$host" ]
333then
334 IFS=":"
335 s=1
336 for spart in $host
337 do
338 eval "srv"$s=\""$spart"\"
339 s=$(($s+1))
340 done
341 IFS=$OLDIFS
342 if [ -z "$srv2" -o "$srv2" = "" ]
343 then
344 srv2=22
345 fi
346
347 if [ "$(checksrv $srv1:$srv2 OpenSSH)" != "1" ]
348 then
349 echo -e "\033[0;31mCannot contact server at $host, backup will halt here\033[0m"
350 echo -e "\033[0;31mCheck that the SSH service is running on the other side and firewalls in between\033[0m"
351 exit 1
352 else
353 # Checking that xsibackup exists on the other side
354 echo -e "\033[0;32mChecking for XSIBackup at $host\033[0m"
355 xsibpath=$( eval ssh "$SSHOPTS" -p "$srv2" "$srv1" "find / -name xsibackup" )
356 xsibdire=$( dirname "$xsibpath" )
357 if [ "$xsibpath" != "" ]
358 then
359 if [ "$( echo "$xsibpath" | wc -l )" == "1" ]
360 then
361 echo -e "\033[0;32mXSIBackup found at $host:$xsibpath\033[0m"
362 else
363 xsibpath=$(echo "$xsibpath" | sed -n 1p )
364 echo -e "\033[1;36mMore than one XSIBackup installation was found at $host\033[0m"
365 echo -e "\033[1;36mUsing the first found at $xsibpath\033[0m"
366 echo -e "\033[1;36mPlease fix the above ASAP by removing all installations but one\033[0m"
367 fi
368
369 if [ $(compHashes "$PWD"/xsibackup "$srv1:$srv2:$xsibpath") == "0" ]
370 then
371 echo -e "\033[1;36mXSIBackup is outdated on the remote server, updating...\033[0m"
372 eval scp "$SSHOPTS" -P$srv2 "$PWD"/xsibackup $REMOTEUSER@$srv1:$xsibpath
373 echo -e "\033[0;32mXSIBackup has been updated on the remote host $host\033[0m"
374 else
375 echo -e "\033[0;32mXSIBackup versions are equal on both ends, continuing backup...\033[0m"
376 fi
377
378 if [ $(compHashes "$PWD"/EULA "$srv1:$srv2:$xsibdire/EULA") == "0" ]
379 then
380 echo -e "\033[1;36mXSIBackup EULA is outdated on the remote server, updating...\033[0m"
381 eval scp "$SSHOPTS" -P$srv2 "$PWD"/EULA $REMOTEUSER@$srv1:$xsibdire/EULA
382 echo -e "\033[0;32mXSIBackup EULA has been updated on the remote host $host\033[0m"
383 else
384 echo -e "\033[0;32mXSIBackup EULA versions are equal on both ends, continuing backup...\033[0m"
385 fi
386
387 if [ $(compHashes "$PWD"/xsibackup-rsync "$srv1:$srv2:${xsibpath}-rsync") == "0" ]
388 then
389 echo -e "\033[1;36mRsync is outdated on the remote server, updating...\033[0m"
390 eval scp "$SSHOPTS" -P$srv2 "$PWD"/xsibackup-rsync $REMOTEUSER@$srv1:$xsibpath-rsync
391 echo -e "\033[0;32mRsync has been updated on the remote host $host\033[0m"
392 else
393 echo -e "\033[0;32mRsync versions are equal on both ends, continuing backup...\033[0m"
394 fi
395
396 else
397 echo -e "\033[0;32mCould not find XSIBackup at $host, I will install it now to ${xsidefaultpath}\033[0m"
398 eval ssh "$SSHOPTS" -p$srv2 $REMOTEUSER@$srv1 "mkdir -p ${xsidefaultpath}"
399 eval scp "$SSHOPTS" -P$srv2 "$PWD"/xsibackup "$PWD"/xsibackup-rsync $REMOTEUSER@$srv1:"${xsidefaultpath}"
400 fi
401
402 echo -e "\033[0;32mExecuting remote backup on $host\033[0m"
403 echo "Saving log locally to => xsibackup-cron-$srv1.log"
404 keyvalstr=$( echo "$keyvalstr" | sed -r "s/--time=[^--]*//" | sed -r "s/--host=[^--]*//" )
405 #eval ssh "$SSHOPTS" -p$srv2 $REMOTEUSER@$srv1 "touch \"${xsibpath}\"-cron.log"
406 #WORKING# eval ssh -f "$SSHOPTS" -p$srv2 $REMOTEUSER@$srv1 "$xsibpath --from=$HOSTIP ${keyvalstr} </dev/null>"${xsidefaultpath}"/xsibackup-cron.log 2>&1 &"
407 #WORKING# eval ssh "$SSHOPTS" -p$srv2 $REMOTEUSER@$srv1 "nohup $xsibpath --from=$HOSTIP $keyvalstr 2>&1 >/dev/null &"
408 eval ssh "$SSHOPTS" -p$srv2 $REMOTEUSER@$srv1 exec "$xsibpath \"${keyvalstr} --from=$HOSTIP\" &" >>"$PWD"/xsibackup-cron-${srv1}.log
409 exit 0
410 fi
411fi
412
413longdate=$( date '+%a, %d %b %Y %H:%M:%S %z' )
414newdirmask=$( date +%Y%m%d''%H%M%S )
415yearstring="20"
416
417proginf=$'
418######################################################################################
419# #
420# (c) --APPNAM-- --APPVER-- backup for --APPCOM-- by 33hops.com #
421# #
422######################################################################################
423'
424
425help=$'\033[0;36m--APPNAM-- --APPVER--\033[0m
426
427This is just a quick reference containing the most important arguments, please visit XSIBackup man page at:
428http://33hops.com/xsibackup-help-man-page.html to document all arguments and options.
429
430RULES:
431Arguments are a list of variable/value pairs separated by an equal sign.
432You can use any character to define values with the exception of double quotes (") and the equal sign (=).
433You must double quote variables if you use spaces or any scapable character.
434
435USAGE:
436Example 1 (backup all running VMs):
437xsibackup --backup-point=/vmfs/volumes/backup --backup-type=running --mail-from=email.sender@yourdomain.com
438--mail-to=email.recipient@anotherdomain.com --smtp-srv=smtp.yourdomain.com --smtp-port=25 --smtp-usr=username
439--smtp-pwd=password
440
441Example 2 (backup 3 VMs even if they are swiched off):
442xsibackup --backup-point=/vmfs/volumes/backup --backup-type=custom --backup-vms="WINDOWSVM1,LINUXVM2,New VM"
443--mail-from=email.sender@yourdomain.com --mail-to=email.recipient@anotherdomain.com --smtp-srv=smtp.yourdomain.com
444--smtp-port=25 --smtp-usr=username --smtp-pwd=password
445
446OPTIONS:
447
448--install-cron This will install the cron system and file xsibackup-cron to the current dir.
449 You can add as many XSIBackup commands as you want into this file, one per line.
450 The only thing you have to do is add the parameter --time, i.e. --time="Mon 23:30".
451 You can find detailed instructions in the sample xsibackup-cron file.
452
453--backup-point 1) Full path to the backup mount point within the local server, it will tipically be under
454 /vmfs/volumes, i.e. /vmfs/volumes/backup, /vmfs/volumes/datastore2.
455 2) Full path in a remote ESXi host by using the following syntax:
456 --backup-point="IP.OF.REMOTE.SERVER:PORT:/full/path/to/datastore"
457 Example: --backup-point="192.168.1.200:22:/vmfs/volumes/datastore2
458 You need to previously link the remote server to this host by using --link-srv option.
459
460--backup-how hot | cold
461 Hot (default): selected virtual machines are backed up without being switched off,
462 this is usefull for e-mail, http servers and VMs that cannot be switched off. If
463 you do not specify a value for --backup-how a hot backup will be carried out.
464 Cold: selected VMs will be switched off before backup and turned on right afterwards.
465 Good if you need a reboot cicle from time to time to refresh resources and don\'t
466 mind having a little downtime.
467
468--backup-type custom | all | running
469 Custom: if this methos is chosen then a list of the VMs to backup must be passed to
470 the --backup-vms option.
471 All: backup -all- VMS.
472 Running: backup only running virtual machines.
473
474--date-dir no (default) | yes
475 Determines if a date subfolder in the form yyyymmddhhmmss is created, if no is chosen
476 the backups will be directly made to the backup root overwriting files or adding the
477 differential data depending on the --backup-prog argument.
478
479--backup-vms List of virtual machines to backup as a comma separated list. You can exclude disks by
480 adding an exclamation sign followed by a list of disks delimited by a semicolon [;]
481 Example: --backup-vms=VM1!scsi0:1;scsi0:2,VM2!disk1;disk2
482 You can use any string, full or partial, that may help identify the disk by its name
483 or by its device descriptor. Take on account that if you use an ambiguous string per
484 instance "scsi" more than one disk may be excluded. This parameter is only needed if
485 custom is selected as the --backup-type.
486
487--backup-prog Defaults to Rsync for TCP/IP backups and to vmkfstools for datastore backups, unless
488 explicitly set to rsync. In this case local copies will be done by means of rsync.
489
490--backup-room Space that will be used for backups in gigabytes. Once this limit is reached the
491 eldest backup folders with XSIBackup folder mask will be deleted. If this argument
492 is omitted all available space will be used.
493
494--test-mode=true Allows testing backup procedure and e-mail submission without having to wait for a
495 full backup process. In this mode VMs are not copied to the backup disk.
496
497--smart-info=yes Will add a complete S.M.A.R.T. report for every local disk, defaults to no.
498
499--mail-from E-mail address as from where the HTML e-mail report will be sent.
500
501--mail-to E-mail address to which the HTML e-mail report will be sent.
502
503--subject Set your own subject for the e-mail report
504
505--smtp-srv SMTP server that we will use to send the HTML e-mail report through.
506
507--smtp-auth none|plain. You can choose plain text authentication or no authentication for SMTP
508 servers configured as open relays inside a controlled LAN. Use at your own risk.
509 If you set --smtp-auth to none you do not need to supply a username and password.
510
511--smtp-port SMTP server port
512
513--smtp-usr SMTP username used for authentication against the SMTP server.
514
515--smtp-pwd SMTP password used for authentication against the SMTP server.
516
517--smtp-sec SMTP authentication scheme, set it =TLS (upper case) if needed, default is no
518 encription. Your SMTP server must support secure renegotiation through the
519 regular SMTP port.
520
521--smtp-delay Set number of seconds from 1 to 3. This will add a delay after the e-mail body and
522 before the QUIT command. May help as a workaround with some e-mail servers like
523 hMailServer. Use only as last resource.
524
525--link-srv This command needs an argument like this --link-srv=192.168.0.100. It generates a DSA
526 key locally and adds it to the authorized_keys file at the remote host allowing to
527 communicate without a password.
528'
529
530###############################################
531# HELP CONTENT END #
532###############################################
533
534
535###############################################
536# BASE64 ASH NATIVE ENCODING FUNCTIONS #
537###############################################
538# These are base64 encodig functions programmed to
539# work natively in busybox present on ESXi >= 5.1
540# Needless to say they are not very efficient for
541# encoding big files, but very convenient to
542# encode SMTP usr & pwd on the other side and be
543# able to send e-mail from the stripped down ESXi
544# version.
545
546
547 base64arr="A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /"
548
549 a=0
550 for car in $base64arr
551 do
552 eval char$a=$car
553 a=$(($a+1))
554 done
555
556dec_to_bin(){
557
558 n=$1
559 b=1
560 while [ $n -ge 2 ]
561 do
562 binstr="$(($n % 2))"$binstr
563 n=$(($n/2))
564 b=$(($b+1))
565 done
566 echo `printf "%0$(($(($b/8+1))*8))d" $(echo $n$binstr | sed 's/^0*//')`
567}
568
569bin_to_dec(){
570
571 binnum=$1
572 c=0
573 while [ $c -lt ${#binnum} ]
574 do
575 p=$((${#binnum}-$c-1))
576 decnum=$(($decnum+$(($((${binnum:$c:1}))*$((2**$p))))))
577 c=$(($c+1))
578 done
579 echo $decnum
580}
581
582bin_to_b64(){
583
584 binstr=$1
585 u=0
586 while [ $u -lt ${#binstr} ]
587 do
588 b64str=$b64str$( eval echo \$char$(bin_to_dec `echo ${binstr:$u:6} | sed -e :a -e 's/^.\{1,5\}$/&0/;ta'`) )
589 u=$(($u+6))
590 done
591 echo $b64str
592
593}
594
595base64_encode(){
596
597 rawstr=$@
598 linewidth=64
599 s=0
600 while [ $s -lt ${#rawstr} ]
601 do
602 binout=$binout$( dec_to_bin `printf "%d\n" \'"${rawstr:$s:1}"` )
603 s=$(($s+1))
604 done
605 b64out=$( bin_to_b64 $binout )
606 app=0
607 if [[ $(( ${#rawstr}%3 )) -ne 0 ]]
608 then
609 while [ $app -lt $(( 3-${#rawstr}%3 )) ]
610 do
611 b64out=$b64out"="
612 app=$(($app+1))
613 done
614 fi
615 echo $b64out
616}
617
618###############################################
619# BASE64 ASH NATIVE ENCODING FUNCTIONS #
620###############################################
621
622ord() {
623 LC_CTYPE=C printf '%d' "'$1"
624}
625
626chr() {
627 [ "$1" -lt 256 ] || return 1
628 printf "\\$(printf '%03o' "$1")"
629}
630
631get_file_b64(){
632
633 attdir=".xsibackup-att"
634 attext=".xsib64"
635
636 if [ ! -d "$attdir" ]
637 then
638 mkdir "$attdir"
639 fi
640
641 if [ "${1:0:7}" == "http://" ]
642 then
643 if [ ! -e $(pwd)"/$attdir/.${2}${attext}" ]
644 then
645 wget -q "$1" -O "$(pwd)/$attdir/.${2}" && openssl enc -base64 -in "$(pwd)/$attdir/.${2}" > "$(pwd)/$attdir/.${2}${attext}"
646 else
647 thefile1=$(cat $(pwd)"/$attdir/.${2}${attext}")
648 wget -q "$1" -O "$(pwd)/$attdir/.${2}" && thefile2=$(cat "$(pwd)/$attdir/.${2}")
649 if [ "$thefile1" != "$thefile2" ]
650 then
651 openssl enc -base64 -in "$(pwd)/$attdir/.${2}" > "$(pwd)/$attdir/.${2}${attext}"
652 fi
653 fi
654 else
655 if [ ! -e $(pwd)"/$attdir/.${2}${attext}" ]
656 then
657 openssl enc -base64 -in "$1" > "$(pwd)/$attdir/.${2}${attext}"
658 else
659 thefile1=$(cat "$1")
660 thefile2=$(cat "$(pwd)/$attdir/.${2}${attext}")
661 if [ "$thefile1" != "$thefile2" ]
662 then
663 openssl enc -base64 -in "$1" > "$(pwd)/$attdir/.${2}${attext}"
664 fi
665 fi
666 fi
667
668}
669
670get_img(){
671 IFS="|"
672 imgcnt=0
673 for imgset in $imglist
674 do
675 IFS=";"
676 tokcnt=0
677 for imgtoken in $imgset
678 do
679 if [ $tokcnt -eq 0 ]
680 then
681 imgsrc="$imgtoken"
682 else
683 imglnk="$imgtoken"
684 fi
685 tokcnt=$(( $tokcnt+1 ))
686 done
687 IFS="|"
688 if [ "$1" == "$imgcnt" -a "$imgsrc" != "" ]
689 then
690 if [ "$imgsrc" != "none" ]
691 then
692 #imgsrc=$(eval echo $imgsrc)
693 echo "<a href=\"${imglnk}\"><img src=\"${imgsrc}\" /></a>"
694 else
695 echo "none"
696 fi
697 fi
698 imgcnt=$(( $imgcnt+1 ))
699 done
700 IFS=$OLDIFS
701}
702
703disk_smart_info(){
704
705 echo " <table class=\"report\"><tr><td colspan=\"4\"><b>S.M.A.R.T. REPORT</b></td></tr>"
706 #echo "<table class=\"report\">"
707 DISKSi=$( esxcli storage core device list | grep "Devfs Path" | awk -F "/" '{print $5}' | sed -e 's/^ *//g' -e 's/ *$//g' )
708 IFS=$newline
709 serr=0
710 for dline in $DISKSi
711 do
712 smartinfo=$( esxcli storage core device smart get -d "$dline" )
713 serr=0
714 for sline in $smartinfo
715 do
716 if [ ${sline//CANNOT\ open/} != $sline ]
717 then
718 serr=1
719 break
720 fi
721 done
722
723 if [ $serr -eq 0 ]
724 then
725 diskname=$( echo $dline echo $a | awk -F "_____" '{print $2}' )
726 echo "<tr><td colspan=\"4\" class=\"separator\"> </td></tr>"
727 echo "<tr><td colspan=\"4\"><b>Disk: "$diskname"</b></td></tr>"
728 cnt=0
729 for pline in $smartinfo
730 do
731 if [ "${pline:0:3}" != "---" ]
732 then
733 echo "<tr>"
734 echo "<td>"
735 echo "${pline:0:28}" | sed -e 's/^ *//g' -e 's/ *$//g'
736 echo "</td>"
737 echo "<td>"
738 echo "${pline:30:5}" | sed -e 's/^ *//g' -e 's/ *$//g'
739 echo "</td>"
740 echo "<td>"
741 echo "${pline:37:9}" | sed -e 's/^ *//g' -e 's/ *$//g'
742 echo "</td>"
743 echo "<td>"
744 echo "${pline:48:5}" | sed -e 's/^ *//g' -e 's/ *$//g'
745 echo "</td>"
746 echo "</tr>"
747 fi
748 cnt=$(( $cnt+1 ))
749 done
750 fi
751
752 done
753 echo "</table>"
754}
755
756if [ "$smartinfo" == "yes" ]
757then
758 smartinfo=$( disk_smart_info )
759fi
760
761is_running(){
762 #echo $(esxcfg-info | grep sh.${1} | grep "Group Name" | grep -c ^)
763 IR=$( ps | grep ${1} | wc -l )
764 echo $IR
765}
766
767if [ -f "${PWD}/xsibackup-pid" ]
768then
769 pid_cleanup
770 MERUNNING=$( cat "${PWD}/xsibackup-pid" 2>&1 | grep -v $$ | grep cron | wc -l )
771 if [ ${MERUNNING} -gt 0 ]
772 then
773 echo "----------------------------------"
774 echo "| Running XSIBackup processes: |"
775 echo "----------------------------------"
776 cat "${PWD}/xsibackup-pid" 2>&1
777 if [ "${time}" != "" ]
778 then
779 echo ""
780 echo "###########################################################"
781 echo ""
782 echo $(date +"%a %H:%M:%S") : "WARNING"
783 echo ""
784 echo "XSIBackup was launched from the cron file without user input"
785 echo "But another cron XSIBackup process is still running. Only one"
786 echo "XSIBackup process is allowed at a time per host. You may use"
787 echo "the --on-success and --on-error arguments to chain backups"
788 echo "This execution request will be ignored."
789 echo ""
790 echo "###########################################################"
791 echo ""
792 exit 0
793 fi
794 fi
795fi
796
797HOSTUUID=$( vim-cmd hostsvc/hosthardware | grep uuid | awk -F "=" '{print $2}' ) && HOSTUUID=${HOSTUUID// /} && HOSTUUID=${HOSTUUID//,/} && HOSTUUID=${HOSTUUID//\"/}
798SESSIONID=$HOSTUUID$(date +%s) && SESSIONID=$( echo $SESSIONID | openssl base64 2> /dev/null ) && SESSIONID=${SESSIONID// /} && SESSIONID=${SESSIONID//=/}
799
800proginf="${proginf//--APPNAM--/$APPNAM}"
801proginf="${proginf//--APPVER--/$APPVER}"
802proginf="${proginf//--APPCOM--/$APPCOM}"
803echo -e "$proginf"
804echo "XSIBackup PID: "$$
805
806DEBUGINFO="${DEBUGINFO}<br />• PID: $$"
807
808if [ "$backupid" != "" ]
809then
810 echo "Backup Id: " $backupid
811fi
812
813rm -rf .ERR* 2>&1
814errseed=$( date )
815errfileb="$( base64_encode $errseed )"
816errfileb="${PWD}/.ERR-${errfileb//=/}"
817touch "$errfileb"
818THERESERR=0
819ERR()
820{
821 if [ "$3" == "W" ]
822 then
823 c="warn"
824 t="WARNING"
825 else
826 c="errr"
827 t="ERROR"
828 fi
829 if [ "$1" -ne "0" ]
830 then
831 VMERRS="$(date) - Exit code: $1 - ${t}: $2"
832 echo "$(date) - Exit code: $1<br /><span class=${c}><b>${t}:</b> $2</span><br />" >> "$errfileb"
833 fi
834}
835
836ESX_VERSION=$(vmware -v | awk '{print $3}')
837if [[ "${ESX_VERSION}" != "5.1.0" -a "${ESX_VERSION}" != "5.5.0" -a "${ESX_VERSION}" != "6.0.0" -a "${ESX_VERSION}" != "6.5.0" ]]
838then
839 echo -e "\033[0;31mOnly ESXi 5.X and 6.X series are supported. You are free to try it in previous versions of ESXi but it has not been officially tested\033[0m"
840 exit 1
841fi
842
843DEBUGINFO="${DEBUGINFO}<br />• ESXi VERSION: $ESX_VERSION"
844
845if [ $# -eq 0 ]
846then
847 echo -e "\033[0;36mPreparing help, please wait...\033[0m"
848 help=${help//--APPNAM--/$APPNAM}
849 #help=${help//--APPCOM--/$APPCOM}
850 help=${help//--APPVER--/$APPVER}
851 echo "$help"
852 exit 0
853fi
854
855if [[ "${keyvalstr// /}" == "--help" ]]
856then
857 echo -e "\033[0;36mPreparing help, please wait...\033[0m"
858 help=${help//--APPNAM--/$APPNAM}
859 #help=${help//--APPCOM--/$APPCOM}
860 help=${help//--APPVER--/$APPVER}
861 echo "$help"
862 exit 0
863fi
864
865link_to_host(){
866
867IFS=":"
868i=1
869hp="22"
870for sp in $1
871do
872 if [ "$i" -eq 1 ]
873 then
874 # If it's a hostname we find the IP
875 theIp=$( ping -c 1 "$sp" | head -n1 | awk -F "(" '{print $2}' | awk -F ")" '{print $1}' )
876 if [ $( echo "$theIp" | grep -oE "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" | wc -l ) -eq 0 ]
877 then
878 echo -e "\033[0;31m${sp} can't be evaluated as an IPv4 address\033[0m"
879 exit 0
880 else
881 hip="$sp"
882 fi
883 fi
884 if [ "$i" -eq 2 ]
885 then
886 if [ $sp -gt 0 ] && [ $sp -lt 65536 ]
887 then
888 hp=$sp
889 else
890 hp=22
891 fi
892 fi
893 i=$(( $i+1 ))
894done
895IFS=$OLDIFS
896
897if [ "$(checksrv $hip:$hp OpenSSH)" != "1" ]
898then
899 echo -e "\033[0;31mThe server at IP:Port $hip:$hp cannot be contacted\033[0m"
900 exit 33
901fi
902
903if [ -f "$PWD"/xsibackup_id_rsa.pub ]
904then
905 echo -e "\033[0;36mThere is already an RSA public key at "$PWD"/xsibackup_id_rsa.pub. We will use the existing one.\033[0m"
906 echo -e "\033[0;36mEnter the remote server root password twice when prompted.\033[0m"
907 ssh_key=$(cat "$PWD"/xsibackup_id_rsa.pub)
908 ssh_key2=$( ssh -p$hp $REMOTEUSER@$hip "cat /etc/ssh/keys-root/authorized_keys")
909
910 IFS=$newline
911 for key in $ssh_key2
912 do
913 if [[ "${key// /}" == "${ssh_key// /}" ]]
914 then
915 echo -e "\033[0;36mThe local RSA key has already been added to the authorized_keys file at $1.\033[0m"
916 echo -e "\033[0;36mThere is no need to add it again, you should be able to connect with XSIBackup to $1 without any password.\033[0m"
917 exit 0
918 fi
919 done
920 IFS=$OLDIFS
921
922 ssh -p$hp $REMOTEUSER@$hip "echo $ssh_key >> /etc/ssh/keys-root/authorized_keys"
923 echo -e "\033[0;32mThe RSA key has been added to the authorized_keys file at $1.\033[0m"
924 echo -e "\033[0;32mRebooting local SSH service...\033[0m"
925 /etc/init.d/SSH restart
926 echo -e "\033[0;32mRebooting remote SSH service...\033[0m"
927 eval ssh -p$hp "$SSHOPTS" $REMOTEUSER@$hip "/etc/init.d/SSH restart"
928 exit 0
929else
930 echo -e "\033[0;36mNo RSA public key found, we will generate one...\033[0m"
931 rm -rf "$PWD"/id_rsa*
932 /usr/lib/vmware/openssh/bin/ssh-keygen -t rsa -f "$PWD"/xsibackup_id_rsa -q -N ''
933 echo -e "\033[0;32mThe RSA key has been generated.\033[0m"
934 ssh_key=$(cat "$PWD"/xsibackup_id_rsa.pub)
935 echo -e "\033[0;32mEnter the remote server root password when prompted.\033[0m"
936 ssh -p$hp $REMOTEUSER@$hip "echo $ssh_key >> /etc/ssh/keys-root/authorized_keys"
937 echo -e "\033[0;32mThe RSA key has been added to the authorized_keys file at $1.\033[0m"
938 echo -e "\033[0;32mRebooting local SSH service...\033[0m"
939 /etc/init.d/SSH restart
940 echo -e "\033[0;32mRebooting remote SSH service...\033[0m"
941 eval ssh -p$hp "$SSHOPTS" $REMOTEUSER@$hip "/etc/init.d/SSH restart"
942 exit 0
943fi
944
945}
946
947if [[ "$linksrv" != "" ]]
948then
949 link_to_host "$linksrv"
950 exit 0
951fi
952
953if [[ "${keyvalstr// /}" == "--install-cron" ]]
954then
955
956ISTHERE=$( grep -c "xsibackup-cron" /etc/rc.local.d/local.sh )
957if [ $ISTHERE -gt 0 ]
958then
959 echo "XSIBackup cron has already been installed."
960 read -p "Do you wish to remove it? (y/n) " yn
961 case $yn in
962 [Yy]* )
963 # BusyBox sed is broken fails in line deletions so we
964 # inverse the file, take the whole minus the matched line
965 # and overwrite both files /etc/rc.local.d/local.sh and /var/spool/cron/crontabs/root
966 TAB1=$( sed -n '/xsibackup/!p' /etc/rc.local.d/local.sh )
967 echo "$TAB1" > /etc/rc.local.d/local.sh
968 TAB2=$( sed -n '/xsibackup/!p' /var/spool/cron/crontabs/root )
969 echo "$TAB2" > /var/spool/cron/crontabs/root
970 echo "xsibackup-cron has been removed"
971
972 exit 0;;
973 [Nn]* ) exit 0;;
974 * ) echo "Please answer (y)es or (n)o."; exit 0;;
975 esac
976fi
977
978echo "This command will install XSIBackup cron to your ESXi > 5.1 BOX"
979echo "xsibackup-cron will be installed to the current working directory"
980echo "You should cd to the desired directory before installing the cron"
981read -p "Do you wish to continue? (y/n) " yn
982case $yn in
983 [Yy]* )
984
985 sed -i 's/exit 0//g' /etc/rc.local.d/local.sh
986 echo "/bin/kill \$(cat /var/run/crond.pid) && /bin/echo \"*/1 * * * * '${PWD}/xsibackup-cron' >> '${PWD}/xsibackup-cron.log' 2>&1\" >> /var/spool/cron/crontabs/root && /usr/lib/vmware/busybox/bin/busybox crond" >> /etc/rc.local.d/local.sh
987 #echo "/bin/echo \"*/1 * * * * '${PWD}/xsibackup-cron' >> '${PWD}/xsibackup-cron.log' 2>&1\" >> /var/spool/cron/crontabs/root" >> /etc/rc.local.d/local.sh
988 #echo "/usr/lib/vmware/busybox/bin/busybox crond" >> /etc/rc.local.d/local.sh
989 echo "" >> /etc/rc.local.d/local.sh
990 echo "exit 0" >> /etc/rc.local.d/local.sh
991 touch "${PWD}"/xsibackup-cron
992 chmod 0700 "${PWD}"/xsibackup-cron
993 echo "#!/bin/sh" > "${PWD}"/xsibackup-cron
994 echo "# This is your XSIBackup crontab, you can add your backup schedules here" >> "${PWD}"/xsibackup-cron
995 echo "# You can use regular XSIBackup commands appending the parameter --time=\"Day HH:mm\", i.e. --time=\"Mon 21:57\"" >> "${PWD}"/xsibackup-cron
996 echo "# The --time format is compounded by three letters weekday acronym (Mon,Tue,Wed,Thu,Fri,Sat,Sun) + space + hh:mm" >> "${PWD}"/xsibackup-cron
997 echo "# You can add multiple \"moments\" in a --time argument separated by a pipeline | like: Mon 17:31|Tue 21:33|Sun 19:21" >> "${PWD}"/xsibackup-cron
998 echo "#" >> "${PWD}"/xsibackup-cron
999 echo "# Example:" >> "${PWD}"/xsibackup-cron
1000 echo "#\"${PWD}/xsibackup\" --time=\"Mon 02:00|Tue 02:00|Wed 02:00|Thu 02:00|Fri 02:00|Sat 02:00|Sun 02:00\" --backup-point=\"/vmfs/volumes/backup\" --backup-type=custom --backup-vms=\"XP01,W701!scsi2:0;scsi3:1;scsi3:2,LIN02,BSD03\" --mail-from=me@mydomain.com --mail-to=someoneelse@otherdomain.com --smtp-srv=smtp.mydomain.com --smtp-port=587 --smtp-usr=me@mydomain.com --smtp-pwd=mypassword" >> "${PWD}"/xsibackup-cron
1001 echo -e "\033[0;36mRemoving cron info...\033[0m"
1002 # BusyBox sed is broken fails in line deletions so we
1003 # inverse the file, take the whole minus de matched line
1004 # and overwrite /var/spool/cron/crontabs/root
1005 TAB=$( sed -n '/xsibackup/!p' /var/spool/cron/crontabs/root )
1006 echo "$TAB" > /var/spool/cron/crontabs/root
1007 echo "Adding new cron info..."
1008 /bin/echo "*/1 * * * * '${PWD}/xsibackup-cron' >> '${PWD}/xsibackup-cron.log' 2>&1" >> /var/spool/cron/crontabs/root
1009 echo "The local cron service will be restarted"
1010 echo "You might need to reboot the ESXi server for the changes to take effect..."
1011 /bin/kill $(cat /var/run/crond.pid) && /usr/lib/vmware/busybox/bin/busybox crond
1012 echo -e "\033[0;32mcron service restarted\033[0m"
1013
1014 exit 0;;
1015 [Nn]* ) exit 0;;
1016 * ) echo "Please answer (y)es or (n)o."; exit 0;;
1017esac
1018
1019fi
1020
1021echo $longdate
1022DO_BACKUP=1
1023
1024if [ -z ${backuppoint} ]
1025then
1026 echo -e "\033[0;31mThe --backup-point string is a mandatory value\033[0m"
1027 DO_BACKUP=0
1028else
1029 if [[ -d "${backuppoint}" ]]
1030 then
1031 echo -e "\033[0;32mFound --backup-point at ${backuppoint}\033[0m"
1032 SERVERTYPE="DIR"
1033 else
1034 if [ "${backuppoint:0:1}" == "/" ]
1035 then
1036 echo -e "\033[0;31mBad --backup-point, the directory ${backuppoint} does not exist\033[0m"
1037 exit 0
1038 fi
1039
1040 # The backup point might be a server
1041 IFS=":"
1042 side=0
1043 for eachside in $backuppoint
1044 do
1045 if [ $side -eq 0 ]
1046 then
1047 #if [ $( echo "$eachside" | grep -oE "^((25[0-5]|2[0-4][0-9]|[1]?[0-9][0-9]?).){3}(25[0-5]|2[0-4][0-9]|[1]?[1-9]?[0-9])$" | wc -l ) -eq 0 ]
1048 if [ $( echo "$eachside" | grep -oE "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" | wc -l ) -eq 0 ]
1049 then
1050 echo -e "\033[0;31mThe --backup-point is not a directory and can't be evaluated as a server either\033[0m"
1051 echo -e "\033[0;31m${eachside} can't be evaluated as an IPv4 address\033[0m"
1052 exit 0
1053 fi
1054 baksrvaddr="$eachside"
1055 elif [ $side -eq 1 ]
1056 then
1057 baksrvport="$eachside"
1058 elif [ $side -eq 2 ]
1059 then
1060 baksrvdire="$eachside"
1061 elif [ $side -eq 3 ]
1062 then
1063 backsrvtrf="$eachside"
1064 fi
1065 side=$(( $side+1 ))
1066 done
1067 IFS=$OLDIFS
1068
1069 srvchkstr=$( checksrv "$baksrvaddr:$baksrvport" "OpenSSH" )
1070 if [ "$srvchkstr" = "1" ]
1071 then
1072 SERVERTYPE="NET"
1073 backupprog="rsync"
1074 else
1075 echo -e "\033[0;31mThe server --backup-point=${backuppoint} does not exist\033[0m"
1076 echo -e "\033[0;31mMake sure there is an SSH server listening on $baksrvaddr port $baksrvport and that the firewall allows this connection\033[0m"
1077 DO_BACKUP=0
1078 fi
1079 fi
1080fi
1081
1082if [ "$SERVERTYPE" = "NET" ]
1083then
1084 echo "Mirroring to server "$baksrvaddr" port "$baksrvport
1085 echo "Checking xsibackup-rsync exists on the other side..."
1086
1087 if [ $(compHashes "$PWD"/xsibackup-rsync "$baksrvaddr:$baksrvport:$baksrvdire/xsibackup-rsync") == "0" ]
1088 then
1089 echo -e "\033[0;36mxsibackup-rsync needs to be copied/updated in the remote server\033[0m"
1090 eval scp "$SSHOPTS" -P$baksrvport "$PWD"/xsibackup-rsync $REMOTEUSER@$baksrvaddr:$baksrvdire
1091 else
1092 echo -e "\033[0;36mxsibackup-rsync found on the other end and same version. Continuing IP mirror backup...\033[0m"
1093 fi
1094fi
1095
1096if [ -z "$backuptype" ]
1097then
1098 echo -e "\033[0;31mYou have to set the variable --backup-type to some of the values described in the help\033[0m"
1099 DO_BACKUP=0
1100else
1101 if [[ "$backuptype" == "custom" ]]
1102 then
1103 if [ -z "$backupvms" ]
1104 then
1105 echo -e "\033[0;31mThe --backup-vms string is a mandatory value when --backup-type is set to: \033[0m"$backuptype
1106 DO_BACKUP=0
1107 fi
1108 fi
1109fi
1110
1111if [ -z "$backupprog" ]
1112then
1113 backupprog="vmkfstools"
1114else
1115 if [[ "$backupprog" != "vmkfstools" -a "$backupprog" != "rsync" ]]
1116 then
1117 echo -e "\033[0;31mThe only accepted values for --backup-prog are vmkfstools | rsync\033[0m"
1118 DO_BACKUP=0
1119 fi
1120fi
1121
1122SEND_EMAIL=1
1123
1124if [[ -z ${mailfrom} ]]
1125then
1126 SEND_EMAIL=0
1127 SEND_EMAIL_MSG="\033[0;36mThe --mail-from string has not been set\033[0m$newline"
1128fi
1129
1130if [[ -z ${mailto} ]]
1131then
1132 SEND_EMAIL=0
1133 SEND_EMAIL_MSG=$SEND_EMAIL_MSG"\033[0;36mThe --mail-to string has not been set\033[0m$newline"
1134fi
1135
1136if [ -z "${subject}" ]
1137then
1138 subject="ESXi Backup Report. More OSS at http://33hops.com/free-open-source-software.html#xsibackup"
1139fi
1140
1141if [[ -z ${smtpsrv} ]]
1142then
1143 SEND_EMAIL=0
1144 SEND_EMAIL_MSG=$SEND_EMAIL_MSG"\033[0;36mThe --smtp-srv string has not been set\033[0m$newline"
1145fi
1146
1147if [[ -z ${smtpport} ]]
1148then
1149 SEND_EMAIL=0
1150 SEND_EMAIL_MSG=$SEND_EMAIL_MSG"\033[0;36mThe --smtp-port string has not been set\033[0m$newline"
1151fi
1152
1153if [[ -z ${smtpauth} ]]
1154then
1155 smtpauth="plain"
1156elif [ "$smtpauth" = "none" ]
1157then
1158 SEND_EMAIL_MSG=$SEND_EMAIL_MSG"\033[0;36mThe --smtp-auth string has been set to -none-\033[0m$newline"
1159fi
1160
1161if [[ -z ${smtpusr} ]]
1162then
1163 if [[ "${smtpauth}" != "none" ]]
1164 then
1165 SEND_EMAIL=0
1166 SEND_EMAIL_MSG=$SEND_EMAIL_MSG"\033[0;36mThe --smtp-usr string has not been set, you need --smtp-usr if --smtp-auth is other than -none-\033[0m$newline"
1167 fi
1168fi
1169
1170if [[ -z ${smtppwd} ]]
1171then
1172 if [[ "${smtpauth}" != "none" ]]
1173 then
1174 SEND_EMAIL=0
1175 SEND_EMAIL_MSG=$SEND_EMAIL_MSG"\033[0;36mThe --smtp-pwd string has not been set, you need --smtp-pwd if --smtp-auth is other than -none-\033[0m$newline"
1176 fi
1177fi
1178
1179#if [[ -e "${busyboxbin}" ]]
1180#then
1181# echo "BusyBox binary found at - $busyboxbin -"
1182#else
1183# SEND_EMAIL=0
1184# SEND_EMAIL_MSG=$SEND_EMAIL_MSG"No BusyBox binary has been found in the specified path - $busyboxbin - if you want an e-mail report to be sent you will need BusyBox.$newline"
1185#fi
1186
1187
1188if [[ "${SEND_EMAIL}" == 0 ]]
1189then
1190 echo -e "\033[0;36mThe e-mail report will not be sent because of the followig reasons:\033[0m$newline$SEND_EMAIL_MSG$newline"
1191fi
1192
1193if [[ "${DO_BACKUP}" == 0 ]]
1194then
1195 echo -e "\033[0;31mThe backup will halt here because some mandatory values are missing\033[0m"
1196 exit 0
1197fi
1198
1199if [ "$backuproom" -gt 0 ]
1200then
1201 echo -e "\033[0;36mThe backup room has been limited to $backuproom gb.\033[0m"
1202fi
1203
1204getDatastorepathByDatastorename(){
1205
1206 VMDATA=$(vim-cmd vmsvc/get.datastores $1)
1207 IFS=$newline
1208 for ds in $VMDATA
1209 do
1210 ln=$( echo $ds | awk '{ print $1 }' | sed -e 's/^ *//g' -e 's/ *$//g' )
1211 if [ $ln = "name" ]
1212 then
1213 tkn=0
1214 IFS=$OLDIFS
1215 for tk in $ds
1216 do
1217 if [ "$tk" == "$2" ]
1218 then
1219 ord=$tkn
1220 fi
1221 tkn=$(( $tkn+1 ))
1222 done
1223 fi
1224 if [ $ln = "url" ]
1225 then
1226 tkn=0
1227 IFS=$OLDIFS
1228 for tk in $ds
1229 do
1230 if [ "$tkn" == "$ord" ]
1231 then
1232 echo "$tk"
1233 fi
1234 tkn=$(( $tkn+1 ))
1235 done
1236 fi
1237 done
1238}
1239
1240avail_backup_room(){
1241
1242 OLDIFS=$IFS
1243 AVAILS=$( df -m )
1244 MYPATH=$( getMountedPath $1 )
1245 IFS=$newline
1246 for line in $AVAILS
1247 do
1248 DFPATH=$( echo $line | awk '{ print $6 }' )
1249 if [[ "${MYPATH#*$DFPATH}" != "$MYPATH" ]]
1250 then
1251 dirs=$(ls -1d "$backuppoint/$yearstring"* 2>/dev/null | wc -l)
1252 if [ $dirs -gt 0 ]
1253 then
1254 THEUSED=$( du -scm "$backuppoint"/$yearstring* | grep total | awk '{ print $1 }' )
1255 else
1256 THEUSED=0
1257 fi
1258 THEROOM=$( echo $line | awk '{ print $4 }' )
1259 fi
1260 done
1261 IFS=$OLDIFS
1262
1263 if [[ -z ${THEROOM} ]]
1264 then
1265 echo -e "\033[0;31mCould not get available backup room in backup device\033[0m"
1266 else
1267 if [ "$backuproom" -gt 0 ]
1268 then
1269 echo $(( $backuproom*1024-$THEUSED ))
1270 else
1271 echo $THEROOM
1272 fi
1273 fi
1274
1275}
1276
1277get_vm_state(){
1278
1279 if [ "$2" != "" ]
1280 then
1281 IFS=":"
1282 pn=1
1283 for spart in $2
1284 do
1285 eval "srv"$pn=\""$spart"\"
1286 pn=$(( $pn+1 ))
1287 done
1288 IFS=$OLDIFS
1289
1290 SOUTPUT=$(eval ssh "$SSHOPTS" -p "$srv2" "$srv1" exec "vim-cmd vmsvc/power.getstate $1 | grep Powered 2> /dev/null")
1291
1292 else
1293 SOUTPUT=$(vim-cmd vmsvc/power.getstate $1 | grep Powered)
1294 fi
1295
1296 if [ "$SOUTPUT" = "Powered off" ]
1297 then
1298 echo "OFF"
1299 else
1300 echo "ON"
1301 fi
1302}
1303
1304make_room(){
1305
1306 OLDIFS=$IFS
1307 ROOMUSED=$( du -sm $2 )
1308 n=0
1309 while [[ "$1" -gt "$(avail_backup_room $2)" ]]
1310 do
1311 if [ "$n" -gt 99 ]
1312 then
1313 available=$(avail_backup_room $2)
1314 echo -e "\033[0;36mCannot make $(( $1/1024 ))G of room, only $(( $available/1024 ))G can be made available\033[0m"
1315 exit 0
1316 fi
1317
1318 OLDESTDIR=$( find $2/ -type d -name "$yearstring*" -maxdepth 1 | sort -nr | tail -1 )
1319 n=$(( $n+1 ))
1320 if [ -d "$OLDESTDIR" ]
1321 then
1322 rm -rf "$OLDESTDIR" 2>/dev/null
1323 fi
1324 DELDIRS=$DELDIRS"<br />"$OLDESTDIR
1325 done
1326 IFS=$OLDIFS
1327 echo "$DELDIRS"
1328}
1329
1330getValue(){
1331
1332 RawData=`eval $1`
1333
1334 IFS=$newline
1335 for dataline in $RawData
1336 do
1337 if [[ ${dataline//$2/} != "$dataline" ]]
1338 then
1339 if [[ ${dataline//=/} != "$dataline" ]]
1340 then
1341
1342 keyval=$dataline
1343
1344 if [[ ${dataline//vmfs/} == "$dataline" ]]
1345 then
1346 keyval=${keyval//-/}
1347 fi
1348
1349 keyval=${keyval//\"/}
1350 keyval=${keyval//,/}
1351 keyval=${keyval// /}
1352 keyval=${keyval//:/}
1353 echo $keyval
1354 exit 0
1355
1356 elif [[ ${dataline//:/} != "$dataline" ]]
1357 then
1358
1359 keyval=$dataline
1360 keyval=${keyval//-/}
1361 keyval=${keyval//\"/}
1362 keyval=${keyval//,/}
1363 keyval=${keyval// /}
1364 keyval=${keyval//:/=}
1365 echo $keyval
1366 exit 0
1367
1368 else
1369
1370 keyval=$dataline
1371 keyval=${keyval//-/}
1372 keyval=${keyval//\"/}
1373 keyval=${keyval//,/}
1374 keyval=${keyval// /}
1375 keyval=`echo $keyval | sed 's/[ \t]\+/ /g'`
1376 keyval=${keyval// /=}
1377 echo $keyval
1378 exit 0
1379
1380 fi
1381 exit 0
1382
1383 fi
1384
1385 done
1386 IFS=$OLDIFS
1387
1388}
1389
1390openFirewall(){
1391
1392 # We check if the firewall is loaded
1393 FWOUT=$( esxcli network firewall get )
1394 IFS=$newline
1395 for fwline in $FWOUT
1396 do
1397 # trim
1398 fwline=$( echo $fwline | sed -e 's/^ *//' -e 's/ *$//' )
1399
1400 if [ "$fwline" = "Loaded: false" ]
1401 then
1402 LOADFW=$( esxcli network firewall load )
1403 fi
1404
1405 done
1406
1407 IFS=$OLDIFS
1408 FWOUT=$( esxcli network firewall ruleset list | grep "$2" )
1409
1410 if [[ "$FWOUT" == "" ]]
1411 then
1412
1413 chmod 644 /etc/vmware/firewall/service.xml
1414 chmod +t /etc/vmware/firewall/service.xml
1415
1416 FWRULE="<service id='"$3"'>\n
1417 <id>"$2"</id>\n
1418 <rule id='"$4"'>\n
1419 <direction>outbound</direction>\n
1420 <protocol>"$5"</protocol>\n
1421 <porttype>dst</porttype>\n
1422 <port>"$1"</port>\n
1423 </rule>\n
1424 <enabled>true</enabled>\n
1425 <required>false</required>\n
1426 </service>\n
1427 </ConfigRoot>"
1428 ADDT=`echo $FWRULE | sed 's/$newline//g'`
1429 sed -i 's,<\/ConfigRoot>,'"$ADDT"',g' "/etc/vmware/firewall/service.xml"
1430 chmod 444 /etc/vmware/firewall/service.xml
1431 esxcli network firewall refresh
1432 echo "Firewall rule $2 added..."
1433
1434 else
1435
1436 # If the firewall service $2 exists we make sure it is open
1437 esxcli network firewall ruleset set --ruleset-id="$2" --enabled=true
1438 echo "Opening port $1 for $2 service..."
1439 fi
1440
1441}
1442
1443getFilename(){
1444IFS="/"
1445 for trozo in $1
1446 do
1447 disk=$trozo
1448 done
1449IFS=$OLDIFS
1450 echo $disk
1451}
1452
1453getVMDir(){
1454
1455 VMDIR=$( vim-cmd vmsvc/get.filelayout $1 | grep vmPathName )
1456 ivmd=0
1457 IFS="="
1458 for pa in $VMDIR
1459 do
1460 #pa=${pa// /}
1461 if [ $ivmd -eq 1 ]
1462 then
1463 IFS="]"
1464 ivme=0
1465 for pb in $pa
1466 do
1467 if [ $ivme -eq 1 ]
1468 then
1469 vmxpath=$( echo $pb | sed -e 's/^ *//g' -e 's/ *$//g' )
1470 vmxdir=$( dirname "${vmxpath}" )
1471 echo ${vmxdir}
1472 fi
1473 ivme=$(( $ivme+1 ))
1474 done
1475 fi
1476 ivmd=$(( $ivmd+1 ))
1477 done
1478}
1479
1480getVMName(){
1481
1482 VMNAME=$( vim-cmd vmsvc/get.config $1 | grep name )
1483 ivmg=0
1484 IFS=","
1485 for name in $VMNAME
1486 do
1487 if [ $ivmg -eq 0 ]
1488 then
1489 name=${name// = /=}
1490 eval $name
1491 echo $name
1492 fi
1493 ivmg=$(( $ivmg+1 ))
1494 done
1495
1496}
1497
1498getVMXDir(){
1499
1500 theRightCol=""
1501 VMDATA=$(vim-cmd vmsvc/get.datastores $1)
1502
1503 theVMXDir=""
1504 IFS=$newline
1505 for ds in $VMDATA
1506 do
1507 ln=$( echo $ds | awk '{ print $1 }' | awk '{print tolower($0)}' | sed -e 's/^ *//g' -e 's/ *$//g' )
1508 if [ "$ln" = "name" ]
1509 then
1510 tkn=0
1511 IFS=$OLDIFS
1512 for tk in $ds
1513 do
1514 if [ "$tk" != "name" ]
1515 then
1516 VMNAMESTR="$(getVMName $1)"
1517 DATASTSTR=$( vim-cmd vmsvc/getallvms | grep -v $'\040'$'\040'"${VMNAMESTR}_XSIBAK"$'\040'$'\040' | grep $'\040'$'\040'"${VMNAMESTR}"$'\040'$'\040' | awk -F '[' '{print $2}' | awk '{print $1}' | sed -e 's/\[//g' | sed -e 's/\]//g' | sed -e 's/^ *//g' -e 's/ *$//g' )
1518 if [ "$DATASTSTR" = "$tk" ]
1519 then
1520 theRightCol=$tkn
1521 fi
1522 fi
1523 tkn=$(( $tkn+1 ))
1524 done
1525 fi
1526 if [ "$ln" = "url" ]
1527 then
1528 tkn=0
1529 IFS=$OLDIFS
1530 for tk in $ds
1531 do
1532 if [ $tk != "url" ] && [ "$tkn" = "$theRightCol" ]
1533 then
1534 if [ -f "$tk/$(getVMDir $1)/"*".vmx" ]
1535 then
1536 theVMXDir=$tk"/"$(getVMDir $1)
1537 theVMXDir=$( echo "$theVMXDir" | sed -e 's/^ *//g' -e 's/ *$//g' )
1538 fi
1539 fi
1540 tkn=$(( $tkn+1 ))
1541 done
1542 fi
1543 done
1544 if [ ${#theVMXDir} -gt 0 ] && [ -d "$theVMXDir" ]
1545 then
1546 echo "$theVMXDir"
1547 fi
1548}
1549
1550getVMSize(){
1551
1552 VMDATA=$(vim-cmd vmsvc/get.datastores $1)
1553 VMNOME=$(getVMName $1)
1554 vmxdir=$(getVMXDir $1)
1555 totalsize=0
1556
1557 IFS=','
1558 for evm in $backupvms
1559 do
1560 if [ "${evm//$VMNOME/}" != "$evm" ]
1561 then
1562 IFS='!'
1563 nex=0
1564 vmdk2exclude=""
1565 for excparts in $evm
1566 do
1567 if [ $nex -eq 1 ]
1568 then
1569 vmdk2exclude="$excparts"
1570 fi
1571 nex=$(( $nex+1 ))
1572 done
1573 IFS=$OLDIFS
1574 fi
1575 done
1576 IFS=$OLDIFS
1577
1578 diskpaths=$(getAllFiles $1)
1579
1580 IFS=$newline
1581 for disk in $diskpaths
1582 do
1583 if [ "${disk:$(( ${#disk}-5 ))}" == ".vmdk" ]
1584 then
1585
1586 matchex=0
1587 IFS=";"
1588 for exvmdk in $vmdk2exclude
1589 do
1590 if [ "${disk//$exvmdk/}" != "$disk" ]
1591 then
1592 matchex=1
1593 fi
1594 done
1595 IFS=$OLDIFS
1596
1597 if [ $matchex -eq 0 ]
1598 then
1599 IFS='='
1600 tm=0
1601 for term in $disk
1602 do
1603 if [ $tm -eq 1 ]
1604 then
1605 path=${term//\"/}
1606 if [ ${path:0:1} == "/" ]
1607 then
1608 if [ -f "$path" ]
1609 then
1610 vmdksize=$(du -ms "$path" | awk '{print $1}')
1611 flat=$(cat "$path" | grep "flat.vmdk\|delta.vmdk" | awk -F "\"" '{print $2}')
1612 if [ "$flat" != "" ]
1613 then
1614 flat=${flat//\"/}
1615 flat=$(dirname "$path")/"$flat"
1616 flatsize=$(du -m "$flat" | awk '{print $1}')
1617 else
1618 flatsize=0
1619 fi
1620 else
1621 vmdksize=0
1622 flatsize=0
1623 fi
1624 else
1625 if [ -f "${vmxdir}/${path}" ]
1626 then
1627 vmdksize=$(du -ms "${vmxdir}/${path}" | awk '{print $1}')
1628 flat=$(cat "${vmxdir}/${path}" | grep flat.vmdk | awk -F "\"" '{print $2}')
1629 flat="${vmxdir}/${flat//\"/}"
1630 flatsize=$(du -m "${flat}" | awk '{print $1}')
1631 else
1632 vmdksize=0
1633 flatsize=0
1634 fi
1635 fi
1636 totalsize=$(( $totalsize+$vmdksize+$flatsize ))
1637 fi
1638 tm=$(( $tm+1 ))
1639 done
1640 IFS=$OLDIFS
1641 fi
1642 fi
1643 done
1644
1645 if [ "$totalsize" != "" ]
1646 then
1647 echo $totalsize
1648 else
1649 echo "0"
1650 fi
1651}
1652
1653killRsync(){
1654
1655 if [ "$1" != "" ]
1656 then
1657 if [ "$2" != "" ]
1658 then
1659 sshport="$2"
1660 else
1661 sshport="22"
1662 fi
1663 REMPIDS=$(eval ssh "$SSHOPTS" -p "$sshport" "$1" exec "pkill -9 xsibackup-rsync 2>&1")
1664 fi
1665 RSPID=$(pkill -9 xsibackup-rsync)
1666 echo -e "\033[0;36mPrevious xsibackup-rsync process terminated\033[0m"
1667}
1668
1669compSizes(){
1670
1671 s1=${1// /\ }
1672 s2=${2// /\ }
1673
1674 if [ -f "$s1" ]
1675 then
1676 size1=$( ls -las "$s1" 2> /dev/null | awk -F " " '{print $1}' )
1677 else
1678 size1=""
1679 echo -e "\033[0;31mThe file ${s1} does not exist\033[0m"
1680 exit 1
1681 fi
1682
1683 if [ -f "$s2" ]
1684 then
1685 size2=$( ls -las "$s2" 2> /dev/null | awk -F " " '{print $1}' )
1686 else
1687 IFS=":"
1688 s=1
1689 for spart in $s2
1690 do
1691 eval "srv"$s=\""$spart"\"
1692 s=$(($s+1))
1693 done
1694 IFS=$OLDIFS
1695
1696 size2=$( eval ssh "$SSHOPTS" -p "$srv2" "$srv1" "ls -las \"${srv3// /\ }\"" )
1697 size2=$( echo "$size2" | awk '{print $1}')
1698 fi
1699
1700 if [ "$size1" -eq "$size2" ]
1701 then
1702 echo "1"
1703 else
1704 echo "0"
1705 fi
1706}
1707
1708getTopVmdks(){
1709 snapshots=$( cat "$( getVMXDir $1 )/"*.vmsd )
1710 IFS=$newline
1711 for eachsnap in $snapshots
1712 do
1713 if [ ${eachsnap//displayName/} != ${eachsnap} ]
1714 then
1715 eval $( echo ${eachsnap// /} | awk -F '.' '{for (i=2; i<=NF; i++) print $i}' )
1716 fi
1717 if [ ${eachsnap//uid/} != ${eachsnap} ]
1718 then
1719 eval $( echo ${eachsnap// /} | awk -F '.' '{for (i=2; i<=NF; i++) print $i}' )
1720 fi
1721 if [ "$displayName" == "xsibackup" ]
1722 then
1723 if [ ${eachsnap//numDisks/} != ${eachsnap} ]
1724 then
1725 eval $( echo ${eachsnap// /} | awk -F '.' '{for (i=2; i<=NF; i++) print $i}' )
1726 topsnapshot=$( echo ${eachsnap// /} | awk -F '.' '{print $1}' )
1727 theuid=$uid
1728 fi
1729 fi
1730 done
1731 IFS=$OLDIFS
1732 theDisks=""
1733 for i in $( seq 0 $(( $numDisks-1 )) )
1734 do
1735 theDisk=$( echo "$snapshots" | grep "${topsnapshot}.disk$i.fileName" | awk -F '=' '{print $2}' | sed -e 's/^ *//g' -e 's/ *$//g' )
1736 theNode=$( echo "$snapshots" | grep "${topsnapshot}.disk$i.node" | awk -F '=' '{print $2}' | sed -e 's/^ *//g' -e 's/ *$//g' )
1737 theDisks=${theDisks}${newline}${theNode//\"/}".fileName = "${theDisk}
1738 #theDisks=${theDisks}${newline}${theDisk}
1739 done
1740 if [ "$2" == "id" ]
1741 then
1742 echo "$theuid"
1743 else
1744 echo "$theDisks"
1745 fi
1746}
1747
1748deleteSnapshot(){
1749 # Get last snapshot id
1750 lastId=$( vim-cmd vmsvc/snapshot.get $1 | grep Id | awk -F ':' '{print $2}' | sed -e 's/^ *//g' -e 's/ *$//g' | tail -n1 )
1751 if [ "$lastId" == "$( getTopVmdks $1 id )" ] && [ "$lastId" != "" ]
1752 then
1753 delSna=$( vim-cmd vmsvc/snapshot.remove $1 $lastId false )
1754 fi
1755}
1756
1757getAllFiles(){
1758 FILES=$(vim-cmd vmsvc/get.filelayout $1 | grep "vmdk\|vmsn" | sed "s/\t//g" | sed "s/vmPathName = //g" \
1759 | sed "s/,//g" | sed 's/"//g' | sed -e 's/^ *//g' -e 's/ *$//g' | sort -u)
1760 IFS=$newline
1761 for paz in $FILES
1762 do
1763 if [ "${paz:0:1}" == "[" ]
1764 then
1765 dsname=$( echo "$paz" | awk '{print $1}' | sed -e 's/\[//g' -e 's/\]//g' | sed -e 's/^ *//g' -e 's/ *$//g' )
1766 dspath=$( getDatastorepathByDatastorename $1 "$dsname" )
1767 tlpath=$( echo ${paz/"["$dsname"]"/} | sed -e 's/^ *//g' -e 's/ *$//g' )
1768 echo "DISK=""$dspath"/"$tlpath"
1769 else
1770 echo "DISK=""$( getVMXDir $1 )"/"$paz"
1771 fi
1772 done
1773 IFS=$OLDIFS
1774}
1775
1776isFileOpen(){
1777 ISOPEN=$( tail -n1 "$1" 2>&1 )
1778 if [ "${ISOPEN/Device or resource busy/}" != "$ISOPEN" ]
1779 then
1780 echo "1"
1781 else
1782 echo "0"
1783 fi
1784}
1785
1786getSnapshotIdByName(){
1787 # $1 => Snapshot Name
1788 # $2 => .vmsd path
1789 SNAPORD=$( grep ".displayName = \"$1\"" "$2" | awk -F "." '{print $1}' )
1790 SNAPID=$( grep "${SNAPORD}.uid" "$2" | awk -F "=" '{print $2}' | sed 's/\"//g' | sed 's/\ //g' )
1791 echo "$SNAPID"
1792}
1793
1794getSnapshotFilesById(){
1795 # $1 => Snapshot Id
1796 # $2 => .vmsd path
1797 snf=$( grep "uid = \"$1\"" "$2" | awk -F "." '{print $1}' )
1798 snf1=$( grep ${snf}.filename "$2" | awk -F "=" '{print $2}' | sed 's/\"//g' )
1799 snf=$( grep "parent = \"$1\"" "$2" | awk -F "." '{print $1}' | sed 's/snapshot//g' )
1800 snf2=$( grep -E snapshot${snf}.disk[0-9]+.fileName "$2" | grep .vmdk | awk -F "=" '{print $2}' | sed 's/\"//g' )
1801 snf3=${snf2//.vmdk/-delta.vmdk}
1802
1803 output="$snf1"${newline}"$snf2"${newline}"$snf3"
1804 vmsddir=$( dirname "${2}" )
1805 vmsddir="$vmsddir"
1806 IFS=$newline
1807 for snaplin in $output
1808 do
1809 snapl=$(echo "${snaplin}" | sed -e 's/^ *//g' -e 's/ *$//g' )
1810 if [ "${snapl:0:1}" = "/" ]
1811 then
1812 if [ -f "${snapl}" ]
1813 then
1814 spout="${spout}"${newline}"${snapl}"
1815 fi
1816 else
1817 snaplp="$(echo ${snapl} | sed -e 's/^ *//g' -e 's/ *$//g' )"
1818 if [ -f "${vmsddir}"/"${snaplp}" ]
1819 then
1820 spout="${spout}"${newline}"${vmsddir}"/"${snaplp}"
1821 fi
1822 fi
1823 done
1824 IFS=$OLDIFS
1825 echo "$spout"
1826}
1827
1828replaceAbsolutePaths(){
1829 if [ -f "$1" ]
1830 then
1831 filecontent=$( cat "$1" )
1832 filecontent="$filecontent"
1833 else
1834 filecontent="$1"
1835 fi
1836 abspath="0"
1837 newfilecontent=""
1838 IFS=$newline
1839 for fileline in $filecontent
1840 do
1841 value=$( echo "$fileline" | awk -F "=" '{print $2}' | sed -e 's/^ *//g' -e 's/ *$//g' | sed 's/\"//g' )
1842 if [ "${value:0:1}" = "/" ]
1843 then
1844 newvalue=$( basename "$value" )
1845 #newfileline="${fileline//$value/$newvalue}"
1846 newfileline=$( echo "$fileline" | sed "s|$value|$newvalue|g" )
1847 newfileline="$newfileline"
1848 abspath="1"
1849 else
1850 newfileline="$fileline"
1851 fi
1852 newfilecontent="${newfilecontent}${newfileline}"$newline
1853 done
1854 IFS=$OLDIFS
1855 if [ "$abspath" = "1" ]
1856 then
1857 echo "$newfilecontent"
1858 else
1859 echo "$filecontent"
1860 fi
1861}
1862
1863cloneVM(){
1864
1865 # Get datastores for VM
1866 DSS=$( vim-cmd vmsvc/get.filelayoutex $1 | grep name | awk -F ' = ' '{print $2}' | awk -F ']' '{print $1}' | sed 's/\"//g' | sed 's/\[//g' | sort | uniq )
1867 # Do not allow datastores with spaces
1868 for ds in $DSS
1869 do
1870 if [ "${ds//\ /}" != "$ds" ]
1871 then
1872 echo -e "\033[0;31mXSIBackup does not allow spaces in datastore names\033[0m"
1873 echo -e "\033[0;31mPlease remove spaces in [$ds] and run again\033[0m"
1874 exit 0
1875 fi
1876 done
1877
1878 delSnapshot=$( (deleteSnapshot $1) 2>&1 )
1879 if [ "$delSnapshot" != "" ]
1880 then
1881 VMERRS="$delSnapshot"
1882 echo "$delSnapshot">>"$errfileb"
1883 fi
1884
1885 if NAM=$( getVMName $1)
1886 then
1887 cloneMsg="\033[0;36mVM name:\033[0m $NAM\n"
1888 else
1889 $( ERR $? "Error getting VM name for: \"$1\"" )
1890 fi
1891
1892 VMPID=$( ps | grep "$NAM" | awk '{print $2}' | head -n1 )
1893
1894 VMXDir="$( getVMXDir $1 )"
1895 if [ "$VMXDir" != "" ]
1896 then
1897 cloneMsg="\033[0;36mVMX file directory:\033[0m \"$VMXDir\"\n"
1898 else
1899 $( ERR $? "Error getting VMX file directory for: \"$NAM\"" )
1900 fi
1901
1902 VMXFILEPATH=$( ls "$VMXDir/"*".vmx" 2>&1 )
1903 if [ ! -f "$VMXFILEPATH" ]
1904 then
1905 echo -e "\033[0;31mNo .vmx config file found for $NAM ($1)\033[0m"
1906 $( ERR $? "No .vmx config file found for $NAM ($1)" )
1907 fi
1908 VMXFILEDIR=$( dirname "$VMXFILEPATH" )
1909 VMXFILENAME=$( basename "$VMXFILEPATH" )
1910
1911 VMSDFILEPATH=$( ls "$VMXDir/"*".vmsd" 2>&1 )
1912 if [ ! -f "$VMSDFILEPATH" ]
1913 then
1914 echo -e "\033[0;31mNo .vmsd file found for $NAM ($1)\033[0m"
1915 $( ERR $? "No .vmsd file found for $NAM ($1)" )
1916 fi
1917 VMSDFILEDIR=$( dirname "$VMSDFILEPATH" )
1918 VMSDFILENAME=$( basename "$VMSDFILEPATH" )
1919
1920 VMXFFILEPATH=$( ls "$VMXDir/"*".vmxf" 2>&1 )
1921 if [ ! -f "$VMXFFILEPATH" ]
1922 then
1923 echo -e "\033[0;36mNo .vmxf file found for $NAM ($1)\033[0m"
1924 $( ERR $? "No .vmxf file found for $NAM ($1)" "W" )
1925 fi
1926 NVRAMFILEPATH=$( ls "$VMXDir/"*".nvram" 2>&1 )
1927 if [ ! -f "$NVRAMFILEPATH" ]
1928 then
1929 echo -e "\033[0;36mNo .nvram file found for $NAM ($1)\033[0m"
1930 $( ERR $? "No .nvram file found for $NAM ($1)" "W" )
1931 fi
1932
1933 VMD="$( getVMDir $1 )"
1934 if [ "$VMD" != "" ]
1935 then
1936 cloneMsg="\033[0;36mVM directory:\033[0m $VMD\n"
1937 else
1938 echo -e "Error getting VM directory for [$1]"
1939 $( ERR $? "Error getting VM directory for [$1]" )
1940 fi
1941
1942 VMXFILECONTENT=$( cat "$VMXFILEPATH" )
1943 VMSDFILECONTENT=$( cat "$VMSDFILEPATH" )
1944
1945 if [ "$SERVERTYPE" = "DIR" ]
1946 then
1947 if [ "$datedir" = "yes" ]
1948 then
1949 thedir="$2"/"$newdirmask"/"$NAM"
1950 else
1951 thedir="$2"/"$NAM"
1952 fi
1953
1954 if [ -d "$thedir" ]
1955 then
1956 if [ "$backupprog" = "vmkfstools" ]
1957 then
1958 if [ -d "$thedir" ]
1959 then
1960 rm -rf "$thedir/"*
1961 fi
1962 fi
1963 else
1964 mkdir -p "$thedir"
1965 fi
1966 if [ -f "$VMXFILEPATH" ]
1967 then
1968 #VMXFILECONTENT=$( cat "$VMXFILEPATH" )
1969 VMXFILECONTENT=$( replaceAbsolutePaths "${VMXFILECONTENT}" )
1970 echo "$VMXFILECONTENT" > "$thedir"/"$VMXFILENAME"
1971 fi
1972 if [ -f "$VMSDFILEPATH" ]
1973 then
1974 #VMSDFILECONTENT=$( cat "$VMSDFILEPATH" )
1975 VMSDFILECONTENT=$( replaceAbsolutePaths "${VMSDFILECONTENT}" )
1976 echo "$VMSDFILECONTENT" > "$thedir"/"$VMSDFILENAME"
1977 fi
1978 if [ -f "$VMXFFILEPATH" ]
1979 then
1980 cp "$VMXFFILEPATH" "$thedir"
1981 fi
1982 if [ -f "$NVRAMFILEPATH" ]
1983 then
1984 cp "$NVRAMFILEPATH" "$thedir"
1985 fi
1986 elif [ "$SERVERTYPE" = "NET" ]
1987 then
1988 thedir="$2"
1989 if [ "$backsrvtrf" = "F" ]
1990 then
1991 # Delete remote folder
1992 RM=$(eval ssh "$SSHOPTS" -p "$baksrvport" "$baksrvaddr" exec "rm -rf \"${2// /\ }\" 2>&1")
1993 fi
1994
1995 LS=$(eval ssh "$SSHOPTS" -p "$baksrvport" "$baksrvaddr" exec "ls -la \"${2// /\ }\" 2>&1")
1996 if [ "${LS/No such file or directory/}" != "$LS" ]
1997 then
1998 CR=$(eval ssh "$SSHOPTS" -p $baksrvport "$baksrvaddr" exec "mkdir -p \"${2// /\ }\" 2>&1")
1999 if [ "${CR/Operation not permitted/}" != "$CR" ]
2000 then
2001 $( ERR 1 "Not allowed to create dir at \"$baksrvaddr\":\"$2\"" )
2002 exit 1
2003 fi
2004 fi
2005 if [ -f "$VMXFILEPATH" ]
2006 then
2007 #VMXFILECONTENT=$( cat "$VMXFILEPATH" )
2008 VMXFILECONTENT=$( replaceAbsolutePaths "${VMXFILECONTENT}" )
2009 TMPFILE=/tmp/"$$_${NAM}_${VMXFILENAME}"
2010 echo "$VMXFILECONTENT" > "${TMPFILE}"
2011 scp -o StrictHostKeyChecking=no -i "${PWD}"/xsibackup_id_rsa -P$baksrvport "${TMPFILE}" "$baksrvaddr":\"${2// /\ }/${VMXFILENAME}\" && echo "VMX file copied succesfully." || echo "Error copying VMX file."
2012 rm -rf "${TMPFILE}"
2013 fi
2014 if [ -f "$VMSDFILEPATH" ]
2015 then
2016 #VMSDFILECONTENT=$( cat "$VMSDFILEPATH" )
2017 VMSDFILECONTENT=$( replaceAbsolutePaths "${VMSDFILECONTENT}" )
2018 TMPFILE=/tmp/"$$_${NAM}_${VMSDFILENAME}"
2019 echo "$VMSDFILECONTENT" > "${TMPFILE}"
2020 scp -o StrictHostKeyChecking=no -i "${PWD}"/xsibackup_id_rsa -P$baksrvport "${TMPFILE}" "$baksrvaddr":\"${2// /\ }/${VMSDFILENAME}\" && echo "VMSD file copied succesfully." || echo "Error copying VMSD file."
2021 rm -rf "${TMPFILE}"
2022 fi
2023
2024 if [ -f "$VMXFFILEPATH" ]
2025 then
2026 scp -o StrictHostKeyChecking=no -i "${PWD}"/xsibackup_id_rsa -P$baksrvport "$VMXFFILEPATH" "$baksrvaddr":\"${2// /\ }\" && echo "VMXF file copied succesfully." || echo "Error copying VMXF file."
2027 fi
2028
2029 if [ -f "$NVRAMFILEPATH" ]
2030 then
2031 scp -o StrictHostKeyChecking=no -i "${PWD}"/xsibackup_id_rsa -P$baksrvport "$NVRAMFILEPATH" "$baksrvaddr":\"${2// /\ }\" && echo "NVRAM file copied succesfully." || echo "Error copying NVRAM file."
2032 fi
2033 fi
2034
2035 NOTPRES=$( grep ".present = \"FALSE\"" "$VMXFILEPATH" | grep -E "scsi|ide" | awk -F '.' '{print $1}' )
2036 if [ "$7" != "" ]
2037 then
2038 VMXFILE="$7"
2039 DOSNAPS="0"
2040 else
2041 VMXFILE=$( cat "$VMXFILEPATH" )
2042 DOSNAPS="1"
2043 fi
2044
2045 ALLVMDKVMX=$( echo "$VMXFILE" | grep -vE '^\s*(#|$)' | grep .vmdk )
2046 if [ "$ALLVMDKVMX" == "" ]
2047 then
2048 echo -e "\033[0;31mNo VMDK disks present at VM, skipping [$VMNAME], nothing to backup\033[0m"
2049 VMERRS="No VMDK disks present at VM [$VMNAME]"
2050 $( ERR 33 "No VMDK disks present at VM [$VMNAME]" )
2051 fi
2052
2053 if [ "$NOTPRES" != "" ]
2054 then
2055 for exd in $NOTPRES
2056 do
2057 ALLVMDKVMX=$( echo "$ALLVMDKVMX" | grep -v $exd )
2058 done
2059 fi
2060
2061 INDEPENDENTNUM=$( echo "$VMXFILE" | grep ".mode = \"independent-" | wc -l )
2062 INDEPENDENTDSK=$( echo "$VMXFILE" | grep ".mode = \"independent-" | awk -F "." '{print $1}' )
2063
2064 if [ "${backuphow}" != "cold" ] && [ "$6" = "ON" ]
2065 then
2066 if [ $INDEPENDENTNUM -gt 0 ]
2067 then
2068 IFS=$newline
2069 THEEXCLUSIONS2=""
2070 for inddisk in $INDEPENDENTDSK
2071 do
2072 toexclude=$( echo "$VMXFILE" | grep "$inddisk".fileName | awk -F "=" '{print $2}' | sed 's/\"//g' | sed -e 's/^ *//g' -e 's/ *$//g' )
2073 if [ "${toexclude:0:1}" == "/" ]
2074 then
2075 toexclude=$( basename "$toexclude" )
2076 fi
2077 THEEXCLUSIONS2=${toexclude}";"${THEEXCLUSIONS2}
2078 THEEXCLUSIONS2=$( echo "$THEEXCLUSIONS2" | sed 's/;$//')
2079 THEEXCLUSIONS3=${toexclude}";"${THEEXCLUSIONS3}
2080 done
2081 snapshot="excludememory,$snapshot"
2082 echo -e "\033[0;36mAt least one independent disk has been detected, excluding memory from snapshot\033[0m"
2083 echo -e "\033[0;36mThe following disks will be automatically excluded from the backup:\033[0m"
2084 echo -e "\033[1;36m${THEEXCLUSIONS2//;/\\n}\033[0m"
2085 echo -e "\033[0;36mThey are independent disks and cannot be hot backed up\033[0m"
2086 fi
2087 if [ "${snapshot//excludememory/}" != "${snapshot}" ]
2088 then
2089 echo -e "\033[1;36mMemory has been excluded from the snapshot file\033[0m"
2090 sm="0"
2091 else
2092 sm="1"
2093 fi
2094
2095 if [ "$DOSNAPS" = "1" ]
2096 then
2097 if [ "$5" = "toolsOk" ]
2098 then
2099 if [ "${snapshot//dontquiesce/}" != "$snapshot" ]
2100 then
2101 echo -e "\033[0;36mThe VM will not be quiesced by user command\033[0m"
2102 qs="0"
2103 else
2104 echo -e "\033[0;32mVMWare Tools detected, the system will be quiesced\033[0m"
2105 qs="1"
2106 fi
2107 CREATESNAP=$( ( vim-cmd vmsvc/snapshot.create $1 xsibackup "XSIBackup snapshot" $sm $qs ) 2>&1 )
2108 if [ "$CREATESNAP" != "Create Snapshot:" ]
2109 then
2110 VMERRS="$CREATESNAP"
2111 echo "$CREATESNAP">>"$errfileb"
2112 fi
2113 else
2114 echo -e "\033[1;36mVMWare tools were not detected, the system will not be quiesced to take the snapshot\033[0m"
2115 CREATESNAP=$( ( vim-cmd vmsvc/snapshot.create $1 xsibackup "XSIBackup snapshot" $sm 0 ) 2>&1 )
2116 if [ "$CREATESNAP" != "Create Snapshot:" ]
2117 then
2118 VMERRS="$CREATESNAP"
2119 echo "$CREATESNAP">>"$errfileb"
2120 fi
2121 fi
2122 fi
2123
2124 # Now lets exclude the snapshots the VM is running on when we make an IP Rsync backup
2125 if [ "$SERVERTYPE" = "NET" ]
2126 then
2127 LOCKEDDISKS=$( cat "$VMXFILEPATH" | grep -E [-][0-9]{6}.vmdk | awk -F "=" '{print $2}' | sed -e 's/^ *//g' -e 's/ *$//g' -e 's/\"//g' )
2128 IFS=$newline
2129 for lckdisk in $LOCKEDDISKS
2130 do
2131 toexclude=$( basename "$lckdisk" )
2132 delta2exclude="${toexclude//.vmdk/-delta.vmdk}"
2133 THEEXCLUSIONS2=${toexclude}";"${delta2exclude}";"${THEEXCLUSIONS2}
2134 done
2135 fi
2136
2137 fi
2138
2139 if [ "$backupprog" = "rsync" ]
2140 then
2141 VMDKLIST=ALL
2142 ALLVMDK=$( getAllFiles $1 )
2143 else
2144 if [ "$backuphow" = "cold" ] || [ "$6" = "OFF" ] || [ "$DOSNAPS" = "0" ]
2145 then
2146 VMDKLIST=VMX
2147 ALLVMDK=$ALLVMDKVMX
2148 else
2149 VMDKLIST=TOP
2150 ALLVMDK=$( getTopVmdks $1 )
2151 fi
2152 fi
2153
2154 THEEXCLUSIONS="${3};${THEEXCLUSIONS2}"
2155 THEEXCLUSIONS="$( echo "${THEEXCLUSIONS}" | sed -e 's/^;//g' -e 's/;$//g' )"
2156
2157 IFS=$newline
2158 for eachdisk in $ALLVMDK
2159 do
2160 EXCLUDEDISK=0
2161 if [ "$THEEXCLUSIONS" != "" ]
2162 then
2163 IFS=';'
2164 for exclusion in $THEEXCLUSIONS
2165 do
2166 exclstr=${exclusion//.vmdk/}
2167 matchex=$( echo "$eachdisk" | sed -e "s/${exclstr}-*[0-9]*.vmdk//" )
2168 if [ "$matchex" != "$eachdisk" ]
2169 then
2170 EXCLUDEDISK=1
2171 eachbasedisk=$( echo "$eachdisk" | awk -F "=" '{print $2}' | sed -e 's/^ *//g' -e 's/ *$//g' )
2172 echo -e "\033[1;36mDisk [$eachbasedisk] excluded\033[0m"
2173 fi
2174 done
2175 fi
2176
2177 if [ $EXCLUDEDISK -eq 0 ]
2178 then
2179
2180 IFS="="
2181 part=0
2182 for eachpart in $eachdisk
2183 do
2184 if [[ $part -eq 1 ]]
2185 then
2186 thedisk=${eachpart//\"/}
2187 thedisk=$( echo $thedisk | sed -e 's/^ *//g' -e 's/ *$//g' )
2188
2189 origin=""
2190 target=""
2191
2192 if [ ${thedisk:0:1} == "/" ]
2193 then
2194 if [ -f "$thedisk" ]
2195 then
2196 origin="$thedisk"
2197 target="$thedir"/$( basename "$thedisk" )
2198 else
2199 VMERRS="No origin disk found at: $origin for VM [$VMNAME]"
2200 $( ERR 33 "No origin disk found at: $origin" )
2201 fi
2202 else
2203 if [ -f "$VMXDir/$thedisk" ]
2204 then
2205 origin="$VMXDir/$thedisk"
2206 target="$thedir/$thedisk"
2207 else
2208 VMERRS="No origin disk found at $VMXDir/$thedisk for VM [$VMNAME]"
2209 $( ERR 33 "No origin disk found at $VMXDir/$thedisk for VM [$VMNAME]" )
2210 fi
2211 fi
2212
2213 if [ "$SERVERTYPE" = "DIR" ] && [ "$backupprog" = "vmkfstools" ]
2214 then
2215 target=$( echo "$target" | sed -r 's/[-][0-9]{6}.vmdk/.vmdk/g' )
2216 fi
2217
2218 if [ "$SERVERTYPE" = "DIR" ]
2219 then
2220 if [ -f "$origin" ]
2221 then
2222 exec 5>&1
2223 if [ "$4" = "rsync" ]
2224 then
2225 if [ -f "$target" ] && [ "$datedir" == "yes" ]
2226 then
2227 target=${target//.vmdk/_1.vmdk}
2228 fi
2229 #killRsync
2230 if [ $( isFileOpen "$origin" ) == "0" ]
2231 then
2232 RSYNCOUT=$( ("$PWD/xsibackup-rsync" -rlpDv --progress --partial "$origin" "$target" >&5) 2>&1 )
2233 if [ "$RSYNCOUT" != "" ]
2234 then
2235 VMERRS="$RSYNCOUT"
2236 echo -e "\033[0;31m${RSYNCOUT}\033[0m" >&5
2237 echo "$RSYNCOUT">>"$errfileb"
2238 fi
2239 fi
2240 # And now the eventual flat/delta files
2241 flatorigin=""
2242 flatfile=""
2243 flatfile="$(grep -ri '\-delta.vmdk\|\-flat.vmdk' "$origin" | cut -d' ' -f 4- )"
2244 if [ "$flatfile" != "" ]
2245 then
2246 flatfile="${flatfile//\"/}"
2247 vmdkfile=$( basename "$origin" )
2248 vmdkdire=${origin//"$vmdkfile"/}
2249 flatorigin="$vmdkdire""$flatfile"
2250 flattarget="$thedir"/"$flatfile"
2251 fi
2252 if [ "$flatorigin" != "" ] && [ -f "$flatorigin" ] && [ $( isFileOpen "$flatorigin" ) == "0" ]
2253 then
2254 if [ -f "$flattarget" ] && [ "$datedir" == "yes" ]
2255 then
2256 flattarget=${flattarget//.vmdk/_1.vmdk}
2257 fi
2258 if [ -f "$flattarget" ]
2259 then
2260 RSYNCOUT=$( ("$PWD/xsibackup-rsync" -rlpDv --progress "$flatorigin" "$flattarget" >&5) 2>&1 )
2261 if [ "$RSYNCOUT" != "" ]
2262 then
2263 VMERRS="$RSYNCOUT"
2264 echo -e "\033[0;31m${RSYNCOUT}\033[0m" >&5
2265 echo "$RSYNCOUT">>"$errfileb"
2266 fi
2267 else
2268 RSYNCOUT=$( ("$PWD/xsibackup-rsync" -rlpDv --progress --whole-file --sparse "$flatorigin" "$flattarget" >&5) 2>&1 )
2269 if [ "$RSYNCOUT" != "" ]
2270 then
2271 VMERRS="$RSYNCOUT"
2272 echo -e "\033[0;31m${RSYNCOUT}\033[0m" >&5
2273 echo "$RSYNCOUT">>"$errfileb"
2274 fi
2275 fi
2276 #else
2277 # $( ERR 33 "Missing file, cannot copy: $flatorigin" )
2278 fi
2279 else
2280 if [ -f "$target" ] && [ "$datedir" == "yes" ]
2281 then
2282 target=${target//.vmdk/_1.vmdk}
2283 fi
2284 if [ -f "$target" ] && [ "$datedir" != "yes" ]
2285 then
2286 REMTARGET=$( rm -rf "$target" )
2287 if [ "$REMTARGET" != "" ]
2288 then
2289 VMERRS="$REMTARGET"
2290 echo "Error removing target file: $REMTARGET">>"$errfileb"
2291 fi
2292 fi
2293 flatfile="$(grep -ri '\-delta.vmdk\|\-flat.vmdk' "$origin" | cut -d' ' -f 4- )"
2294 flatfile="${flatfile//\"/}"
2295 flattarget="$thedir"/"$flatfile"
2296 if [ -f "$flattarget" ]
2297 then
2298 REMFLATTARGET=$( rm -rf "$flattarget" )
2299 if [ "$REMFLATTARGET" != "" ]
2300 then
2301 VMERRS="$REMFLATTARGET"
2302 echo "Error removing flat target file: $REMFLATTARGET">>"$errfileb"
2303 fi
2304 fi
2305 if [ $( isFileOpen "${origin//.vmdk/-flat.vmdk}" ) == "0" ]
2306 then
2307 VMKFSTOOLSOUT=$( (vmkfstools -d thin -i "$origin" "$target" >&5) 2>&1 )
2308 if [ "$VMKFSTOOLSOUT" != "" ]
2309 then
2310 VMERRS="$VMKFSTOOLSOUT"
2311 echo -e "\033[0;31m${VMKFSTOOLSOUT}\033[0m" >&5
2312 echo "$VMKFSTOOLSOUT">>"$errfileb"
2313 fi
2314 else
2315 VMWARNS="Disk $origin at $NAM is locked by the VM. Persistent or RDM disks can only be -cold- backed up. Exclude $(basename "$origin") from the backup to skip this message."
2316 echo -e "\033[1;31mDisk $origin at $NAM is locked by the VM. Persistent or RDM disks can only be COLD backed up. Exclude $(basename "$origin") from the backup to skip this message.\033[0m" >&5
2317 echo "<span class=warn><b>WARNING:</b> disk $origin at $NAM is locked by the VM. Persistent or RDM disks can only be -cold- backed up. Exclude <b>$(basename "$origin")</b> from the backup to skip this message</span>" >>"$errfileb"
2318 fi
2319 sed -ir 's/[-][0-9]{6}.vmdk/.vmdk/g' "$thedir"/*.vmx
2320 fi
2321 exec 5>&-
2322 else
2323 VMERRS="No origin disk found at: $origin for VM [$VMNAME]"
2324 $( ERR 33 "No origin disk found at: $origin" )
2325 fi
2326
2327 elif [ "$SERVERTYPE" = "NET" ]
2328 then
2329 if [ -f "$origin" ]
2330 then
2331 if [ $( isFileOpen "$origin" ) == "0" ]
2332 then
2333 # We kill any posible remote xsibackup-rsync process
2334 KR=$( killRsync "$baksrvaddr" "$baksrvport" )
2335 echo $KR
2336 wait 1
2337
2338 LS=$(eval ssh "$SSHOPTS" -p "$baksrvport" "$baksrvaddr" exec "ls -la \"${target// /\ }\" 2>&1")
2339 if [ "${LS/No such file or directory/}" != "$LS" ]
2340 then
2341 exec 5>&1
2342 RSYNCOUT=$( ("$PWD/xsibackup-rsync" -rlpDv --progress --partial --whole-file --rsh="ssh -o StrictHostKeyChecking=no -i \"$PWD/xsibackup_id_rsa\" -p$baksrvport" --rsync-path=$baksrvdire"/xsibackup-rsync" "$origin" $REMOTEUSER@"$baksrvaddr":"${target// /\ }" >&5) 2>&1 )
2343 if [ "$RSYNCOUT" != "" ]
2344 then
2345 VMERRS="$RSYNCOUT"
2346 echo -e "\033[0;31m${RSYNCOUT}\033[0m" >&5
2347 echo "$RSYNCOUT">>"$errfileb"
2348 fi
2349 exec 5>&-
2350 else
2351 exec 5>&1
2352 RSYNCOUT=$( ("$PWD/xsibackup-rsync" -rlpDv --progress --partial --inplace --rsh="ssh -o StrictHostKeyChecking=no -i \"$PWD/xsibackup_id_rsa\" -p$baksrvport" --rsync-path=$baksrvdire"/xsibackup-rsync" "$origin" $REMOTEUSER@"$baksrvaddr":"${target// /\ }" >&5) 2>&1 )
2353 if [ "$RSYNCOUT" != "" ]
2354 then
2355 VMERRS="$RSYNCOUT"
2356 echo -e "\033[0;31m${RSYNCOUT}\033[0m" >&5
2357 echo "$RSYNCOUT">>"$errfileb"
2358 fi
2359 exec 5>&-
2360 fi
2361
2362 if [ "$backuphow" == "cold" ] && [ $( cat "$origin" | grep parentCID=ffffffff | wc -l ) -gt 0 ]
2363 then
2364 echo "Removing unused blocks, please wait..."
2365 vmkfstools -K "$origin"
2366 fi
2367
2368 flatfile="$(grep -ri '\-delta.vmdk\|\-flat.vmdk' "$origin" | cut -d' ' -f 4- )"
2369
2370 if [ "$flatfile" != "" ]
2371 then
2372
2373 vmdkdire=$( dirname "$origin" )
2374 flatfile=${flatfile//\"/}
2375 flatorigin="$vmdkdire"/"$flatfile"
2376 flattarget="$thedir"/"$flatfile"
2377
2378 if [ -f "$flatorigin" ]
2379 then
2380 if [ $( isFileOpen "$flatorigin" ) == "0" ]
2381 then
2382
2383 LS=$(eval ssh "$SSHOPTS" -p "$baksrvport" "$baksrvaddr" exec "ls -la \"${flattarget// /\ }\" 2>&1")
2384 if [ "${LS/No such file or directory/}" != "$LS" ]
2385 then
2386 exec 5>&1
2387 RSYNCOUT=$( ("$PWD/xsibackup-rsync" -rlpDv --progress --partial --whole-file --sparse --rsh="ssh -o Compression=no -o StrictHostKeyChecking=no -i \"$PWD/xsibackup_id_rsa\" -p$baksrvport" --rsync-path=$baksrvdire"/xsibackup-rsync" "$flatorigin" $REMOTEUSER@"$baksrvaddr":"${flattarget// /\ }" >&5) 2>&1 )
2388 if [ "$RSYNCOUT" != "" ]
2389 then
2390 VMERRS="$RSYNCOUT"
2391 echo -e "\033[0;31m${RSYNCOUT}\033[0m" >&5
2392 echo "$RSYNCOUT">>"$errfileb"
2393 fi
2394 exec 5>&-
2395 else
2396 FRsync=0
2397 echo "Comparing file sizes..."
2398 if [ $(compSizes "$flatorigin" "$baksrvaddr:$baksrvport:$flattarget") == "0" ]
2399 then
2400 echo -e "\033[0;36mSizes are different, calculating delta checksums, can take a while, time for a coffee...\033[0m"
2401 FRsync=1
2402 else
2403 echo -e "\033[0;36mFile sizes are equal\033[0m"
2404 echo -e "\033[0;36mComparing MD5 checksums on both files, can take from a few seconds to several minutes, depending on the sizes...\033[0m"
2405 if [ $(compHashes "$flatorigin" "$baksrvaddr:$baksrvport:$flattarget") == "0" ]
2406 then
2407 echo -e "\033[0;36mChecksums are different, calculating delta checksums, can take a while, time for a coffee...\033[0m"
2408 FRsync=1
2409 else
2410 echo -e "\033[0;32mChecksums are equal, skipping $flatorigin\033[0m"
2411 FRsync=0
2412 fi
2413 fi
2414 if [ $FRsync -eq 1 ]
2415 then
2416 exec 5>&1
2417 RSYNCOUT=$( ("$PWD/xsibackup-rsync" -rlpDv --progress --block-size=131072 --inplace --partial --rsh="ssh -T -x -o Compression=no -o StrictHostKeyChecking=no -i \"$PWD/xsibackup_id_rsa\" -p$baksrvport" --rsync-path=$baksrvdire"/xsibackup-rsync" "$flatorigin" $REMOTEUSER@"$baksrvaddr":"${flattarget// /\ }" >&5) 2>&1 )
2418 if [ "$RSYNCOUT" != "" ]
2419 then
2420 VMERRS="$RSYNCOUT"
2421 echo -e "\033[0;31m${RSYNCOUT}\033[0m" >&5
2422 echo "$RSYNCOUT">>"$errfileb"
2423 fi
2424 exec 5>&-
2425 fi
2426 fi
2427 else
2428 VMWARNS="The file \"$flatorigin\" is locked. Independent disks cannot be hot backed up, please issue a cold backup for [$VMNAME] or exlude the disk from the backup"
2429 echo -e "\033[0;31mThe file \"$flatorigin\" is locked. Independent disks cannot be hot backed up, please issue a cold backup for [$VMNAME] or exlude the disk from the backup\033[0m"
2430 $( ERR 1 "1051 - The file \"$flatorigin\" is locked. Independent disks cannot be hot backed up, please issue a cold backup for [$VMNAME] or exlude the disk from the backup" "W" )
2431 fi
2432 #else
2433 # $( ERR 1 "1051 - The file \"$flatorigin\" does not exist" )
2434 fi
2435 fi
2436 else
2437 VMWARNS="The file \"$flatorigin\" is locked. Independent disks cannot be hot backed up, please issue a cold backup for [$VMNAME] or exlude the disk from the backup"
2438 $( ERR 1 "1447 - The file \"$origin\" is locked by some process, it was not copied" "W" )
2439 fi
2440 #else
2441 # $( ERR 1 "1447 - The file \"$origin\" does not exist" )
2442 fi
2443 fi
2444 fi
2445 part=$(( $part+1 ))
2446 done
2447 IFS=$newline
2448
2449 fi
2450 done
2451
2452 # Remove excluded disks from the .vmx file
2453 if [ "$THEEXCLUSIONS" != "" ]
2454 then
2455 echo -e "\033[0;36m----------------------------------------------------\033[0m"
2456 if [ "$SERVERTYPE" = "DIR" ]
2457 then
2458 IFS=';'
2459 for exclusion in $THEEXCLUSIONS
2460 do
2461 # Remove disks
2462 exclstr=${exclusion//.vmdk/}
2463 remvmxpath=$( ls "$thedir"/*.vmx )
2464 deletewhat=$( cat "$remvmxpath" | grep -E "${exclstr}-*[0-9]*.vmdk" | awk -F "." '{print $1}' | head -n1 | sed -e 's/^ *//g' -e 's/ *$//g' )
2465 if [ "$deletewhat" != "" ]
2466 then
2467 sed -i "/$deletewhat/d" "$remvmxpath"
2468 fi
2469 done
2470 elif [ "$SERVERTYPE" = "NET" ]
2471 then
2472 TMPFILE=/tmp/"$$_${NAM}_${VMXFILENAME}"
2473 echo "$VMXFILECONTENT" > "${TMPFILE}"
2474 IFS=';'
2475 for exclusion in $THEEXCLUSIONS
2476 do
2477 exclstr=${exclusion//.vmdk/}
2478 deletewhat=$( cat "$TMPFILE" | grep -E "${exclstr}-*[0-9]*.vmdk" | awk -F "." '{print $1}' | head -n1 | sed -e 's/^ *//g' -e 's/ *$//g' )
2479 if [ "$deletewhat" != "" ]
2480 then
2481 sed -i "/$deletewhat/d" "$TMPFILE"
2482 fi
2483 done
2484 rmd=$( (scp -o StrictHostKeyChecking=no -i "${PWD}"/xsibackup_id_rsa -P$baksrvport "${TMPFILE}" "$baksrvaddr":\"${2// /\ }/${VMXFILENAME}\" ) 2>&1 )
2485 rm -rf "${TMPFILE}"
2486 if [ "$rmd" != "" ]
2487 then
2488 VMERRS="Error updating VMX file ${rmd}"
2489 echo -e "\033[0;31mError updating VMX file: ${rmd}\033[0m"
2490 echo "Error updating VMX file ${rmd}">>"$errfileb"
2491 fi
2492 fi
2493 echo -e "\033[0;36mExcluded disks removed from backup .vmx file\033[0m"
2494 fi
2495
2496 if [ "$SERVERTYPE" = "NET" ] && [ "$domigrate" == "yes" ]
2497 then
2498 REMOTEVMID=$(echo $(eval ssh "$SSHOPTS" -p "$baksrvport" "$baksrvaddr" exec "vim-cmd vmsvc/getallvms | grep \"$VMNAME\" 2>&1") | awk '{print $1}')
2499 if [ "$REMOTEVMID" != "" ]
2500 then
2501 # Check if remote VM is on
2502 if [ $( get_vm_state $REMOTEVMID "$baksrvaddr:$baksrvport" ) == "ON" ]
2503 then
2504 eval ssh "$SSHOPTS" -p "$baksrvport" "$baksrvaddr" exec "vim-cmd vmsvc/power.off $REMOTEVMID 2>&1"
2505 fi
2506 else
2507 # We must register the VM remotely
2508 REMOTEVMID=0
2509 fi
2510 fi
2511
2512 delSnapshot=$( (deleteSnapshot $1 ) 2>&1 )
2513 if [ "$delSnapshot" != "" ]
2514 then
2515 VMERRS="$delSnapshot"
2516 echo "$delSnapshot">>"$errfileb"
2517 fi
2518
2519}
2520
2521getMountedPath(){
2522
2523 OLDIFS=$IFS
2524 DIRLIST=$( ls -la /vmfs/volumes 2> /dev/null )
2525 MYPATH=$1
2526 PHYS=0
2527 IFS=$newline
2528 for line in $DIRLIST
2529 do
2530 THEPART=$( echo $line | awk '{ print $11 }' | sed 's/[ \t]\+/ /g' )
2531 THEMOUN=$( echo $line | awk '{ print $9 }' | sed 's/[ \t]\+/ /g' )
2532 THEMOUNT="/vmfs/volumes/"$THEMOUN
2533
2534 if [[ "${MYPATH//$THEPART/}" != "$MYPATH" ]]
2535 then
2536 PHYS=1
2537 echo "${MYPATH//$THEPART/$THEMOUN}"
2538 fi
2539
2540 done
2541
2542 if [ $PHYS -eq 0 ]
2543 then
2544 echo "$MYPATH"
2545 fi
2546
2547
2548 IFS=$OLDIFS
2549
2550}
2551
2552# Preparing of images for the HTML layout
2553
2554img0="<a href=\"http://33hops.com/\"><img src=\"http://33hops.com/downloads/?f=../images/logo1.gif&${SESSIONID}\" /></a>"
2555img1="<a href=\"https://twitter.com/intent/user?screen_name=xsibackup\"><img src=\"http://33hops.com/images/follow_tw.jpg\" /></a>"
2556img2="<a href=\"https://www.facebook.com/xsibackup\"><img src=\"http://33hops.com/images/follow_fb.jpg\" border=\"0\" /></a>"
2557img3="<a href=\"https://es.linkedin.com/pub/daniel-j-garc%C3%ADa-fidalgo/21/b41/55b\"><img src=\"http://33hops.com/images/follow_ln.jpg\" border=\"0\" /></a>"
2558img4="<a href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RGCHH6EJG93DL\"><img src=\"http://33hops.com/images/paypal_donate.jpg\" border=\"0\" /></a>"
2559img5="<a href=\"http://33hops.com/?xsipancar\"><img src=\"http://33hops.com/images/xsibackup_banner.jpg?${SESSIONID}\" /></a>"
2560
2561i=0
2562IFS="|"
2563for img in $imglist
2564do
2565echo "Setting custom image;link $(( $i+1 )) -> $img"
2566 imgout=$(get_img $i)
2567 if [ "$imgout" != "none" ]
2568 then
2569 imgvar="img${i}"
2570 eval $imgvar="\$(get_img $i)"
2571 else
2572 imgvar="img${i}"
2573 eval $imgvar="\ \;"
2574 fi
2575i=$(( $i + 1 ))
2576done
2577IFS=$OLDIFS
2578
2579# We define the HTML and table e-mail header
2580headHTMLStr="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n
2581 <html>\r\n"
2582
2583 stylesHTMLStr="<style type=\"text/css\">\r\n
2584
2585 body{\r\n
2586 font-size:14px;\r\n
2587 font-family:arial,helvetica;\r\n
2588 font-weight:400;\r\n
2589 color:#333333;\r\n
2590 }\r\n
2591
2592 .txthost{\r\n
2593 color:#0000AA;\r\n
2594 }\r\n
2595
2596 .errr{\r\n
2597 color:#DD0000;\r\n
2598 }\r\n
2599
2600 .warn{\r\n
2601 color:#D74700;\r\n
2602 }\r\n
2603
2604 .lok{\r\n
2605 color:#FFFFFF;\r\n
2606 background-color:#669933;\r\n
2607 font-weight:600;\r\n
2608 }\r\n
2609
2610 .lko{\r\n
2611 color:#FFFFFF;\r\n
2612 background-color:#CC3333;\r\n
2613 font-weight:600;\r\n
2614 }\r\n
2615
2616 .ok{\r\n
2617 color:#FFFFFF;\r\n
2618 background-color:#0C3300;\r\n
2619 font-weight:600;\r\n
2620 }\r\n
2621
2622 .ko{\r\n
2623 color:#FFFFFF;\r\n
2624 background-color:#A10008;\r\n
2625 font-weight:600;\r\n
2626 }\r\n
2627
2628 .report td{\r\n
2629 font-size:12px;\r\n
2630 font-family:arial,helvetica;\r\n
2631 font-weight:400;\r\n
2632 border-color:#AAAAAA;\r\n
2633 border-width: 1px 1px 1px 1px;\r\n
2634 border-top-style:dotted;\r\n
2635 border-left-style:dotted;\r\n
2636 border-right-style:solid;\r\n
2637 border-bottom-style:solid;\r\n
2638 margin:0;\r\n
2639 padding:4px;\r\n
2640 }\r\n
2641
2642 .report td.separator{\r\n
2643 border-width: 0px;\r\n
2644 }\r\n
2645
2646 .l{\r\n
2647 float: left;\r\n
2648 }\r\n
2649
2650 .r{\r\n
2651 float: right;\r\n
2652 }\r\n
2653
2654 </style>\r\n"
2655
2656 logosHTMLStr="<body>\r\n"
2657
2658 if [ "$img0" != " " ] || [ "$img2" != " " ] || [ "$img3" != " " ] || [ "$img4" != " " ]
2659 then
2660 logosHTMLStr="<table border=\"0\">\r\n
2661 <tr>\r\n
2662 <td>\r\n
2663 "$img0"
2664 </td>\r\n
2665 <td width=\"70\">\r\n
2666
2667 </td>\r\n
2668 <td>\r\n
2669 "$img1"
2670 </td>\r\n
2671 <td>\r\n
2672 "$img2"
2673 </td>\r\n
2674 <td>\r\n
2675 "$img3"
2676 </td>\r\n
2677 <td>\r\n
2678 "$img4"
2679 </td>\r\n
2680 </tr>\r\n
2681 </table>\r\n
2682 <br />\r\n"
2683 fi
2684 if [ "$img5" != "" ]
2685 then
2686 bannerHTMLStr="
2687 <table width=\"700\">\r\n
2688 <tr>\r\n
2689 <td colspan=\"8\" align=\"center\">\r\n
2690 "$img5"
2691 </td>\r\n
2692 </tr>\r\n
2693 <tr>\r\n
2694 <td colspan=\"8\" height=\"10\" class=\"error\">\r\n
2695 \r\n
2696 </td>\r\n
2697 </tr>\r\n
2698 </table>\r\n
2699 "
2700 fi
2701
2702 hostipHTMLStr="
2703 <table border=\"0\" width=\"700\">\r\n
2704 <tr>\r\n
2705 <td width=\"50%\">\r\n
2706 "$(date)"<br />\r\n
2707 <b>"$APPNAM" "$APPVER" AT HOST:<br />\r\n
2708 <span class=\"txthost\">"$HOSTNAME"</span></b><br />\r\n
2709 </td>\r\n
2710 <td width=\"50%\" align=\"right\">\r\n
2711 <b>IP v4:</b> "${HOSTIP}"/ "${HOSTMASK}"<br/>"$(vmware -v)"<br /><br />\r\n
2712 </td>\r\n
2713 </tr>\r\n
2714 "
2715 if [ "$testmode" == "true" ]
2716 then
2717 hostipHTMLStr="${hostipHTMLStr}<tr><td colspan=\"2\"><br /><span class=errr><b>TEST MODE ACTIVATED, REMOVE --test-mode=true TO MAKE A BACKUP</b></span></td></tr>\r\n"
2718 fi
2719
2720 hostipHTMLStr="${hostipHTMLStr}
2721 <tr>\r\n
2722 <td colspan=\"2\"> </td>\r\n
2723 </tr>\r\n
2724 </table>\r\n"
2725
2726 vmlistHTMLStr="<table width=\"700\" border=\"0\" class=\"report\">\r\n"
2727
2728
2729echo "Getting list of all VMs..."
2730LISTA=$( vim-cmd vmsvc/getallvms )
2731
2732i=0
2733IFS=$newline
2734for line in $LISTA
2735do
2736
2737ISVMLINE=0
2738if [ "${line/vmx-/}" != "$line" ] && [ "${line/Guest/}" != "$line" ] && [ "${line/.vmx/}" != "$line" ] && [ "${line/_XSIBAK/}" == "$line" ]
2739then
2740 ISVMLINE=1
2741fi
2742 if [[ "$i" -gt "0" ]] && [[ "$ISVMLINE" == "1" ]]
2743 then
2744 echo $line
2745
2746 VMPID=$(echo $line | awk '{ print $1 }')
2747 VMLDIR=$( getVMDir $VMPID )
2748 #VMPATH=$( getVMXDir $VMPID )
2749 VMSIZE=$( getVMSize $VMPID )
2750 VMSALL=$(($VMSALL+$VMSIZE))
2751 VMNAM=$( getVMName $VMPID )
2752 LISTA2=$LISTA2$newline"$line"
2753
2754 if [[ "$(get_vm_state $VMPID)" == "ON" ]]
2755 then
2756 LISTAON="$LISTAON"$newline"$line"
2757 VMSIZON=$(($VMSIZON+VMSIZE))
2758 else
2759 LISTAOF=$LISTAOF$newline"$line"
2760 VMSIZOF=$(($VMSIZOF+VMSIZE))
2761 fi
2762
2763 IFS=','
2764 for svm in $backupvms
2765 do
2766 IFS='!'
2767 tp=1
2768 for vmpart in $svm
2769 do
2770 if [ $tp -eq 1 ]
2771 then
2772 if [[ "$vmpart" == "$VMNAM" ]]
2773 then
2774 LISTACU=$LISTACU$newline"$line"
2775 VMSCUST=$(($VMSCUST+VMSIZE))
2776 fi
2777 fi
2778 tp=$(( $tp+1 ))
2779 done
2780 IFS=','
2781 done
2782
2783 fi
2784
2785i=$(( $i+1 ))
2786done
2787IFS=$OLDIFS
2788
2789if [[ "$backuptype" == "custom" ]]
2790then
2791 LISTA2=$LISTACU
2792 VMSALL=$VMSCUST
2793fi
2794
2795if [[ "$backuptype" == "running" ]]
2796then
2797 LISTA2=$LISTAON
2798 VMSALL=$VMSIZON
2799fi
2800
2801if [[ "$LISTA2" == "" ]]
2802then
2803 echo -e "\033[0;31mNo VMs to backup\033[0m"
2804 rm -rf "${PWD}/xsibackup-pid"
2805 exit 0
2806else
2807 echo "VMs to backup: $LISTA2"
2808fi
2809
2810if [[ "$testmode" == "true" ]]
2811then
2812 ENOUGH_ROOM=1
2813fi
2814 vmlistHTMLStr=$vmlistHTMLStr"<tr>
2815 <td colspan=\"8\">Done <b>"$backuphow"</b> backup, using <b>"$backupprog"</b>.<br />
2816 </td>
2817 </tr>\r\n"
2818
2819if [ "$datedir" == "yes" ]
2820then
2821 vmlistHTMLStr=$vmlistHTMLStr"<tr>
2822 <td colspan=\"8\">Backing up to folder <b>"$backuppoint"/"$newdirmask"</b><br />
2823 </td>
2824 </tr>\r\n"
2825fi
2826
2827if [ "$SERVERTYPE" = "DIR" ]
2828then
2829 NEEDED_ROOM=$(($VMSALL/1024))
2830 AVAILA_ROOM=$(($(avail_backup_room "$backuppoint")/1024))
2831 echo "Needed room: $NEEDED_ROOM Gb."
2832 echo "Available room: $AVAILA_ROOM Gb."
2833
2834 if [[ $(($NEEDED_ROOM+4)) -lt $AVAILA_ROOM ]]
2835 then
2836 ENOUGH_ROOM=1
2837 else
2838
2839 ENOUGH_ROOM=0
2840 echo -e "\033[0;36mNot enough room to make the backup, some older folders will be deleted\033[0m"
2841 fi
2842
2843 if [ "$backuproom" -gt 0 ]
2844 then
2845 vmlistHTMLStr=$vmlistHTMLStr"<tr>
2846 <td colspan=\"8\">The backup room has been limited to "$backuproom" Gb.<br />
2847 </td>
2848 </tr>\r\n"
2849 fi
2850
2851 vmlistHTMLStr=$vmlistHTMLStr"<tr>
2852 <td colspan=\"8\">Available room in device $backuppoint before backup: "$AVAILA_ROOM" Gb.<br />
2853 Needed room in device $backuppoint for backup: "$NEEDED_ROOM" Gb.</td>
2854 </tr>\r\n"
2855else
2856 vmlistHTMLStr=$vmlistHTMLStr"<tr>
2857 <td colspan=\"8\">Mirroring following VMs to "$backuppoint"...<br />
2858 </td>
2859 </tr>\r\n"
2860fi
2861
2862vmlistHTMLStr=$vmlistHTMLStr"<tr>\r\n
2863 <td><b>VM Name</b></td>\r\n
2864 <td><b>State</b></td>\r\n
2865 <td><b>Size</b></td>\r\n
2866 <td><b>Stop</b></td>\r\n
2867 <td><b>Copy</b></td>\r\n
2868 <td><b>Start</b></td>\r\n
2869 <td><b>Time (min)</b></td>\r\n
2870 <td><b>Speed (mb/s)</b></td>\r\n
2871 </tr>\r\n"
2872STARTALL=$(date +%s)
2873i=0
2874IFS=$newline
2875for line in $LISTA2
2876do
2877 VMERRS=""
2878 VMWARNS=""
2879 vmlistHTMLStr=$vmlistHTMLStr"<tr>\r\n"
2880 STARTVM=$(date +%s)
2881
2882 VMIDNU=`echo $line | awk '{ print $1 }'`
2883 VMNAME=$(getVMName $VMIDNU)
2884 vmlistHTMLStr=$vmlistHTMLStr"<td><b>"$VMNAME"</b></td>\r\n"
2885 VMSTAT=$(get_vm_state $VMIDNU)
2886 if [ "$VMSTAT" == "ON" ]
2887 then
2888 c="lok"
2889 else
2890 c="lko"
2891 fi
2892 vmlistHTMLStr=$vmlistHTMLStr"<td class=\""${c}"\"><b>"${VMSTAT}"</b></td>\r\n"
2893 VMSIZE=$( getVMSize $VMIDNU )
2894 vmlistHTMLStr=$vmlistHTMLStr"<td><b>"$(($VMSIZE/1024))"G</b></td>\r\n"
2895
2896 VMLOCA=$( echo $line | awk '{ print $8 }' )
2897 ETOOLS=$( getValue "vim-cmd vmsvc/get.guest $VMIDNU" "toolsStatus" )
2898 eval $ETOOLS
2899 if [[ "$backuphow" == "cold" ]]
2900 then
2901 if [[ "$VMSTAT" == "ON" ]]
2902 then
2903 #1
2904 echo "Stopping VM [$VMNAME]"
2905 if [ "$toolsStatus" == "toolsNotInstalled" ]
2906 then
2907 vim-cmd vmsvc/power.off $VMIDNU
2908 echo -e "\033[0;36mNo VMware Tools detected in VM: [$VMNAME], power-off issued\033[0m"
2909 EXITCODE="OK (Power Off)"
2910 else
2911 vim-cmd vmsvc/power.shutdown $VMIDNU
2912 fi
2913 wait2shut="30"
2914 if [ "$shutdownwait" != "" ]
2915 then
2916 wait2shut="$shutdownwait"
2917 fi
2918 sleep "${wait2shut}"
2919 echo "SLEEPING "${wait2shut}" s, waiting for VM to be off"
2920 EXITCODE="OK (Shutdown)"
2921 m=0
2922 while [ "$(get_vm_state $VMIDNU)" == "ON" ]
2923 do
2924 if [[ $m -lt 3 ]]
2925 then
2926 echo "SLEEPING 10 s, waiting for VM to be off"
2927 sleep 10
2928 EXITCODE="OK (Shutdown)"
2929 else
2930 #2
2931 if [[ $m -eq 3 ]]
2932 then
2933 vim-cmd vmsvc/power.off $VMIDNU
2934 sleep 10
2935 fi
2936 if [[ $? != 0 ]]
2937 then
2938 EXITCODE="KO (Power Off)"
2939 else
2940 EXITCODE="OK (Power Off)"
2941 fi
2942 fi
2943 m=$(($m+1))
2944 done
2945 else
2946 echo "VM [$VMNAME] was already in an Off state"
2947 EXITCODE="-"
2948 fi
2949 else
2950 if [[ "$VMSTAT" == "ON" ]]
2951 then
2952 echo -e "\033[0;36mHot backup selected for VM: ["$VMNAME"], will not be switched off\033[0m"
2953 EXITCODE="NO (hot backup)"
2954 else
2955 echo -e "\033[0;36mHot backup selected for VM: ["$VMNAME"], the VM is off though\033[0m"
2956 EXITCODE="Off yet"
2957 fi
2958 fi
2959 # EXCLUDE DISKS
2960 EXCLUDEVMDK=""
2961 IFS=','
2962 for evm in $backupvms
2963 do
2964 IFS='!'
2965 tp=1
2966 for evmpart in $evm
2967 do
2968 if [ $tp -eq 1 ]
2969 then
2970 evmname="$evmpart"
2971 fi
2972
2973 if [ $tp -eq 2 ]
2974 then
2975 if [[ "$evmname" == "$VMNAME" ]]
2976 then
2977 EXCLUDEVMDK="$evmpart"
2978 fi
2979 fi
2980 tp=$(($tp+1))
2981 done
2982 IFS=','
2983 done
2984 IFS=$newline
2985 if [ "$EXCLUDEVMDK" != "" ]
2986 then
2987 echo -e "\033[0;36mExcluding disk [$EXCLUDEVMDK] and derived files\033[0m"
2988 fi
2989
2990 vmlistHTMLStr=$vmlistHTMLStr"<td><b>"$EXITCODE"</b></td>\r\n"
2991
2992 VMOS=$( echo "$line" | awk -F "Guest" '{print $1}' | awk -F ".vmx" '{print $2}' | sed -e 's/^ *//g' -e 's/ *$//g' )
2993 QUIESCEVM="1"
2994 if [ "$VMOS" = "winLonghorn64" ]
2995 then
2996 QUIESCEVM="0"
2997 else
2998 QUIESCEVM="1"
2999 fi
3000
3001 if [[ "$testmode" != "true" ]]
3002 then
3003 VMDIRN=$( getVMDir $VMIDNU )
3004 if [ "$SERVERTYPE" = "DIR" ]
3005 then
3006 if [[ $ENOUGH_ROOM == 0 ]]
3007 then
3008 makeRoomHtml=""
3009 # Now we make room for the current backup
3010 ROOMWENEED=$(( $VMSIZE * (120/100) ))
3011 # Deprecated 120% + 12288 VMWare rule
3012 # ROOMWENEED=$(( $VMSIZE * (120/100) + 12288 ))
3013 echo "Attempting to make room at $backuppoint in local server"
3014 MAKEROOMRESP=$(make_room $ROOMWENEED "$backuppoint")
3015 if [[ "$MAKEROOMRESP" != "" ]]
3016 then
3017 makeRoomHtml="<tr>
3018 <td colspan=\"8\"><b>The eldest folders were deleted to make room:</b><br />"$MAKEROOMRESP"</td>
3019 </tr>\r\n"
3020 fi
3021 fi
3022
3023 cloneVM $VMIDNU "$backuppoint" "$EXCLUDEVMDK" "$backupprog" "$toolsStatus" "$VMSTAT"
3024
3025 elif [ "$SERVERTYPE" = "NET" ]
3026 then
3027 cloneVM $VMIDNU "$baksrvdire/$VMDIRN" "$EXCLUDEVMDK" "rsync" "$toolsStatus" "$VMSTAT"
3028 #CLONERETURN=$(cloneVM $VMIDNU "$baksrvdire/$VMDIRN")
3029 if [ $? -ne 0 ]
3030 then
3031 echo -e "\033[0;31mThe remote backup path does not exist and cannot be created\033[0m"
3032 exit 0
3033 fi
3034 else
3035 echo -e "\033[0;31mUnable to determine the type of server parsed\033[0m"
3036 exit 0
3037 fi
3038 else
3039 echo -e "\033[0;36mTest mode activated VMs will not be cloned, please remove --test-mode=true to allow backups\033[0m"
3040 fi
3041 sleep 10
3042 if [[ $? != 0 -o "$VMERRS" != "" ]]
3043 then
3044 EXITCODE="KO!"
3045 EXITCLAS="ko"
3046 else
3047 EXITCODE="OK"
3048 EXITCLAS="ok"
3049 fi
3050 vmlistHTMLStr=$vmlistHTMLStr"<td class=\""$EXITCLAS"\"><b>"$EXITCODE"</b></td>\r\n"
3051
3052 if [[ "$backuphow" == "cold" ]]
3053 then
3054 if [ "$VMSTAT" == "ON" ]
3055 then
3056
3057 #4
3058 vim-cmd vmsvc/power.on $VMIDNU
3059 if [[ $? != 0 ]]
3060 then
3061 EXITCODE="KO"
3062 else
3063 EXITCODE="OK"
3064 fi
3065 else
3066 EXITCODE="-"
3067 fi
3068 else
3069 EXITCODE="-"
3070 fi
3071 vmlistHTMLStr=$vmlistHTMLStr"<td><b>"$EXITCODE"</b></td>\r\n"
3072
3073sleep 1
3074ENDVM=$(date +%s)
3075DIFFVM=$(( $ENDVM - $STARTVM ))
3076
3077 vmlistHTMLStr=$vmlistHTMLStr"
3078 <td><b>"$(($DIFFVM/60))"</b></td>\r\n
3079 <td><b>"$(($VMSIZE/$DIFFVM))"</b></td>\r\n
3080 </tr>\r\n"$makeRoomHtml
3081 if [ "$VMERRS" != "" ]
3082 then
3083 # If we have an error in the context of the current VM we output it (only last)
3084 vmlistHTMLStr=$vmlistHTMLStr"
3085 <tr>\r\n
3086 <td colspan=\"8\"><b>Last error for the above VM:</b><br />"$VMERRS"</td>
3087 </tr>\r\n"
3088 fi
3089 # We treat warnings independently
3090 if [ "$VMWARNS" != "" ]
3091 then
3092 # If we have a warning in the context of the current VM we output it (only last)
3093 vmlistHTMLStr=$vmlistHTMLStr"
3094 <tr>\r\n
3095 <td colspan=\"8\" class=\"warn\"><b>Last warning for the above VM:</b><br />"$VMWARNS"</td>\r\n
3096 </tr>\r\n"
3097 fi
3098i=$(( $i + 1 ))
3099done
3100IFS=$OLDIFS
3101
3102ENDALL=$(date +%s)
3103DIFFALL=$(( $ENDALL - $STARTALL ))
3104
3105 if [ "$SERVERTYPE" = "DIR" ]
3106 then
3107 AVAILA_ROOM=$(( $(avail_backup_room $backuppoint)/1024 ))
3108 vmlistHTMLStr=$vmlistHTMLStr"<tr>
3109 <td colspan=\"8\">Available space in device $backuppoint after backup: "$AVAILA_ROOM" Gb.</td>
3110 </tr>\r\n"
3111 fi
3112 vmlistHTMLStr=$vmlistHTMLStr"<tr>
3113 <td colspan=\"8\">Complete backup elapsed time: "$(($DIFFALL/60))" min</td>
3114 </tr>\r\n"
3115
3116 if [ "$testmode" != "true" ]
3117 then
3118 if [ "$debuginfo" == "yes" ]
3119 then
3120 echo -e "\033[0;32mAdding debug information to the report\033[0m"
3121 vmlistHTMLStr=$vmlistHTMLStr"
3122 <tr>\r\n
3123 <td colspan=\"8\"><b>DEBUG INFORMATION:</b><br />$DEBUGINFO</td>\r\n
3124 </tr>\r\n"
3125 fi
3126 # End of testmode check
3127 fi
3128
3129 IFS=","
3130 for email in $mailto
3131 do
3132 if [ ! $(echo "${email}" | grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b") ]
3133 then
3134 echo -e "\033[0;31m[${email}] excluded from the e-mail recipient list, not evaluable as an e-mail address\033[0m"
3135 $( ERR 2188 "<b>${email}</b> excluded from the e-mail recipient list, not evaluable as an e-mail address" "W" )
3136 fi
3137 done
3138 IFS=$OLDIFS
3139
3140 ERR_FILE_SIZE=$( ls -la "${errfileb}" | awk '{print $5}' )
3141 cmd64=$( echo $@ | openssl base64 2>/dev/null )
3142
3143 if [ "$ERR_FILE_SIZE" != "0" ]
3144 then
3145 echo -e "\033[0;31mErrors detected in backup, check logs\033[0m"
3146 cat "${errfileb}"
3147 ERR_STR=$( cat "${errfileb}" | grep -v "WARNING" | sed -e 's/^ *//g' -e 's/ *$//g' | sort -u )
3148 WRN_STR=$( cat "${errfileb}" | grep "WARNING" | sed -e 's/^ *//g' -e 's/ *$//g' | sort -u )
3149 errstr64=$( echo "$ERR_STR" | openssl base64 2>/dev/null )
3150
3151 if [ "$ERR_STR" != "" ] || [ "$WRN_STR" != "" ]
3152 then
3153 THERESERR=1
3154 if [ "$ERR_STR" != "" ]
3155 then
3156 vmlistHTMLStr=$vmlistHTMLStr"
3157 <tr>\r\n
3158 <td colspan=\"8\">• ${ERR_STR//$newline/<br>• }</td>\r\n
3159 </tr>\r\n"
3160 fi
3161 if [ "$WRN_STR" != "" ]
3162 then
3163 vmlistHTMLStr=$vmlistHTMLStr"
3164 <tr>\r\n
3165 <td colspan=\"8\">• ${WRN_STR//$newline/<br>• }</td>\r\n
3166 </tr>\r\n"
3167 fi
3168 fi
3169 else
3170 echo -e "\033[0;32mNo errors detected in backup\033[0m"
3171 fi
3172 rm -rf "$errfileb"
3173
3174
3175vmlistHTMLStr=$vmlistHTMLStr"</table>\r\n"
3176
3177emailHTMLStr=${headHTMLStr}${stylesHTMLStr}${logosHTMLStr}${bannerHTMLStr}${hostipHTMLStr}${vmlistHTMLStr}"<br /><br />"${smartinfo}
3178
3179# We write the footer of the e-mail
3180emailHTMLStr=$emailHTMLStr"\r\n</body>\r\n</html>"
3181
3182# We send the e-mail
3183if [[ $SEND_EMAIL == 1 ]]
3184then
3185 IFS=","
3186 em=0
3187 for email in $mailto
3188 do
3189 if [ $(echo "${email}" | grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b") ]
3190 then
3191 recipient="$email"
3192 break
3193 fi
3194 em=$(( $em+1 ))
3195 done
3196 IFS=$OLDIFS
3197 err_exit() { echo -e 1>&2; exit 1; }
3198 mail_input() {
3199 if [ "${smtpsrv//gmail/}" != "${smtpsrv}" ]
3200 then
3201 nl="\n"
3202 delay="2"
3203 smtpport="465"
3204 else
3205 if [ $smtpdelay -gt 0 -a $smtpdelay -lt 4 ]
3206 then
3207 nl="\r\n"
3208 delay="$smtpdelay"
3209 else
3210 nl="\r\n"
3211 delay="0"
3212 fi
3213 fi
3214 sleep 2
3215 echo -ne "helo ${HOSTNAME}${nl}"
3216 sleep ${delay}
3217 echo -ne "ehlo ${HOSTNAME}${nl}"
3218 sleep ${delay}
3219 if [ "$smtpauth" != "none" ]
3220 then
3221 echo -ne "AUTH LOGIN${nl}"
3222 sleep ${delay}
3223 if [ "${smtpsrv//gmail/}" != "${smtpsrv}" ]
3224 then
3225 echo -ne "$( echo $smtpusr | openssl base64 2>/dev/null )${nl}"
3226 sleep ${delay}
3227 echo -ne "$( echo $smtppwd | openssl base64 2>/dev/null )${nl}"
3228 else
3229 echo -ne "$( base64_encode $smtpusr )${nl}"
3230 sleep ${delay}
3231 echo -ne "$( base64_encode $smtppwd )${nl}"
3232 fi
3233 sleep ${delay}
3234 fi
3235 echo -ne "MAIL FROM: <${mailfrom}>${nl}"
3236 sleep ${delay}
3237 IFS=","
3238 for email in $mailto
3239 do
3240 if [ $(echo "${email}" | grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b") ]
3241 then
3242 echo -ne "RCPT TO: <${email}>${nl}"
3243 sleep ${delay}
3244 fi
3245 done
3246 IFS=$OLDIFS
3247 echo -ne "DATA${nl}"
3248 sleep ${delay}
3249 echo -ne "SUBJECT: ${subject}${nl}"
3250 sleep ${delay}
3251 echo -ne "TO: <${recipient}>${nl}"
3252 sleep ${delay}
3253 echo -ne "Content-type: text/html${nl}"
3254 sleep ${delay}
3255 echo -ne "MIME-Version: 1.0${nl}"
3256 sleep ${delay}
3257 echo -ne "From: <${mailfrom}>${nl}"
3258 sleep ${delay}
3259 echo -ne "Date: $(date -R)${nl}"
3260 sleep ${delay}
3261 echo -ne "${nl}"
3262 echo -ne $emailHTMLStr"${nl}"
3263 sleep ${delay}
3264 if [ -z "$smtpdelay" ]
3265 then
3266 smtpdelay=0
3267 fi
3268 if [ $smtpdelay -gt 0 -a $smtpdelay -lt 4 ]
3269 then
3270 sleep $smtpdelay
3271 fi
3272 echo -ne ".${nl}"
3273 sleep ${delay}
3274 if [ $smtpdelay -gt 0 -a $smtpdelay -lt 4 ]
3275 then
3276 sleep $smtpdelay
3277 fi
3278 echo -ne "quit${nl}"
3279 }
3280
3281 FWRESPONSE=$( openFirewall "$smtpport" "SMTPout-$smtpport" "9999" "0000" "tcp" )
3282
3283 sleep 2
3284 echo $FWRESPONSE
3285
3286 FWRESPONSE=$( esxcli network firewall ruleset set --ruleset-id=SMTPout-$smtpport --enabled=true )
3287 if [ "$FWRESPONSE" != "" ]
3288 then
3289 echo "$FWRESPONSE"
3290 fi
3291
3292 FWRESPONSE=$( esxcli network firewall refresh )
3293 if [ "$FWRESPONSE" != "" ]
3294 then
3295 echo "$FWRESPONSE"
3296 fi
3297
3298 if [ "${smtpsrv//gmail/}" != "${smtpsrv}" ]
3299 then
3300 exec 5>&1
3301 SRVSTATUS=$( echo "EHLO ${HOSTNAME}" | nc ${smtpsrv} ${smtpport} -w 7 2>/dev/null | sed -e 's/^ *//g' -e 's/ *$//g' )
3302 if [ ${#SRVSTATUS} -eq 0 ]
3303 then
3304 echo -e "\033[0;31mGMail Module ::: The e-mail server [${smtpsrv}] is not reachable at port [${smtpport}]\033[0m"
3305 else
3306 MAILOUT=$( (mail_input | openssl s_client -pause -connect ${smtpsrv}:${smtpport} -ign_eof -crlf >&5) 2>/dev/null )
3307 if [ "$MAILOUT" != "" ]
3308 then
3309 IFS=$newline
3310 for mo in $MAILOUT
3311 do
3312 if [ "${mo//openssl.cnf/}" = "${mo}" ] && [ "${mo//self signed certificate in certificate chain/}" = "${mo}" ]
3313 then
3314 echo "$mo"
3315 fi
3316 done
3317 IFS=$OLDIFS
3318 fi
3319 fi
3320 exec 5>&-
3321 elif [ "$smtpsec" = "tls" ]
3322 then
3323 exec 5>&1
3324 SRVSTATUS=$( echo "EHLO ${HOSTNAME}" | nc ${smtpsrv} ${smtpport} -w 7 2>/dev/null | sed -e 's/^ *//g' -e 's/ *$//g' )
3325 if [ "${SRVSTATUS:0:3}" != "220" ]
3326 then
3327 echo -e "\033[0;31mTLS Module ::: The e-mail server [${smtpsrv}] is not reachable at port [${smtpport}]\033[0m"
3328 else
3329 MAILOUT=$( (mail_input | openssl s_client -starttls smtp -connect ${smtpsrv}:${smtpport} -ign_eof >&5) 2>&1 )
3330 if [ "$MAILOUT" != "" ]
3331 then
3332 IFS=$newline
3333 for mo in $MAILOUT
3334 do
3335 if [ "${mo//openssl.cnf/}" = "${mo}" ] && [ "${mo//self signed certificate in certificate chain/}" = "${mo}" ]
3336 then
3337 echo "$mo"
3338 fi
3339 done
3340 IFS=$OLDIFS
3341 fi
3342 fi
3343 exec 5>&-
3344 else
3345 exec 5>&1
3346 SRVSTATUS=$( echo "EHLO ${HOSTNAME}" | nc ${smtpsrv} ${smtpport} -w 7 2>/dev/null | sed -e 's/^ *//g' -e 's/ *$//g' )
3347 if [ "${SRVSTATUS:0:3}" != "220" ]
3348 then
3349 echo -e "\033[0;31mPlain SMTP Module ::: The e-mail server [${smtpsrv}] is not reachable at port [${smtpport}]\033[0m"
3350 else
3351 MAILOUT=$( (mail_input | nc $smtpsrv $smtpport -w 7 || err_exit >&5) 2>&1 )
3352 if [ "$MAILOUT" != "" ]
3353 then
3354 IFS=$newline
3355 for mo in $MAILOUT
3356 do
3357 if [ "${mo//openssl.cnf/}" = "${mo}" ] && [ "${mo//self signed certificate in certificate chain/}" = "${mo}" ]
3358 then
3359 echo "$mo"
3360 fi
3361 done
3362 IFS=$OLDIFS
3363 fi
3364 fi
3365 exec 5>&-
3366 fi
3367
3368 # We close the SMTP port
3369 esxcli network firewall ruleset set --ruleset-id=SMTPout-$smtpport --enabled=false
3370 echo "Firewall rule SMTPout-$smtpport closed."
3371fi
3372
3373echo -e "\033[0;32mBackup finished\033[0m"
3374if [ ${#next} -gt 0 ]
3375then
3376 echo -e "\033[0;36mExecuting next chained backup ID($backupId)\033[0m"
3377 eval $next >> "${PWD}/xsibackup-cron.log"
3378else
3379 echo -e "\033[0;36mNo chained backups scheduled, set --on-success and/or --on-error arguments to chain a backup\033[0m"
3380 echo -e "\033[0;36mGet XSIBACKUP-PRO at http://33hops.com to chain backups.\033[0m"
3381fi
3382xsib_shutdown