View unanswered posts | View active topics It is currently Sat Sep 22, 2018 6:31 pm



Reply to topic  [ 1 post ] 
 Poor man's VM Replication for Esxi 
Author Message

Joined: Thu Feb 25, 2010 1:08 am
Posts: 12
Reply with quote
 Poor man's VM Replication for Esxi
After my NFS binary for ESXi 4 (viewtopic.php?f=16&t=2280), I needed light VM Replication. I didn't find it on the Internet, so with the exemple of the ghettoVCB script, I made it myself.

Here it is ! In use since 1 week on ESXi 4 and 5, try it and don't hesitate to reply if you got ideas or comments :-)
Code:
# Fxmx86 10/12/2012
# Ce script permet de repliquer régulièrement une VM, via  un cache disk, vers un autre disk sur NFS distant (les autres disks sont independants)
# A voir : Lancement depuis rc.local avec un autostart.sh : Parcours des VMs et lancement auto si Cache existe.
# Mise en place sans arrêt de la VM :  http://www.peetersonline.nl/2009/08/set-vmware-snapshot-location-with-powershell/
# pas de stop sinon il faut refaire la copie initiale.
# Attention, les snapshots mettent la VM en courte pause, il faut donc la tenir à l'heure s'ils ont lieu très souvent.
# Copie locale pour eviter dépendance NasAdmin (idem replicate)
# Envoi de mail au bout d'une demi-heure de pb numsnapshot


PrintUsage() {
   echo "syntaxe de `basename $0` :"
   echo "Usage : `basename $0` VM_NAME [start|pause|log|init|testCopy]"
   exit
}

VerifNumSnapshot() {
   # Attente 30 min si pb dans le nb de snapshot puis envoi d'un mail d'avertissement et sortie
   i=0; while [ $i -lt 180 -a -f $VMX_DIR/Copy.conf ] && ! grep -q "numSnapshots = \"$1\"" $Vmsd; do
      busybox sleep 10; i=$((i+1)); [ $((i%6)) -eq 0 ] && echo "Error : 1 min - Pb dans le nb de snapshot, pause de la replication"; done
   grep -q "numSnapshots = \"$1\"" $Vmsd || { echo "Envoi d'un mail d'avertissement et sortie"; exit; }

   # Rotate Log
   ls $PathCache/*99.vmsn >/dev/null 2>&1 && {
      cat $PathCopy/CopyDisks.log > $PathCopy/CopyDisks.oldlog 2>&1
      echo > $PathCopy/CopyDisks.log
   }
}

CreateSnapshotVMs() {
   cp $VMX_PATH $PathCopy/temp.vmx; cp $Vmsd $PathCopy/temp.vmsd

   vim-cmd vmsvc/snapshot.create $VM_ID "$1" "$1" 0 1; echo; sleep 10

   { touch $PathCache/busy; cp $PathCache/*.vmdk $PathCacheCopy/ 2>/dev/null
      rm $PathCache/busy; } &

   # Arret d'un possible autre process en cours
   mv $VMX_DIR/Copy.conf $VMX_DIR/Copy-off.conf; sleep 15; mv $VMX_DIR/Copy-off.conf $VMX_DIR/Copy.conf

   # Attente Timer et fin de la copie
   i=0; while [ -f $VMX_DIR/Copy.conf ]; do busybox sleep 10; i=$((i+1))
      [ "$i" -ge $Timer -a ! -f $PathCache/busy ] && break; done
}

FormatFileVMxx() {
   # Mise en forme des fichiers de VMCopy avant Remove Snapshot
   mv $PathCopy/temp.vmsd $PathCopy/`basename $Vmsd`; cp $PathCache/*.vmsn $PathCacheCopy/
   sed -i 's/displayName = "'$1'"/displayName = "'$1'-Copy"/' $PathCopy/temp.vmx > /dev/null 2>&1
   sed -i '/sched.swap.derivedName/d' $PathCopy/temp.vmx > /dev/null 2>&1
   sed -i 's/workingDir = .*//' $PathCopy/temp.vmx
   echo "workingDir = \"$PathCacheCopy\"" >> $PathCopy/temp.vmx
   mv $PathCopy/temp.vmx $PathCopy/`basename $VMX_PATH`
}

RemoveSnapshotVMs() {
   # Attente dispo du disque parent sinon arret brutal de la VM en cas de coupure NFS
   touch $PathCache/busy; while ! ls $VMX_DIR/$DiskParent >/dev/null 2>&1; do
      echo Attente Disk Parent; busybox sleep 10; done

   tail -n 0 -f /var/log/messages > $PathCache/busy &
   TAIL_PID2=$!; vim-cmd vmsvc/snapshot.remove $VM_ID "$1"; echo

   # Attente du log "remove snapshot" sur la VM ou 30 min max
   # Exemple log ESXi V4 :  Dec 17 15:51:15 Hostd: [2012-12-17 15:51:15.037 56DF0B90 verbose 'vm:/vmfs/volumes/4e7b120d-07b508a0
   # -e8d5-002590512617/VM7-SandBox/New7.vmx'] Done disk consolidation after removing snapshots.

   i=0; while [ $i -lt 180 ] && ! grep "removing snapshot" $PathCache/busy | grep -q $VMX_CONF; do
      busybox sleep 10; i=$((i+1)); [ $((i%6)) -eq 0 ] && echo "1 min"; done
   kill -9 $TAIL_PID2; rm $PathCache/busy

   # Modif path dans copies vmdk
   for i in $PathCacheCopy/*.vmdk; do echo $i | grep -q delta.vmdk || {
      sed -i 's/\(parentFileNameHint=.*\/\)/\1Copy\//' $i; }; done
   vim-cmd vmsvc/reload $VM_IDCopy
   tail -n 0 -f /var/log/messages > $PathCache/busy &
   TAIL_PID2=$!; vim-cmd vmsvc/snapshot.remove $VM_IDCopy "$1"; echo

   # Attente du log "remove snapshot" sur la VM Copy ou 30 min max
   i=0; while [ $i -lt 180 ] && ! grep "removing snapshot" $PathCache/busy | grep -q "`basename $PathCopy`/`basename $VMX_CONF`"; do
         busybox sleep 10; i=$((i+1)); [ $((i%6)) -eq 0 ] && echo "1 min"; done
   kill -9 $TAIL_PID2; rm $PathCache/busy
   sed -i 's/workingDir = .*//' $PathCopy/`basename $VMX_PATH`
}

. /bootbank/Parametres.sh

# Initialisation
[ -z "$1" ] && PrintUsage || . InfoVM.sh $1 quiet
[ -z "$VM_ID" ] && { echo "Error : La VM $1 n'a pas ete trouvee"; exit; }

[ "$2" == "start" -o -z "$2" ] && mv $VMX_DIR/Copy-off.conf $VMX_DIR/Copy.conf 2>/dev/null && echo "La replication va maintenant (re)démarrer"
[ "$2" == "pause" ] && {
   [ -f $VMX_DIR/Copy.conf ] && . $VMX_DIR/Copy.conf
   while [ -f $PathCache/busy ]; do echo "La replication ne peut pas s'arreter maintenant, il faut patienter..."; busybox sleep 10; done
   mv $VMX_DIR/Copy.conf $VMX_DIR/Copy-off.conf 2>/dev/null && echo "La replication va s'arreter d'ici 15s maximum mais le snapshot va continuer de grossir" ||
   echo "Error : La replication ne semble pas en fonctionnement"; exit
}
[ "$2" == "testCopy" ] && {
   echo; echo "explications et interaction :"; read ans
   echo; echo "attente plus de cache sur la copie et pause :" read ans
   $0 $1 pause
   echo; echo "Creation d'un snapshot pour conserver la copie initale :" read ans
   echo; echo "reload et infos déconnexion réseau :" read ans
   echo; echo "démarrage local ou distant et vérification :" read ans
   echo; echo "arrêt (brutal) local ou distant et suppression du snapshot :" read ans
   echo; echo "Retour à la normale :" read ans
}
[ "$2" == "log" ] && {
   [ -f $VMX_DIR/Copy.conf ] && . $VMX_DIR/Copy.conf || . $VMX_DIR/Copy-off.conf
   less $PathCopy/CopyDisks.log; exit
}

# Initialisation/Recuperation des parametres
Vmsd=$VMX_DIR/*.vmsd
[ -f $VMX_DIR/Copy.conf ] && . $VMX_DIR/Copy.conf
[ ! -f $VMX_DIR/Copy.conf ] || [ "$2" == "init" ] && {
   [ -z "$2" -o "$2" == "start" -o "$2" == "testCopy" -o "$2" == "pause" -o "$2" == "log" ] && { echo "Error : Il faut d'abord faire la configuration initiale"; exit; }
   [ -f $VMX_DIR/Copy.conf ] && { echo "Un parametrage a deja ete effectue. CTL+C pour arreter ou entree pour continuer"; read ans; }
   [ $(vim-cmd vmsvc/snapshot.get ${VM_ID} | wc -l) -eq 1 ] || { echo "Error : Pas de replication possible, la VM a deja un snapshot"; exit; }

   echo; echo "Saisir le repertoire qui va recevoir la copie de la VM :"; read ans
   [ -n "$ans" ] && PathCopy=$ans || { echo "Error : Parametre invalide"; exit; }
   rm -r $ans/* $VMX_DIR/Copy > /dev/null 2>&1; mkdir -p $ans || { echo "Error : Parametre invalide"; exit; }
   ln -sf $PathCopy $VMX_DIR/Copy

   echo; echo "Saisir le repertoire qui va recevoir les caches :"; read ans
   [ -n "$ans" ] && PathCache=$ans && PathCacheCopy=$ans/Copy || { echo "Error : Parametre invalide"; exit; }
   rm -r $ans/* $VMX_DIR/Cache > /dev/null 2>&1; mkdir -p $ans/Copy || { echo "Error : Parametre invalide"; exit; }
   ln -sf $PathCache $VMX_DIR/Cache

   echo; echo "Saisir le timer en minute (defaut = 60 min) :"; read ans
   [ -n "$ans" ] && Timer=$ans || Timer=60

   cat $PathCopy/CopyDisks.log > $PathCopy/CopyDisks.oldlog 2>&1
   echo > $PathCopy/CopyDisks.log
   rm $Vmsd
   echo State=Initial > $VMX_DIR/Copy.conf
   echo PathCache=$PathCache >> $VMX_DIR/Copy.conf
   echo PathCacheCopy=$PathCache/Copy >> $VMX_DIR/Copy.conf
   echo PathCopy=$PathCopy >> $VMX_DIR/Copy.conf
   echo Timer=$Timer >> $VMX_DIR/Copy.conf
   chmod 755 $VMX_DIR/Copy.conf
}

# Verifications
[ -d $VMX_DIR/Cache/Copy ] || { echo "Error : Il n'y a pas de repertoire cache"; exit; }
[ -d $VMX_DIR/Copy ] || { echo "Error : Il n'y a pas de repertoire cache"; exit; }
[ -z $Timer ] && Timer=60
Timer=$((Timer*6))
# dont parametrage Path workingDir
grep -q "workingDir = \"$PathCache\"" $VMX_PATH && ls $PathCache/*.vswp  > /dev/null 2>&1 || {
   sed -i 's/workingDir = .*//' $VMX_PATH
   echo "workingDir = \"$PathCache\"" >> $VMX_PATH
   sed -i 's/snapshot.redoNotWithParent = .*//' $VMX_PATH
   echo "snapshot.redoNotWithParent = \"true\"" >> $VMX_PATH
   vim-cmd vmsvc/reload $VM_ID
   echo "Error : La configuration du cache nécessite d'arrêter et redémarrer la VM"; exit
}

# Init de l'affichage des logs
kill -9 `ps -c | grep "tail -n 0 -f $PathCopy/CopyDisks.log" | awk '{print $1}'` >/dev/null 2>&1

# Boucle principale en background
while [ -f $VMX_DIR/Copy.conf ]; do

# Affichage des logs
tail -n 0 -f $PathCopy/CopyDisks.log &
TAIL_PID=$!; {

while ! vim-cmd vmsvc/power.getstate $VM_ID | grep -q "Powered on"; do
   echo "Attente VM start 60s"; busybox sleep 60; done

grep -q State=Initial $VMX_DIR/Copy.conf 2>/dev/null && {
   echo "Copie initiale apres creation du Snapshot initial Cut1"; date
   cp $VMX_PATH $PathCopy
   sed -i 's/displayName = "'$1'"/displayName = "'$1'-Copy"/' $PathCopy/`basename $VMX_PATH` > /dev/null 2>&1
   sed -i '/sched.swap.derivedName/d' $PathCopy/`basename $VMX_PATH` > /dev/null 2>&1
   vim-cmd vmsvc/snapshot.create $VM_ID "Cut1" "Cut1" 0 1; echo; sleep 10

   ls $PathCache/*.vmdk  > /dev/null 2>&1 || { echo "Error : Il n'y a pas de disque non independant"; exit; }
   for i in $PathCache/*.vmdk; do echo $i | grep -q delta.vmdk || {
      i=`awk -F "=" '/parentFileNameHint/ {print $2}' $i | sed 's/\"//g'`
      DiskParent=`basename $i`; vmkfstools -d thin -i $i $PathCopy/$DiskParent
      }
   done
   vim-cmd solo/registervm $PathCopy/*.vmx > /dev/null 2>&1
   . InfoVM.sh $1"-Copy" quiet; VM_IDCopy=$VM_ID; . InfoVM.sh $1 quiet
   echo VM_IDCopy=$VM_IDCopy >> $VMX_DIR/Copy.conf
   echo DiskParent=$DiskParent >> $VMX_DIR/Copy.conf

   sed -i 's/State=.*/State=SrcCut1-CopyCut1/' $VMX_DIR/Copy.conf
}

grep -q State=SrcCut1-CopyCut1 $VMX_DIR/Copy.conf 2>/dev/null && {
   # Verif correspondance CID
   [ `grep ^CID $VMX_DIR/$DiskParent` == `grep ^CID $PathCopy/$DiskParent` ] ||
      { echo "Error : La replication est alteree, vous devez reinitialiser";
      mv $VMX_DIR/Copy.conf $VMX_DIR/Copy-hs.conf; exit; }

   VerifNumSnapshot 1

   echo Creation-Transfert Tranche 1 puis Attente; date
   sed -i 's/State=.*/State=SrcCut2-CopyCut1/' $VMX_DIR/Copy.conf
   CreateSnapshotVMs Cut2
}

grep -q State=SrcCut2-CopyCut1 $VMX_DIR/Copy.conf 2>/dev/null && {
   VerifNumSnapshot 2

   echo Integration Tranche 1; date
   FormatFileVMxx $1
   sed -i 's/State=.*/State=SrcCut2-CopyCut2/' $VMX_DIR/Copy.conf
   RemoveSnapshotVMs Cut1
}

grep -q State=SrcCut2-CopyCut2 $VMX_DIR/Copy.conf 2>/dev/null && {
   VerifNumSnapshot 1

   echo Creation-Transfert Tranche 2 puis Attente; date
   sed -i 's/State=.*/State=SrcCut1-CopyCut2/' $VMX_DIR/Copy.conf
   CreateSnapshotVMs Cut1
}

grep -q State=SrcCut1-CopyCut2 $VMX_DIR/Copy.conf 2>/dev/null && {
   VerifNumSnapshot 2

   echo Integration Tranche 2; date
   FormatFileVMxx $1
   sed -i 's/State=.*/State=SrcCut1-CopyCut1/' $VMX_DIR/Copy.conf
   RemoveSnapshotVMs Cut2
}

} >> $PathCopy/CopyDisks.log 2>&1
kill "${TAIL_PID}" 2>/dev/null

done &
exit


## Replication avec Raid distant d'un disk :
#1 Go écrit sur VM =
#1 Go écrit sur VM avec Raid distant = 1 Go écrit (HDD1) et 1 Go écrit (Nas)

## Replication avec Raid distant et cache snapshot du disk distant :
#1 Go écrit sur VM =
#1 Go ecrit (HDD1) et 1 Go écrit (SSD1) dans le snapshot
#1 Go lu (SSD1) et 1 Go écrit (Nas) pour consolidation
#Donc 1 Go écrit = 1 Go écrit sur HDD1
#          2 Go lu et écrit sur SSD1 et 1 Go écrit sur Nas
# Gain perf CacheDisks (non SSD) sur disk NFS : Lecture de 2 Go passe de 15s a 6s, Ecriture de 320s a 18s !!!
# Pb : les accés en lecture sur Nas concurrencent ceux en écriture d'où latences. Il faudrait n'autoriser que l'écriture.

## Replication complete de la VM avec snapshot sur SSD :
#(pré-requis : L'avant-dernier snapshot doit être consolidé sur le disk parent, pour éviter toute perte de données)
#1 Go écrit sur VM =
#1 Go ecrit (SSD1) dans le snapshot
#1 Go lu (SSD1) et 1 Go écrit (SSD2) pour copie vers réplication
#1 Go lu (SSD1) et 1 Go écrit (HDD1) pour consolidation VM 1
#1 Go lu (SSD2) et 1 Go écrit (HDD2) pour consolidation VM 2
# Donc 1 Go écrit = 3 Go lu et écrit sur SSD1 et 1 Go sur HDD1
#           2 Go lu et écrit sur SSD2 et 1 Go sur HDD2
# En fait, avec le cache Linux, la plupart des lectures doivent se faire en mémoire.


Sun Dec 30, 2012 11:34 am
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 1 post ] 

Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by STSoftware for PTF.