scripts/gestion/iscsi/nolslib.py
Pierre-Elliott Bécue 827df964b3 [Iscsi] Corrections
Ignore-this: 3d4ab27e27be2f1f6c282b2a727509f6

darcs-hash:20120903224513-b6762-e8805dd1aadfe9d0fa131764323bdaa339abea17.gz
2012-09-04 00:45:13 +02:00

173 lines
5.8 KiB
Python
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# baie_lib.py
# ----------
# Type à taper si ça chie : Pierre-Elliott Bécue <peb@crans.org>
# 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 <what>")'''
print self.cmd("show " + what)
def help(self, what = ""):
'''Raccourci pour: print slon.cmd("help <what>")'''
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)
## Cf juste en dessous
Objects = tree.findall("OBJECT")
#Objects = tree.findall("OBJECT[@name='volume-view']")
## Fin cf juste en dessous
for Object in Objects:
name = None
lun = None
# Quand on passera à wheezy, décommenter ces lignes, et virer
# la merde que j'ai fait juste après.
#name = Object.findall("PROPERTY[@name='volume-name']")[0].text
#lun = Object.findall("OBJECT/PROPERTY[@name='lun']")[0].text
######## Début merde que j'ai faite juste après ###########
if not (Object.attrib['name'] == "volume-view"):
pass
properties = Object.findall("PROPERTY")
for property in properties:
if property.attrib['name'] == "volume-name":
name = property.text
else:
pass
subObjects = Object.findall("OBJECT")
for subObject in subObjects:
properties = subObject.findall("PROPERTY")
for property in properties:
if property.attrib['name'] == "lun":
lun = property.text
else:
pass
####### Fin merde que j'ai faite juste après #############
if lun is None:
pass
else:
map[int(lun)] = name
return map
def create_volume(self, name, size, unit="GiB", vdisk="slon1"):
'''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))
print "Le volume %s a été créé, son numéro 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))