Sommaire
Bonjour,
ce matin j'avais besoin d'adresser des commandes ipmi à plusieurs hôtes pour pouvoir, notamment, paramétrer l'hôte pour qu'il démarre dans les options de BIOS, qu'il boote en PXE, qu'il démarre ou s'éteigne aussi, tout simplement. Et j'avais besoin de me simplifier la vie pour lancer ces commandes sur un grand nombre d'hôte.
Chercher dans l'historique des commandes, remplacer le nom d'hôte devient vite non satisfaisant. Ecrire un script shell, pourquoi pas; oh et puis pourquoi ne pas regarder comment faire simplement une petite interface utilisateur en shell ?!
Les commandes ipmitool utiles
Les commandes ipmitool qui m'étaient utiles sont les suivantes (en notant monhote
le nom de l'hôte ciblé ) :
Aller dans les paramètres de BIOS au prochain boot :
ipmitool -I lanplus -H imonhote -U root -P PASSWORD chassis bootparam set bootflag force_bios
Partir en boot PXE au prochain boot :
ipmitool -I lanplus -H imonhote -U root -P PASSWORD chassis bootdev pxe
Eteindre le chassis :
ipmitool -I lanplus -H imonhote -U root -P PASSWORD chassis power off
Allumer le chassis :
ipmitool -I lanplus -H imonhote -U root -P PASSWORD chassis power on
Faire un power off/power on :
ipmitool -I lanplus -H imonhote -U root -P PASSWORD chassis power cycle
Faire un power reset quand l'extinction propre ne fonctionne plus :
ipmitool -I lanplus -H imonhote -U root -P PASSWORD chassis power reset
Ces commandes très pratiques, je vais devoir les répéter pour environ 100 hôtes pour lancer des réinstallations PXE à distance et probablement de temps en temps pour d'autres raisons.
L'interface whiptail
J'ai commencé à regarder ce qu'il existe comme outils pour faire une petite interface. Et puis je suis tombé sur dialog et whiptail. Je n'ai pas suffisamment creusé pour avoir un avis sur l'un ou l'autres (et d'ailleurs dialog semble avoir eu 2 vies). Les syntaxes m'ont l'air similaires, j'avais whiptail installé sur le serveur d'administration que j'utilisai, je suis partie là dessus.
Pour ma petite interface, je vais utiliser une hiérarchie de menu :
- une première liste de l'ensemble des hôtes parmi lesquel on peut sélectionner l'hôte cible, on appellera la fonction
select_node $message
, la variablemessage
me permettant d'afficher un message arbitraire sur l'interface - une liste de commandes IPMI exécutables sur l'hôte, on appellera la commande
ipmi_menu $selected_node
, la variableselected_node
étant le nom d'hôte ciblé
Boucle principale
Le script bash commence par une fonction principale
# Main loop
run=1
message=""
while [ $run = 1 ]; do
selected_node=`select_node $message`
exitstatus=$?
if [ $exitstatus = 1 ]; then
run=1
message=`ipmi_menu $selected_node`
else
run=0
fi
done
Menu de sélection de l'hôte
Pour la sélection de l'hôte, je définis un menu avec whiptail --menu
. La commande complète est de la forme whiptail --menu text height width menu-height [tag item]
. Les options à fournir à whiptail (ce qui est appelé tag item dans la documentation* sont de la forme "nom de l'option 1" "texte supplémentaire pour l'option 1" "nom de l'option 2" "texte supplémentaire pour l'option 2". J'ai un certain nombre d'hôte à mettre en option, j'utilise un array bash pour définir ces options.
function select_node() {
local message=$1
node_list=()
for i in {01..68}; do
node="kyle$i"
node_list[${#node_list[@]}]=$node
node_list[${#node_list[@]}]=""
done
OPTION=$(whiptail --title "IPMI interaction" --menu "Choose a node. Last message : $message" 30 90 10 "${node_list[@]}" 3>&1 1>&2 2>&3)
exitstatus=$?
if [ $exitstatus = 0 ]; then
echo $OPTION
return 1
else
return 0
fi
}
Je n'ai pas creusé la raison des redirections 3>&1 1>&2 2>&3
. Je profite de l'affichage de ce menu pour afficher un message arbitraire. Dans mon UI, je revies à ce menu chaque fois que j'ai lancé une commande ipmi et je voulai voir la sortie standard de la dernière commande exécutée.
Menu d'exécution des commandes ipmi
Lorsque l'hôte est sélectionné, je lance un menu pour les commandes ipmi :
function run_ipmi {
local node=$1
local cmd=$2
result=`ipmitool -I lanplus -H i$node -U root -P $ipmipass $cmd`
echo $result
}
function ipmi_menu {
local node=$1
pwr_status=`run_ipmi $node "power status"`
options=("Force bios on reboot" "" "Force PXE on reboot" "" "Power cycle" "" "Power reset" "" "Power on" "" "Power off" "")
OPTION=$(whiptail --title "IPMI interaction" --menu "Choose an ipmitool for node $node; Pwr: $pwr_status" 30 90 6 "${options[@]}" 3>&1 1>&2 2>&3)
exitstatus=$?
if [ $exitstatus = 0 ]; then
case $OPTION in
"Force bios on reboot")
echo "Bios on reboot for $node"
run_ipmi $node "chassis bootparam set bootflag force_bios"
;;
"Force PXE on reboot")
echo "PXE on reboot for $node"
run_ipmi $node "chassis bootdev pxe"
;;
"Power cycle")
echo "Power cycle $node"
run_ipmi $node "chassis power cycle"
;;
"Power on")
echo "Power reset $node"
run_ipmi $node "chassis power on"
;;
"Power off")
echo "Power reset $node"
run_ipmi $node "chassis power off"
;;
"Power reset")
echo "Power reset $node"
run_ipmi $node "chassis power reset"
;;
*)
echo "unknown"
;;
esac
else
return 0
fi
}
Cette fois-ci, je défini explicitement les options pour le menu. Je profite de ce menu pour afficher l'état électrique du châssis. La sortie standard de cette commande est capturée dans la boucle principale qui va afficher le premier menu avec commande message arbitraire cette sortie standard.
Et voila, je trouve ce petit script bricolé assez pratique et relativement efficace pour piloter mes hôtes par ipmi.
# kiss
Posté par Xanatos . Évalué à 3.
Merci de la découverte, je n'avais pas réalisé que c'était des boites de dialogue du style installateur de distro, à l'ancienne, c'est vraiment tout simple et semble empaqueté pour Debian & dérivés & openwrt.
Des exemples ici https://en.wikibooks.org/wiki/Bash_Shell_Scripting/Whiptail
Je ne connais pas assez pour savoir ce que cela change concrètement, je ne connaissais que ncurses.
[^] # Re: kiss
Posté par toremilaC . Évalué à 1.
De ce que j'ai pu lire, il y a la parenté curses d'une part, avec dialog et ses dérivés, et la parenté slang d'autre part, avec newt et whiptail.
Whiptail est fourni dans la librairie Newt (première version il y a 27 ans !) qui est basée sur la libraire slang.
Dialog est basé sur curses/ncurses.
Github: https://github.com/jeremyfix
# Une image vaut 1000 mots
Posté par Mimoza . Évalué à 7.
Une petite capture d'écran aurait été pas mal en fin d'article pour voir le résultat final :)
Mais sinon merci pour le partage ;)
[^] # Re: Une image vaut 1000 mots
Posté par toremilaC . Évalué à 3.
Oh oui, tout à fait !
Le premier menu :
Et le second menu une fois l'hôte sélectionné :
Github: https://github.com/jeremyfix
[^] # Re: Une image vaut 1000 mots
Posté par gUI (Mastodon) . Évalué à 6.
Je me suis permis de le rajouter dans le journal.
Et si t'es motivé pour faire une dépêche sur cet outil je suis ton homme pour la relecture ;)
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: Une image vaut 1000 mots
Posté par toremilaC . Évalué à 4.
Merci !
Ok, je vais y réfléchir.
Github: https://github.com/jeremyfix
# 3>&1 1>&2 2>&3
Posté par steph1978 . Évalué à 6.
Ce code shell redirige la sortie de la commande donnée.
3>&1
: redirige le descripteur de fichier 3 vers le descripteur de fichier 1. En d'autres termes, cela redirige la sortie du descripteur de fichier 3 vers le même emplacement que le descripteur de fichier 1 (qui est généralement la sortie standard).1>&2
: redirige le descripteur de fichier 1 vers le descripteur de fichier 2. Cela redirige la sortie standard vers la sortie d'erreur.2>&3
: redirige le descripteur de fichier 2 vers le descripteur de fichier 3. Cela redirige la sortie d'erreur vers l'emplacement de sortie du descripteur de fichier 3 (qui était initialement la sortie standard).En résumé, le code échange les flux de sortie standard et d'erreur standard. Ainsi, lorsque la commande est exécutée, la sortie qui irait normalement vers la sortie standard est redirigée vers la sortie d'erreur, et la sortie qui irait normalement vers la sortie d'erreur est redirigée vers la sortie standard.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.