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