Script de sauvegarde esx-esxi Ce script sauvegarde une VM, passée en argument. Il se connecte en SSH sur le serveur ESX et utilise les commandes internes de VMware ESX. La sauvegarde est envoyée via RSync vers un serveur de stockage. Scénario: Sur le réseau, nous avons un serveur ESXi avec la licence gratuite et un serveur de stockage avec un daemon RSYNC opérationnel. Le script peut être copié sur le serveur de stockage ou sur tout autre serveur. Ce serveur devra disposer de Perl avec toutes ces dépendances. Sur le serveur de stockage, il faudra installer le daemon RSync et de configurer un partage nommé backup. Le transfert se fera uniquement en rsync. Installation serveur rsync : Pour autoriser rsync à se lancer, il faut éditer le fichier /etc/default/rsync via la commande : sudo nano /etc/default/rsync //Modifier la ligne RSYNC à true RSYNC_ENABLE=true Pour configurer rsync, on crée le fichier de configuration de rsync en éditant le fichier /etc/rsyncd.conf via la commande : sudo nano /etc/rsyncd.conf //En entête de ce fichier, il faut copier les lignes suivantes : uid = root gid = root Dans ce fichier, on introduit les informations concernant les modules. Un module est une sorte de partage rsync. Dans notre cas, on va créer un module nommé share_rsync. [nompartagersync] path = /cheminrepertoiredesauvegarde comment = Synchro fichiers internes read only = false Attribuer le répertoire de sauvegarde à rsync : sudo chown -R root:root /cheminrepertoiredesauvegarde Attribuer les droits adéquats au répertoire de sauvegarde : sudo chmod -R 777 /cheminrepertoiredesauvegarde Pour terminer, lancer rsync sans redémarrage avec la commande : sudo /etc/init.d/rsync start Mise en place du client rsync et script de sauvegarde : Sur le serveur ESX, il faut activer l'accès SSH. Comme il n'est pas possible d'installer le client Rsync sur un serveur ESXi, il faut copier le binaire Rsync sur le serveur. Mais une version dont les bibliothèques (librairies) sont intégrées au binaire. Récupération du binaire sur esxi :
wget http://pegasus45.free.fr/images/f/f2/rsync-static.gz gunzip Rsync-static.gz -C cp Rsync-static /bin/rsync-static Installation des librairie perl sur le serveur rsync : cpan install Net::OpenSSH install Time::HiRes //doc officiel : http://search.cpan.org/~salva/net-openssh-0.52/lib/net/openssh.pm Autorisation de connexion SSH pour le serveur esxi : ssh-keyscan -t rsa,dsa adresseipserveuresxi nano /root/.ssh/known_hosts //Coller le résultat de la commande précedente dans le fichier Créer le script de sauvegarde backup-snapshot.pl : #!/usr/bin/perl -w use strict; use Net::OpenSSH; use Time::HiRes qw (time alarm sleep); # Declaration des variables par les arguments passer my $VMName = $ARGV[0]; my $HOST_ESX = $ARGV[1]; my $username = $ARGV[2]; my $password = $ARGV[3]; my $HOST_RSYNC = $ARGV[4]; my $fichiertxtlog =$ARGV[5]; my $timeshutdown = 2; my $fichiertxttemp = "/tmp/".$argv[0]; my $cmd; my $ssh; my $stdout; my $VMID; my $numargs = $#ARGV + 1; my $keyword = "Powered off"; # Creer le fichier log si il n'existe pas system("touch $fichiertxtlog");
# Recuperation de la date du jour et formatage my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); my $datefr = $mday."/".($mon+1). /.(1900+$year); my $heurefr = $hour."h".$min; # Test si presence de tous les arguments if (($numargs == 0) ($numargs == 1) ($numargs == 2) ($numargs == 3) ($numargs == 4) ($numargs == 5) ($numargs == 7) ($numargs == 8)) print "Usage pour windows : backup-snapshot.pl <nom VM> <adresse IP serveur esx> <nom d'utilisateur serveur esx> <password serveur esx> <adresse IP serveur rsync> <chemin fichier log>\n"; print "Usage pour linux : backup-snapshot.pl <nom VM> <adresse IP serveur esx> <nom d'utilisateur serveur esx> <password serveur esx> <adresse IP serveur rsync> <chemin fichier log> <adresse IP vm linux> <nom d'utilisateur vm linux> <mot de passe vm linux>\n"; exit; elsif($numargs > 9) print "Attention vous avez specifiez trop d'arguments\n"; print "Usage pour windows : backup-snapshot.pl <nom VM> <adresse IP serveur esx> <nom d'utilisateur serveur esx> <password serveur esx> <adresse IP serveur rsync> <chemin fichier log>\n"; print "Usage pour linux : backup-snapshot.pl <nom VM> <adresse IP serveur esx> <nom d'utilisateur serveur esx> <password serveur esx> <adresse IP serveur rsync> <chemin fichier log> <adresse IP vm linux> <nom d'utilisateur vm linux> <mot de passe vm linux>\n"; exit; print LOG "==> Sauvegarde de la VM $VMName le $datefr a $heurefr\n"; # Connexion au serveur print "==> Connexion SSH au serveur ESX en cours\n"; $ssh = Net::OpenSSH->new(''.$username.':'.$password.'@'.$HOST_ESX.''); $ssh->error and die "Ne peut pas etablir de connexion SSH : ". $ssh->error;
print "\n"; print LOG "==> Connexion SSH au serveur ESX en cours\n"; # Liste des VMs print "==> listage des VMs\n"; $cmd = "/bin/vim-cmd vmsvc/getallvms"; $stdout = $ssh->capture($cmd); $ssh->error and die "Erreur de listage des VM". $ssh->error; # Fichier temporaire du nom des VMs print "$stdout\n"; open(vm,">".$fichiertxttemp); print VM $stdout; close(vm); print LOG "==> listage des VMs\n"; # traitement de la liste des VM print "==> Traitement de la liste\n"; my @liste; my $ligne; print LOG "==> Traitement de la liste\n";
open(vm,$fichiertxttemp) while (<VM>) chomp; $ligne = $_; # Remplacement des multiples espaces par une tabulation $ligne =~ s/\s2,/\t/g; # Spliter dans un tableau @liste = split(/\t/,$ligne); $VMID = $liste[0]; if ($VMID eq "Vmid") next; ; # 1ere ligne inutile. On saute. if (lc($liste[1]) eq lc($vmname)) print "==> VM $VMName trouve\n"; print LOG "==> VM $VMName trouve\n"; # Test si VM est eteinte si non extinction $cmd = "vim-cmd vmsvc/power.getstate $VMID"; $stdout = $ssh->capture($cmd); $ssh->error and die "Erreur de recuperation de l'etat de la vm". $ssh->error; print "$stdout\n"; if($stdout =~/$keyword/i) print "==> VM déja eteinte \n"; else
# Test si VM est un linux ou windows if ($numargs == 9) my $ssh2; my $ipvmlinux = $ARGV[6]; my $login = $ARGV[7]; my $passwd = $ARGV[8]; ". $ssh2->error; # Connexion a la machine virtuelle sous linux print "==> Connexion SSH à la VM linux en cours\n"; $ssh2 = Net::OpenSSH->new(''.$login.':'.$passwd.'@'.$ipVMlinux.''); $ssh2->error and die "Erreur dans la connexion SSH sur la machine virtuelle linux print "\n"; print LOG "==> Connexion SSH à la VM linux en cours\n"; else # Extinction de la machine linux $cmd = "halt"; $stdout = $ssh2->capture($cmd); $ssh2->error and die "Erreur extinction de la machine linux". $ssh2->error; print "$stdout\n"; # Extinction de la VM print "==> Extinction de la VM \n"; $cmd = "vim-cmd vmsvc/power.shutdown $VMID"; $stdout = $ssh->capture($cmd); $ssh->error and die "Erreur de l'extinction". $ssh->error;
print "$stdout\n"; print LOG "==> Extinction de la machine\n"; # On attend tant que la machine n'est pas eteinte print "==> Recuperation de l'etat de la VM\n"; until ($stdout =~/$keyword/i) $cmd = "vim-cmd vmsvc/power.getstate $VMID"; $stdout = $ssh->capture($cmd); $ssh->error and die "Erreur de recuperation de l'etat de la vm". $ssh->error; print "$stdout\n"; sleep ($timeshutdown); print "==> VM eteinte\n"; print LOG "==> VM eteinte\n"; # Recup repertoire de la VM print "==> Recuperation du repertoire de la VM\n"; my ($datastore,$vm) = split(' ',$liste[2]); $datastore = substr($datastore,1); $datastore = substr($datastore,0,-1); my ($rep_vm) = split('/',$vm); my $rep = "/vmfs/volumes/".$datastore."/".$rep_vm; print "=====> Datastore: $datastore Repertoire: $rep_vm\n";
print "=====> Repertoire complet: $rep\n"; print LOG "==> Recuperation du repertoire de la VM\n"; # Transfert RSYNC print "==> Debut du transfert Rsync\n"; $cmd = "/bin/rsync-static -avt --stats --delete --whole-file $rep rsync://". $HOST_RSYNC."::/backup/"; print "$cmd\n"; $stdout = $ssh->capture($cmd); $ssh->error and die "Erreur dans le transfert de la VM". $ssh->error; print "$stdout\n"; print LOG "==> Debut du transfert Rsync : $cmd\n"; # Demarrage de la VM print "==> Demarrage de la VM et fin de la sauvegarde\n"; $cmd = "vim-cmd vmsvc/power.on $VMID"; $stdout = $ssh->capture($cmd); $ssh->error and die "Erreur de l'extinction". $ssh->error; print "$stdout\n"; print LOG "==> Demarrage de la VM et fin de la sauvegarde le $datefr a $heurefr\n"; print LOG
"<=========================================================>\n"; ; close(vm); # Suppression des fichiers temps system("rm -r $fichiertxttemp"); Définir le script en tant qu'executable : chmod +x backup-snapshot.pl Installation des librairie perl sur le serveur rsync : cpan install MIME::Lite Script perl send-log-backup.pl pour envoyer les logs par mail : #!/usr/bin/perl -w use strict; use MIME::Lite; # Declaration des variables par les arguments passer my $fichiertxtlog = $ARGV[0]; my $adressefrom = $ARGV[1]; my $adresseto = $ARGV[2]; my $sujetmessage = $ARGV[3]; my $numargs = $#ARGV + 1; # Verification si tous les champs requis on ete renseigner if (($numargs == 0) ($numargs == 1) ($numargs == 2) ($numargs == 3)) print "Usage : send-log-backup.pl <chemin du fichier log> <adresse mail source> <adresse mail destination>" elsif($numargs > 4) print "Attention vous avez specifiez trop d'arguments\n"; print "Usage : send-log-backup.pl <chemin du fichier log> <adresse mail source> <adresse mail destination>"
# Recuperation du log my $contenufichierlog; open(log,$fichiertxtlog) or die "Erreur d'ouverture du fichier log : $!"; while (<LOG>) my $resultatligne = $_; $contenufichierlog.= $resultatligne; # Envoi du mail my $msg = MIME::Lite->new( ); From To => $adressefrom, => $adresseto, Subject => $sujetmessage, Data $msg->send; => $contenufichierlog Définir le script en tant qu'executable : chmod +x send-log-backup.pl Script bash VMliste-cron.sh enchainer les backups de VM avec envoie de logs à la fin : #!/bin/bash #Pour une VM linux : /mnt/backup-snapshot.pl nomvm adresseipserveuresx nomutilisateurserveuresx passwordserveuresx adresseipserveurrsync cheminfichierlog adresseip #Pour une VM windows : /mnt/backup-snapshot.pl nomvm adresseipserveuresx nomutilisateurserveuresx passwordserveuresx adresseipserveurrsync cheminfichierlog #Envoie des logs par mail : /mnt/send-log-backup.pl chemindufichierlog adressemailsource adressemaildestination sujetdumessage #Suppression du fichier de log : rm -r logbackup.txt Définir le script en tant qu'executable : chmod +x VMliste-cron.sh