Chez JL

Joliciel Libre

Accueil > Informatique > Haute Disponibilité > Script de gestion du cluster à 2 noeuds

Script de gestion du cluster à 2 noeuds

mardi 11 octobre 2011, par JL

L’architecture concernée est un cluster à 2 noeuds. Les machines virtuelles sont sur un volume drbd qui s’appuie sur des volumes lvm sur chaque noeud. Par exemple sur le noeud1 il y a un volume lvm /dev/vg1/vmdd, et également sur le noeud2 /dev/vg1/vmdd. Un volume drbd /dev/drbd1 permettra de déclarer le disque dur de la vm.

Les 2 noeuds sont reliés par un cable croisé pour le traffic drbd, sur les adresses ip 10.0.0.1 et 10.0.0.2

Dans l’exemple, il y a 6 machines virtuelles : vm1, vm2... vm6

La machine vm6 est une machine windows, qui s’appuie sur un seul volume drbd : vm6dd

La vm5 est une machine redhat créé avec virt-manager, qui nécessiste la commande virsh pour être démarrée. Elle ne s’appuie également que sur un seul volume drbd.

Les fichiers de configuration xen des machines sont dans /root/xen_vm_cfg/

Les autres vm sont des vm linux qui s’appuie sur 2 volumes drbd (disque dur et le swap) : par exemple vm1dd et vm1sw

# <Gestion simplifiée de machine virtuelle sur un cluster xen-drbd à 2 noeuds >
# Copyright (C) 2011  <Jean-Louis Touraine>

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.



#! /bin/bash


SELFHOST=noeud1
SELFIP=10.0.0.1
PEERHOST=noeud2
PEERIP=10.0.0.2

if [ `uname -n` = noeud2 ] ; then
        SELFHOST=noeud2
        SELFIP=10.0.0.2
        PEERHOST=noeud1
        PEERIP=10.0.0.1
fi

function is_alive {
   xm list $1 >/dev/null 2>&1
}

function safe_to_migrate_win {
   case "$(drbdadm cstate $1)" in
   Connected|SyncSource|SyncTarget)
       return 0
       ;;
   *)
       return 1
       ;;
   esac
}

function safe_to_migrate_linux {
   case "$(drbdadm cstate $1dd)" in
   Connected|SyncSource|SyncTarget)
       return 0
       ;;
   *)
       return 1
       echo "$DRBD is disconnected, NOT safe to migrate"
       ;;
   esac
}

function update_mac_cache {
   arp -d $1 >/dev/null 2>&1 || true
   ping -c1 -w1 $1 >/dev/null 2>&1 || true
}

function migrer_vm {
echo "-----------------------------------------"
echo " Cette fonction n'est à utiliser que si :"
echo "- noeud1 et noeud2 sont actifs"
echo "- ils sont bien connectés au réseau"
echo "- les liens drbd sont UpToDate"
echo "- et autre..."
echo "-----------------------------------------"
echo ""
echo -n "Ecrire le nom de la machine virtuelle à migrer : "
read vm
case "$vm" in
        "") echo "Mettre le nom d'une machine virtuelle";;
        vm5|vm6)
                DEAD=1;
                ping -c 1 $vm > /dev/null 2>&1  && DEAD=0;
                if [ $DEAD -eq 1 ]; then echo "La machine virtuelle $vm ne répond pas au ping. Serait-elle inactive ?";
                else
                  if is_alive $vm; then
                        if safe_to_migrate_win $vm; then
                                ssh $PEERIP "drbdadm primary $vm";
                                  echo "Migration en cours...";
                                xm migrate --live $vm $PEERIP;
                                update_mac_cache;
                        else
                          echo "Volume drbd déconnecté, migration non effectuée";
                        fi
                  else
                        echo "La machine virtuelle $vm est sur l'autre serveur";
                        echo "Voulez vous la rapatrier sur ce serveur ?";
                        echo -n "oui ou non ? : "
                        read migre
                        case "$migre" in
                                oui)
                                   drbdadm primary $vm;
                                     echo "Migration en cours...";
                                   ssh $PEERIP "xm migrate --live $vm $SELFIP";
                                   update_mac_cache;;
                                non) echo "Pas de migration";;
                                *) echo "Pas de migration";;
                        esac
                  fi
                fi
                ;;
        vm1|vm2|vm3|vm4)
                DEAD=1;
                ping -c 1 $vm > /dev/null 2>&1  && DEAD=0;
                if [ $DEAD -eq 1 ]; then echo "La machine virutelle $vm n'est pas active";
                else
                  if is_alive $vm; then
                        if safe_to_migrate_linux $vm; then
                        # Normalement commande drbdadm primary inutile pour vm linux
                                ssh $PEERIP "drbdadm primary $vm'dd'";
                                ssh $PEERIP "drbdadm primary $vm'sw'";
                                  echo "Migration en cours...";
                                xm migrate --live $vm $PEERIP;
                                update_mac_cache;
                        else
                          echo "Volume drbd déconnecté, migration non effectuée";
                        fi
                  else
                        echo "La machine virtuelle $vm est sur l'autre serveur";
                        echo "Voulez vous la rapatrier sur ce serveur ?";
                        echo -n "oui ou non ? : "
                        read migre
                        case "$migre" in
                                oui)
                                     echo "Migration en cours...";
                        # Normalement commande drbdadm primary inutile pour vm linux
                                   drbdadm primary $vm'dd';
                                   drbdadm primary $vm'sw';
                                   ssh $PEERIP "xm migrate --live $vm $SELFIP";
                                   update_mac_cache;;
                                non) echo "Pas de migration";;
                                *) echo "Pas de migration";;
                        esac
                  fi
                fi
                ;;

        *) echo "$vm : Cette machine virtuelle n'est pas définie";;
esac
}


function connexion {
if
   ping -c1 -w1 10.0.0.1 >/dev/null 2>&1 || false
then
   if
        ping -c1 -w1 10.0.0.2 >/dev/null 2>&1 || false
        then echo "noeud1 et noeud2 répondent au ping sur le lien drbd"
   else echo "!!! noeud2 ne répond pas au ping sur le lien drbd !!!"
   fi
else
   echo " !!! noeud1 ne répond pas au ping sur le lien drbd !!!"
fi

if
   ping -c1 -w1 noeud1 >/dev/null 2>&1 || false
then
   if
        ping -c1 -w1 noeud2 >/dev/null 2>&1 || false
        then echo "noeud1 et noeud2 répondent au ping sur le reseau local"
   else echo "!!! noeud2 ne répond pas au ping sur le reseau local !!!"
   fi
else
   echo "!!! noeud1 ne répond pas au ping sur le reseau local !!!"
fi
}


function eteindre_vm {
echo "-------------------------------------------------------------"
echo "Consignes :"
echo "ATTENTION, vous avez décidé d'éteindre une machine virtuelle"
echo "-------------------------------------------------------------"
echo -n "Ecrire le nom de la machine virtuelle à éteindre : "
read vm
case "$vm" in
        "") echo "Mettre le nom d'une machine virtuelle";;
        vm1|vm2|vm3|vm4|vm5|vm6)
        echo -n "Ecrire le nom du serveur sur lequel est la machine virtuelle (pas de détection automatique encore...) : "
                  read serveur
                  case "$serveur" in
                   "") echo "Mettre le nom d'un serveur (noeud1 ou noeud2)";;
                    noeud1)
                      if [ $SELFHOST = noeud1 ] ; then
                      xm shutdown $vm;
                      else
                      ssh noeud1 "xm shutdown $vm";
                      fi
                      ;;
                    noeud2)
                      if [ $SELFHOST = noeud2 ] ; then
                      xm shutdown $vm;
                      else
                      ssh noeud2 "xm shutdown $vm"
                      fi
                      ;;
                    *) echo "Pas de démarrage de vm";;
                  esac
        ;;
        *) echo "Pas d'extinction de machine virutelle";
esac
}

function eteindre_force_vm {
echo "-------------------------------------------------------------"
echo "Consignes :"
echo "ATTENTION, vous avez décidé d'éteindre une machine virtuelle DE FORCE (destroy)"
echo "-------------------------------------------------------------"
echo -n "Ecrire le nom de la machine virtuelle à éteindre : "
read vm
case "$vm" in
        "") echo "Mettre le nom d'une machine virtuelle";;
        vm1|vm2|vm3|vm4|vm5|vm6|migrating-vm1|migrating-vm2|migrating-vm3|migrating-vm4|migrating-vm5|migrating-vm6)
        echo -n "Ecrire le nom du serveur sur lequel est la machine virtuelle (pas de détection automatique encore...) : "
                  read serveur
                  case "$serveur" in
                   "") echo "Mettre le nom d'un serveur (noeud1 ou noeud2)";;
                    noeud1)
                      if [ $SELFHOST = noeud1 ] ; then
                      xm destroy $vm;
                      else
                      ssh noeud1 "xm destroy $vm";
                      fi
                      ;;
                    noeud2)
                      if [ $SELFHOST = noeud2 ] ; then
                      xm destroy $vm;
                      else
                      ssh noeud2 "xm destroy $vm"
                      fi
                      ;;
                    *) echo "Pas de démarrage de vm";;
                  esac
        ;;
        *) echo "Pas d'extinction de machine virutelle";
esac
}


# parametres :
# $1 : machine virtuelle a démarrer
# $2 : hote sur lequel la demarrer
function demarrer_vm {
 DEAD=1;
 ping -c 1 $1 > /dev/null 2>&1  && DEAD=0;
        if [ $DEAD -eq 0 ]; then echo "La machine virtuelle $1 répond au ping, elle est déjà démarrée.";
        # voir pour un test supplementaire, car la vm peut etre démarrée mais ne par repondre au ping...
        else
                echo "La vm $1 ne répond pas au ping, a priori elle n'est pas démarrée. Pour la démarrer, valider avec Entrée, sinon faire ctrl+c"
                read
                                        echo "Démarrage de la vm $1 sur l'hôte $2";
                if [[ $SELFHOST == $2 ]] ; then
                        case "$1" in
                                vm5)
                      drbdadm primary $1;
                                        virsh create /root/xen_vm_cfg/$1.xml;;
              vm6)
                                        drbdadm primary $1;
                                        xm create /root/xen_vm_cfg/$1.cfg;;
                                vm1|vm2|vm3|vm4)
                                        drbdadm primary $1'dd';
                                        drbdadm primary $1'sw';
                                        xm create /root/xen_vm_cfg/$1.cfg;;
                                *) echo "Erreur dans le script. La vm n'est pas prise en compte.";;
                        esac
                else
                        case "$1" in
                                redis)
                      ssh $PEERHOST "drbdadm primary $1";
                                        ssh $PEERHOST "virsh create /root/xen_vm_cfg/$1.xml";;
              vm6)
                                        ssh $PEERHOST "drbdadm primary $1";
                                        ssh $PEERHOST "xm create /root/xen_vm_cfg/$1.cfg";;
                                vm1|vm2|vm3|vm4|vm5)
                                        ssh $PEERHOST "drbdadm primary $1'dd'";
                                        ssh $PEERHOST "drbdadm primary $1'sw'";
                                        ssh $PEERHOST "xm create /root/xen_vm_cfg/$1.cfg";;
                                *) echo "Erreur dans le script. La vm n'est pas prise en compte.";;
                        esac
                fi
        fi
}

# permet de choisir sur quel serveur demarrer la vm
function menu_demarrer_une_vm {
echo "--------------------------------------------------------"
echo "Consignes :"
echo "S'assurer que la vm n'est pas déjà démarrée"
echo "S'assurer que drbd connecté, que connexion réseau ok..."
echo "--------------------------------------------------------"
echo ""
echo -n "Ecrire le nom de la machine virtuelle à démarrer : "
read vm
echo -n "Ecrire le nom du serveur sur lequel démarrare la machine virtuelle (noeud1 ou noeud2) : "
read serveur

demarrer_vm $vm $serveur;
}

function menu_demarrer_vms_repartition {
        # Permet de preciser l'ordre de démarrage des vms
        echo "Démarrage des machines virtuelles, réparties sur noeud1 et noeud2"
        demarrer_vm vm1 noeud1;
        demarrer_vm vm2 noeud1;
        demarrer_vm vm3 noeud1;
        demarrer_vm vm4 noeud2;
        demarrer_vm vm5 noeud2;
        demarrer_vm vm6 noeud2;
       
echo ""
echo "---------------------------------------------------------------"
echo "Si vm1 a redémarré, vérifier que le montage nfs vers vm2"
echo "est ok !"
echo "---------------------------------------------------------------"
echo "Si vm6 a redémarré, vérifier que le logiciel X fonctionne bien"
echo "Vérifier également que vm6 est à l'heure."
echo "---------------------------------------------------------------"

}

function menu_demarrer_vms_noeud1 {
        echo "Démarrage des machines virtuelles sur noeud1"
        # Permet de preciser l'ordre de démarrage des vms
for i in vm1 vm2 vm3 vm4 vm5 vm6
do
        demarrer_vm $i noeud1;
done

echo ""
echo "---------------------------------------------------------------"
echo "Si vm1 a redémarré, vérifier que le montage nfs vers vm2"
echo "est ok !"
echo "---------------------------------------------------------------"
echo "Si vm6 a redémarré, vérifier que le logiciel X fonctionne bien"
echo "Vérifier également que vm6 est à l'heure."
echo "---------------------------------------------------------------"

}


function menu_demarrer_vms_noeud2 {
        echo "Démarrage des machines virtuelles sur noeud2"
        # Permet de preciser l'ordre de démarrage des vms
for i in vm1 vm2 vm3 vm4 vm5 vm6
do
        demarrer_vm $i noeud2;
done
echo ""
echo "---------------------------------------------------------------"
echo "Si vm1 a redémarré, vérifier que le montage nfs vers vm2"
echo "est ok !"
echo "---------------------------------------------------------------"
echo "Si vm6 a redémarré, vérifier que le logiciel X fonctionne bien"
echo "Vérifier également que vm6 est à l'heure."
echo "---------------------------------------------------------------"

}



function menu {
echo "###### Serveur $SELFHOST ###############"
echo "1 : tester connexion"
echo "2 : voir état des liens drbd"
echo "3 : lister les machines virutelles actives"
echo "4 : démarrer toutes les machines virutelles (reparties sur noeud1 et noeud2)"
echo "5 : migrer une machine virtuelle"
echo "6 : gestionnaire graphique de noeud1 (fonctionne si serveur X)"
echo "7 : gestionnaire graphique de noeud2 (fonctionne si serveur X)"
echo "8 : eteindre une machine virtuelle"
echo "9 : eteindre de force (destroy) une machine virtuelle"
echo "10 : demarrer une machine virtuelle (préciser sur serveur noeud1 ou noeud2)"
echo "11 : demarrer toutes les machines virtuelles sur noeud1 (si noeud2 est en panne)"
echo "12 : demarrer toutes les machines virtuelles sur noeud2 (si noeud1 est en panne)"
echo "q : quitter"
echo ""
echo "Ecrire votre choix (1 ou 2 ou 3...) :"
echo ""
}

while :
do
clear
menu
echo -n "Choix : "; read choix

case $choix in
        1) clear;menu;echo "";
                connexion;
                echo ""
                echo -n "Appuyer sur Entrée"
                read;;
        2) clear;menu;echo "";
                /etc/init.d/drbd status;
                echo ""
                echo "Pour un état correcte, tout doit être UpToDate/UpToDate"
                echo -n "Appuyer sur Entrée"
                read;;
        3) clear;menu;echo "";
                echo "Sur le serveur $SELFHOST"
                xm list;
                echo ""
                echo "Sur le serveur $PEERHOST"
                ssh $PEERIP "xm list";
                echo ""
                echo -n "Appuyer sur Entrée"
                read;;
        4) clear;menu;echo "";
                menu_demarrer_vms_repartition
                echo ""
                echo -n "Appuyer sur Entrée"
                read;;
        5) clear;menu;echo "";
                migrer_vm
                echo ""
                echo -n "Appuyer sur Entrée"
                read;;
        6) clear;menu;echo "";
                if [ $SELFHOST = noeud1 ] ; then
                  virt-manager
                else
                  ssh -X noeud1 "virt-manager"
                fi
                echo ""
                echo -n "Appuyer sur Entrée"
                ;;
        7) clear;menu;echo "";
                if [ $SELFHOST = noeud2 ] ; then
                  virt-manager
                else
                  ssh -X noeud2 "virt-manager"
                fi
                echo ""
                echo -n "Appuyer sur Entrée"
                ;;
        8) clear;menu;echo "";
                eteindre_vm
                echo ""
                echo -n "Appuyer sur Entrée"
                ;;
        9) clear;menu;echo "";
                eteindre_force_vm
                echo ""
                echo -n "Appuyer sur Entrée"
                ;;
        10) clear;menu;echo "";
                menu_demarrer_une_vm
                echo ""
                echo -n "Appuyer sur Entrée"
                ;;
        11) clear;menu;echo "";
                menu_demarrer_vms_noeud1
                echo ""
                echo -n "Appuyer sur Entrée"
                read;;
        12) clear;menu;echo "";
                menu_demarrer_vms_noeud2
                echo ""
                echo -n "Appuyer sur Entrée"
                read;;
        q) exit;;
        *) clear;menu;echo "";
                echo "Ce choix n'est pas correct";
                echo ""
                echo -n "Appuyer sur Entrée"
                read;;
esac
done