diff --git a/gestion/iscsi/slon-get-volume-mapping.py b/gestion/iscsi/slon-get-volume-mapping.py index 3f826523..9da18826 100755 --- a/gestion/iscsi/slon-get-volume-mapping.py +++ b/gestion/iscsi/slon-get-volume-mapping.py @@ -9,80 +9,24 @@ u'''Outil pour récupérer le mapping lun/volume depuis la baie de stockage''' -import telnetlib, re, sys +import slonlib, re, sys sys.path.append("/usr/scripts/gestion") from config import ISCSI_MAP_FILE import affich_tools -# Ce script utilise l'interface telnet de la baie. - -# La réponse à la commande "show volume-map" est une séquence -# d'éléments de la forme: -# -# nom du volume -# | -# v -# > Volume [SN 00c0ffd5e51800004ca1454901000000, Name (o2_slash)] mapping view: -# > CH ID LUN Access Host-Port-Identifier Nickname -# > ------------------------------------------------------------------------------- -# > 0,1 0 4 rw all other hosts -# ^ -# | -# lun - -# On utilise cette expression un peu barbare pour récupérer les deux -# informations qui nous intéressses: -volume_regexp = re.compile("Volume \[SN [0-9a-f]+, Name \(([^)]*)\)\][^\n]*\n[^\n]*\n[^\n]*\n[0-9,-]+ *[0-9]+ *([0-9]+)[^\n]*\n") - -username = "" -password = "" - -# Récupération des identifiants. Cela écrase les deux variables -# username et password: -execfile("/etc/crans/secrets/slon.py") - print u"Connection à la baie de stockage..." -tn = telnetlib.Telnet("slon.adm.crans.org") - -# Identification -tn.read_until("Login: ") -tn.write(username + "\r\n") -tn.read_until("Password: ") -tn.write(password + "\r\n") - -# Ça c'est pour attendre la l'invite de commande: -tn.read_until("#") +slon = slonlib.Slon() print u"Récupération des informations..." -tn.write("show volume-maps" + "\r\n") -resp = "" -# Lecture de la réponse, c'est terminé quand on atteint un nouveau -# prompt: -while resp.find("#") < 0: - resp = resp + tn.read_some() - # Parfois le serveur attend que l'on appuie sur une touche pour - # continuer à envoyer les données: - if resp.endswith("Press any key to continue (Q to quit)"): - tn.write(" ") +map = slon.volume_map().items() +map.sort() print u"Déconnection..." -tn.write("exit\r\n") -tn.read_all() -tn.close() - -# On retire les messages parasites -junk = re.compile("Press any key to continue \(Q to quit\)\x0d *\x0d") -resp = junk.sub("", resp) - -# Parsing de la réponse -map = [] -for m in volume_regexp.finditer(resp): - map.append((int(m.group(2)), m.group(1))) -map.sort() +slon.logout() print u"Enregistrement des informations..." diff --git a/gestion/iscsi/slonlib.py b/gestion/iscsi/slonlib.py new file mode 100755 index 00000000..6312656a --- /dev/null +++ b/gestion/iscsi/slonlib.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# slonlib.py +# ---------- +# Copyright : (c) 2008, Jeremie Dimino +# Licence : BSD3 + +u'''Librairie pour accéder à la baie de stockage''' + +import telnetlib, re + +# Message envoyé par le serveur pour attendre l'appuie sur touche +junk_regexp = re.compile("Press any key to continue \(Q to quit\)\r *\r") + +# Matching des fin de lignes avec \r\n +crlf_regexp = re.compile("\r\n") + +username = "" +password = "" + +# Récupére des identifiants +execfile("/etc/crans/secrets/slon.py") + +# La réponse à la commande "show volume-maps" est une séquence +# d'éléments de la forme: +# +# nom du volume +# | +# v +# > Volume [SN 00c0ffd5e51800004ca1454901000000, Name (o2_slash)] mapping view: +# > CH ID LUN Access Host-Port-Identifier Nickname +# > ------------------------------------------------------------------------------- +# > 0,1 0 4 rw all other hosts +# ^ +# | +# lun +# +# On utilise cette expression un peu barbare pour récupérer les deux +# informations qui nous intéressses: +volume_map_regexp = re.compile("Volume \[SN [0-9a-f]+, Name \(([^)]*)\)\][^\n]*\n[^\n]*\n[^\n]*\n[0-9,-]+ *[0-9]+ *([0-9]+)[^\n]*\n") + +class Slon: + u'''Object représentant la baie de stockage''' + + def __init__(self, host="slon.adm.crans.org"): + self.tn = telnetlib.Telnet(host) + + # Identification + self.tn.read_until("Login: ") + self.tn.write(username + "\r\n") + self.tn.read_until("Password: ") + self.tn.write(password + "\r\n") + + # Ça c'est pour attendre l'invite de commande initiale: + self.tn.read_until("# ") + + # On met un nombre de lignes le plus élévé possible pour + # éviter que le serveur ne se mette en attente de l'appuie sur + # une touche + self.cmd("stty rows 32767") + # Au delà de cette valeur il y a un overflow + + def logout(self): + u'''Déconnexion de la baie''' + self.tn.write("exit\r\n") + self.tn.read_all() + self.tn.close() + + def cmd(self, cmd): + u'''Exécute une commande et renvoie le résultat. Lance + l'exception Error si la commande échoue''' + self.tn.write(cmd + "\r\n") + resp = "" + # Lecture de la réponse, c'est terminé quand on atteint un + # nouveau prompt: + while not resp.endswith("# "): + resp = resp + self.tn.read_some() + # Parfois le serveur attend que l'on appuie sur une touche + # pour continuer à envoyer les données: + if resp.endswith("Press any key to continue (Q to quit)"): + self.tn.write(" ") + + # On retire les messages parasites + resp = junk_regexp.sub("", resp) + + # On retire le prompt + [resp, _] = resp.rsplit("\r\n", 1) + + # Remplace les fins de ligne dos pas des fin de lignes unix + resp = crlf_regexp.sub("\n", resp) + + return resp + + def volume_map(self): + u'''Retourne le mapping lun<->nom de volume''' + map = {} + for m in volume_map_regexp.finditer(self.cmd("show volume-maps")): + map[int(m.group(2))] = m.group(1) + return map +