diff --git a/gestion/iscsi/slonlib.py b/gestion/iscsi/slonlib.py index c4c29bef..c89d7afc 100644 --- a/gestion/iscsi/slonlib.py +++ b/gestion/iscsi/slonlib.py @@ -8,7 +8,9 @@ '''Bibliothèque pour accéder à la baie de stockage''' -import telnetlib, re +import telnetlib +import re +from xml.etree.ElementTree import ElementTree, fromstring # 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") @@ -58,7 +60,7 @@ class Slon(object): # 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") + self.cmd("set cli-parameters pager off") # Au delà de cette valeur il y a un overflow def logout(self): @@ -69,28 +71,38 @@ class Slon(object): print ("Si vous avez effectué des modifications pensez à exécuter:\n" + "/usr/scripts/gestion/iscsi/update.sh sur chacun des dom0\n") - def cmd(self, cmd): - '''Exécute une commande et renvoie le résultat. Lance + def cmd(self, cmd, mode='text'): + '''Exécute une commande et renvoie le résultat. Lève l'exception Error si la commande échoue''' + + # Si c'est le script qui bosse, on utilise le mode XML, sinon + # on peut aussi lancer des commandes en mode texte + if mode == 'XML': + self.tn.write("set cli-parameters xml\r\n") + self.tn.read_until("# ") + else: + self.tn.write("set cli-parameters console\r\n") + self.tn.read_until("# ") + 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(" ") + resp = self.tn.read_until("# ") - # On retire les messages parasites + # On retire les messages parasites s'il en reste par hasard resp = junk_regexp.sub("", resp) + # On vire la commande qui est là et dont on veut pas + [_, resp] = resp.split(cmd+"\r\n", 1) + # On retire le prompt [resp, _] = resp.rsplit("\r\n", 1) - # Remplace les fins de ligne dos pas des fin de lignes unix + # Remplace les fins de ligne dos par des fin de lignes unix resp = crlf_regexp.sub("\n", resp) + if resp.lower().startswith("error"): + raise NolsError(resp.replace("Error: ", "")) return resp @@ -105,11 +117,27 @@ class Slon(object): def volume_map(self): '''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) + XML_map = self.cmd("show volume-maps", mode="XML") + root = fromstring(XML_map) + tree = ElementTree(root) + + # XML c'est trobyien + tree = tree.findall("volume-view")[0] + Objects = tree.findall("volume_view") + + for Object in Objects: + name = None + lun = None + name = Object.findall("volume_name")[0].text + lun = Object.findall("lun")[0].text + + if lun is None: + pass + else: + map[int(lun)] = name return map - def create_volume(self, name, size, unit="GB", vdisk="slon1"): + def create_volume(self, name, size, unit="GB", vdisk="slon2"): '''Créé un nouveau volume. Retourne le lun sur lequel il est mappé. La taille est en Giga-octet. L'unité doit être "KB", "MB" ou "GB". Par défault c'est "GB".'''