diff --git a/gestion/iscsi/nols-get-volume-mapping.py b/gestion/iscsi/nols-get-volume-mapping.py new file mode 100755 index 00000000..9f57d45a --- /dev/null +++ b/gestion/iscsi/nols-get-volume-mapping.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# nols-get-volume-mapping.py +# -------------------------- +# Qui taper si ça marche pas : Pierre-Elliott Bécue +# Merci à : Jérémie Dimino , je n'ai fait que s/slon/nols/ sur ce script. +# Licence : BSD3 + +u'''Outil pour récupérer le mapping lun/volume depuis la baie de +stockage''' + +import nolslib, re, sys + +sys.path.append("/usr/scripts/gestion") +from config import ISCSI_MAP_FILE +import affich_tools + +print u"Connexion à la baie de stockage..." + +nols = nolslib.Nols() + +print u"Récupération des informations..." + +map = nols.volume_map().items() +map.sort() + +print u"Déconnexion..." + +nols.logout() + +print u"Enregistrement des informations..." + +f = open(ISCSI_MAP_FILE, "w") +f.write((u"""\ +# -*- coding: utf-8 -*- +# Fichier de mapping lun -> nom de volume +# +# Ce fichier est généré par %s + +map = { +""" % sys.argv[0]).encode("UTF-8")) + +for lun, name in map: + f.write(' %d : "%s",\n' % (lun, name)) + +f.write("}\n") + +f.close() + +print u"Terminé, mapping enregistré dans %s" % ISCSI_MAP_FILE + +print u"Le mapping actuel est:" +print affich_tools.tableau(titre = ["lun", "nom"], data = map, alignement = ["g", "c"]) diff --git a/gestion/iscsi/nolslib.py b/gestion/iscsi/nolslib.py new file mode 100755 index 00000000..05150c01 --- /dev/null +++ b/gestion/iscsi/nolslib.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# baie_lib.py +# ---------- +# Type à taper si ça chie : Pierre-Elliott Bécue +# Licence : WTFPL + +'''Bibliothèque pour accéder à la baie de stockage nols, récupère les données +formatées en XML''' + +import telnetlib, 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") + +# 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/nols.py") + +class Nols(object): + '''Objet représentant la baie de stockage''' + + def __init__(self, host="nols.adm.crans.org"): + self.tn = telnetlib.Telnet(host) + + # Identification + self.tn.expect(["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 veut des sorties en XML + self.cmd("set cli-parameters api-embed") + + # On se débarasse des "appuie sur un bouton pour voir la suite" + self.cmd("set cli-parameters pager off") + + def logout(self): + '''Déconnexion de la baie''' + self.tn.write("exit\r\n") + self.tn.read_all() + self.tn.close() + 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, 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 api-embed\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: + resp = self.tn.read_until("# ") + + # 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 par des fin de lignes unix + resp = crlf_regexp.sub("\n", resp) + return resp + + def show(self, what): + '''Raccourci pour: print slon.cmd("show ")''' + print self.cmd("show " + what) + + def help(self, what = ""): + '''Raccourci pour: print slon.cmd("help ")''' + print self.cmd("help " + what) + + def volume_map(self): + '''Retourne le mapping lun<->nom de volume''' + map = {} + XML_map = self.cmd("show volume-map", mode="XML") + root = fromstring(XML_map) + tree = ElementTree(root) + Objects = tree.findall("OBJECT[@name='volume-view']") + for Object in Objects: + name = Object.findall("PROPERTY[@name='volume-name']")[0].text + lun = Object.findall("OBJECT/PROPERTY[@name='lun']")[0].text + if lun is None: + pass + else: + map[int(lun)] = name + return map + + def create_volume(self, name, size, unit="GiB", vdisk="VD1"): + '''Crée un nouveau volume. Retourne le lun sur lequel il est + mappé. L'unité doit être "B", "K(i)B", "M(i)B", "G(i)B" ou T(i)B. + Par défault l'unité est le giga octet binaire : Gib.''' + + # On récupère le mapping pour chercher un lun de libre + map = self.volume_map() + lun = 0 + while lun in map: lun = lun + 1 + + # Création du volume + self.cmd("create volume vdisk %s size %d%s lun %d %s" % (vdisk, size, unit, lun, name)) + + return "Le volume %s a été créé, son numéri d'identification est %d" %(name, lun) + + def delete_volume(self, name): + '''Supprime un volume''' + + self.cmd("delete volume %s" % (name)) + + def expand_volume(self, name, size, unit="GiB"): + '''Permet d'étendre un volume, la taille par défaut est le giga octet + binaire (GiB), les unités possibles sont B, K(i)B, M(i)B, G(i)B, T(i)B.''' + + self.cmd("expand volume size %d%s %s" % (size, unit, name)) + + def rename_volume(self, origin_name, new_name): + '''Renomme un volume.''' + + self.cmd("set volume name %s %s" % (new_name, orig_name)) diff --git a/gestion/iscsi/update.sh b/gestion/iscsi/update.sh index 2ae0c966..dc6963b5 100644 --- a/gestion/iscsi/update.sh +++ b/gestion/iscsi/update.sh @@ -5,7 +5,7 @@ # Copyright : (c) 2008, Jeremie Dimino # Licence : BSD3 -# Ce script fait tous ce qu'il faut après l'ajout d'un volume sur la +# Ce script fait tout ce qu'il faut après l'ajout d'un volume sur la # baie de stockage. exec_cmd() { @@ -27,7 +27,7 @@ exec_cmd() { } exec_cmd "Récupération du mapping lun<->nom de volume" \ - python /usr/scripts/gestion/iscsi/slon-get-volume-mapping.py + python /usr/scripts/gestion/iscsi/nols-get-volume-mapping.py exec_cmd "Rechargement des règles de udev" \ invoke-rc.d udev reload