Expect en action
Informations générales
- Nom du script : publip.sh (publi(point)sh...publipSH...publipèssache...publipostage...bon ok, laissez tomber...)
- Flexibilité : Quasi-totale
- Contraintes : 1 seule, il faut que le mot de passe soit le même pour tout les équipements, sinon il faut rajouter quelques lignes de code...
- Criticité : élevée. Il faut faire très attention avec les commandes entrées, vous pouvez geler votre réseau entier si vous ne savez pas ce que vous faites !
- Connaissances requises en Linux : Vous savez ouvrir/éditer un fichier (vi nom_fichier) ? Rentrer des jolies choses dedans (i [pour insérer du texte], puis blablabla), l'enregistrer et le fermer (echap, puis :wq <entrée> ? Vous savez exécuter un script par la commande ./nom_script dans le dossier où il se trouve ? non ? Eh bien maintenant, oui ! Aucune connaissance n'est requise pour utiliser ce script :-)
publipmachin point cheu ? Mais c'est quoi au juste ?
Ce script permet pour un administrateur réseau, de rentrer des lignes de commandes Cisco, publipostées sur un nombre d'équipements distants choisi (
routeur,
firewall,
switch, Point d'accès
Wifi...), ce en
SSH, où en
Telnet (le script gère les deux types de connexion) et automatiquement.
Ces lignes de commandes seront tout d'abord saisies à la suite, une commande par ligne comme un batch, ou un fichier de configuration, dans un petit fichier nommé commandes.txt (il n'y a aucune limite de taille)
Ensuite, il va falloir rentrer toutes les IP (où alias
DNS), des équipements où vous voulez que les commandes soient rentrées (il n'y a aucune limite de nombre d'équipements).
Enfin, vous exécutez le script, et là, il faudra pas vous tromper quand le script vous demandera de saisir le mot de passe, qui
je le rappelle doit être impérativement le même pour tous les équipements.
Mais là où cela devient intéressant, c'est que ce script va beaucoup plus loin !
En effet, il prends en charge et ce de façon totale les erreurs de connexion, et de saisie, pour les rentrer ensuite dans un fichier log. Ce script identifie également les équipements pour lequel il est parvenu à se connecter en SSH, où en telnet, et enfin il conserve une archive des procédures de saisies générant des erreurs critiques (plantage du script, erreur d'interprétation d'une commande par l'équipement). Les différents types d'erreurs pris en charge sont :
- 1 - Connexion en timeout
- 2 - Erreur de log-in, où de mot de passe
- 3 - Alias DNS ou IP inexistante
- 4 - Plantage du script Expect (création de fichier log de l'équipement)
- 5 - Connexion à distance désactivée
- 6 - Alias DNS correct mais associée a une IP qui n'existe pas (no route to host)
- 7 - Équipement non Cisco (HP Procurve)
- 8 - Équipement non Cisco (X1000)
- 9 - Équipement non Cisco (Alcatel)
- 10 - Commande publipostée non reconnu par l'équipement (création de fichier log de l'équipement)
- 11 - Erreur non répertoriée çi-dessus ($? = 1)
Vous pourrez en plus d'opérer sur tous vos équipements en même temps, recueillir des informations précieuses sur votre réseau ! Elle est pas belle la vie ?
Le contenu des fichiers annexes
commandes.txt
Vous devrez absolument rentrer des commandes à la suite...Le fichier doit pour toute modification de la configuration du routeur commencer par "conf t" et finir par "end". N'oubliez pas de procéder de manière hiérarchique, pour ne pas rentrer des commandes là où il ne faut pas...et surtout...n'oubliez pas d'enregistrer vos modifications ! Petit exemple :
#commandes.txt
conf t
router ospf 100
network 50.50.100.0 0.0.0.255 area 0
exit
interface fa0/0
ip ospf hello-interval 5
ip ospf dead-interval 20
exit
area 0 authentication message-digest
end
write mem
liste.txt
Un jeu d'enfant ! Rentrez juste les IP, ou les alias DNS, des équipements concernés, et c'est tout ! Un équipement par ligne...petit exemple encore :
# liste.txt
10.25.85.46
routeur-marseille
switch-assemblee-generale
80.54.136.105
J'ai laissé volontairement un espace, pour vous montrer que le script ne prends pas en compte les espaces.
THE Script
Le script sera légendé par des petits #[1], qui seront commentés tout en bas du script
#!/bin/bash
#script.sh
echo "veuillez donner le mot de passe"
stty -echo #[1]
read password
stty echo
export ssh='./ssh.sh' #[2]
export telnet='./telnet.sh'
export erreur='./rapport_erreurs.log'
export temp='./tmp_routeur.log'
export cmdcisco='./commandes.txt'
export liste='./liste.txt'
export password
export routeur
export commande
rm -f $erreur #[3]
rm -f $ssh
rm -f $telnet
cat $liste | while read routeur;
do
if [ "$routeur" != "" ]
then
if[ ! -f $ssh ] #[4]
then
echo 'expect 2>&1 << EOF'>> $ssh
echo 'spawn ssh admin@$routeur' >> $ssh
echo 'expect {' >> $ssh
echo '"Password:" {send "$password\r"}' >> $ssh
echo 'timeout {exit}' >> $ssh
echo ' }' >> $ssh
echo 'expect "#"' >> $ssh
cat $cmdcisco | while read commande
do
echo "send \"$commande\r\""
echo 'expect "#"'
done >> $ssh
echo 'send "exit\r"' >> $ssh
echo 'expect "closed"' >> $ssh
echo 'exit' >> $ssh
echo 'EOF' >> $ssh
chmod +x $ssh #[5]
fi
time -p $ssh > $temp 2>&1 #[6]
COD_RET=$?
auth='cat $temp | grep -c "Password: "' #[7]
if [ "$auth" -gt "1" ]
then
echo "Problème d'authentification sur $routeur !"
echo "$routeur : wrong log-in/password" >> $erreur
continue
fi
temps='grep 'real ' $temp | sed 's/real /§/' | cut -d'§' -f2 | cut -d' ' -f1 | cut -d'.' -f1'
if [ $temps -ge 10 -a ! "'grep 'closed' $temp'" ] #[8]
then
echo "L'equipement $routeur ne réponds pas !";
echo "$routeur : connection timed out" >> $erreur
continue
fi
if [ "$COD_RET" != "0" ] #[9]
then
#Erreur de connexion a l'équipement en SSH
if [ ! -f $telnet ]
then
echo 'expect 2>&1 << EOF'>> $telnet
echo 'spawn telnet $routeur' >> $telnet
echo 'send "admin\r"' >> $telnet
echo 'expect "Password:"' >> $telnet
echo 'send "$password\r"' >> $telnet
echo 'expect "#"' >> $telnet
cat $cmdcisco | while read commande
do
echo "send \"$commande\r\""
echo 'expect "#"'
done >> $telnet
echo 'send "exit\r"' >> $telnet
echo 'expect "closed"' >> $telnet
echo 'exit' >> $telnet
echo 'EOF' >> $telnet
chmod +x $telnet
fi
$telnet > $temp 2>&1
fi
COD_RET=$?
auth='cat $temp | grep -c "Password: "' #[10]
if [ "$auth" -gt "1" ]
then
echo "Problème d'authentification sur $routeur !"
echo "$routeur : wrong log-in/password" >> $erreur
elif [ "'grep 'Host name lookup failure' $temp'" ]
then
echo "l'equipement $routeur n'existe pas !"
echo "$routeur : does not exist" >> $erreur
elif [ "'grep 'Unknown host' $temp'" ]
then
echo "la saisie de l'ip ou du nom $routeur est incorrecte !"
echo "$routeur : wrong spelling" >> $erreur
elif [ "'grep 'send: spawn id exp4 not open' $temp'" ]
then
echo " ERREUR dans la procédure. Consultez le fichier log de $routeur !!!"
echo "$routeur : Expect script execution failed !" >> $erreur
cp $temp $routeur.error.log
elif [ "'grep 'Authentication failed' $temp'" ]
then
echo "Mot de passe erroné pour $routeur !"
echo "$routeur : wrong log-in/password" >> $erreur
elif [ "'grep 'Connection refused' $temp'" ]
then
echo "Connexion à distance sur $routeur désactivé !"
echo "$routeur : vty connection disabled" >> $erreur
elif [ "'grep 'No route to host' $temp'" ]
then
echo "Alias DNS $routeur existant mais IP invalide !"
echo "$routeur : No route to host" >> $erreur
elif [ "'grep 'ProCurve' $temp'" ]
then
echo "routeur $routeur HP et non Cisco !"
echo "$routeur : non Cisco router (HP ProCurve)" >> $erreur
elif [ "'grep 'Alcatel' $temp'" ]
then
echo "routeur $routeur Alcatel et non Cisco !"
echo "$routeur : non Cisco router (Alcatel)" >> $erreur
elif [ "'grep 'Welcome to X1000' $temp'" ]
then
echo "routeur $routeur X1000 et non Cisco !"
echo "$routeur : non Cisco equipement (X1000)" >> $erreur
elif [ "'grep '% Unknown command' $temp'" -o "'grep '% Invalid' $temp'" ]
then
echo " Commandes Cisco non reconnues par l'equipement. Consultez le fichier log de $routeur !!!"
echo "$routeur : Unrecognized commands found" >> $erreur
cp $temp $routeur.error.log
elif [ "'grep 'Connected to ' $temp'" -o "'grep 'Connection closed by foreign host.' $temp'" ]
then
echo "$routeur Telnet OK !"
elif [ "'grep 'Connexion enregistree sur le terminal' $temp'" -o "'grep 'Connection to ' $temp'" ]
then
echo "$routeur SSH OK !"
elif [ "$COD_RET" != "0" ]
then
echo "Problème de connexion a l'equipement $routeur !"
echo "$routeur : connection problem" >> $erreur
fi
fi
done
rm -f $temp #[11]
exit
Commentaires
- 1 : On cache la saisie du mot de passe
- 2 : Tous les fichiers sont stockés dans des variables en chemin relatif, pour que le script puisse être exécuté de n'importe où
- 3 : on supprime les fichiers générés existants si le script à déjà été exécuté
- 4 : on génère le fichier Expect si ce n'est pas déjà fait, en rentrant la procédure de connexion SSH ainsi que les commandes provenant de commandes.txt
- 5 : on attribue les droits d'exécution au script Expect généré, si on veut qu'il s'exécute correctement
- 6 : on execute le script expect, en regroupant la sortie d'erreur avec la sortie standard, en calculant le temps d'exécution pour gérer le timeout, et en crachant le tout dans un fichier temp
- 7 : on vérifie qu'il n'y ai pas un problème d'authentification en comptant le nombre d'occurrence "Password:" dans le fichier temp
- 8 : on récupère le nombre du temps d'execution, et on vérifie qu'il ne soit pas supérieur à 10 (valeur du timeout du expect)
- 9 : En cas d'erreur de connexion en SSH, on refait la procédure en Telnet
- 10 : On gère tous les cas d'erreur pris en compte par le script. (c.f. II)
- 11 : On supprime le fichier temp, qui devient inutile
Remerciements
Je remercie en particlier
jipicy, pour son aide cruciale à la réalisation de ce script, et j'espère qu'il servira à plus d'un ;)
Questions / Report de Bugs / Modifications
M'étant réorienté de mon précédent poste, je n'ai malheureusement plus les compétences pour pouvoir vous aider sur le débogage du script. Je vous invite cependant à faire part de vos soucis dans la section forum développement de CCM, en prenant bien soin de linker cet article (n'oubliez pas de formuler poliment votre demande).
Bonne journée !
Ce document intitulé « Envoi de commandes CISCO publipostées via SSH/Telnet » issu de
Comment Ça Marche (www.commentcamarche.net) est mis à disposition sous les termes de la licence
Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.