scripts/gestion/iscsi/slonlib.py
Antoine Durand-Gasselin 4a68475e34 [wiki-lenny] suppression de static/
darcs-hash:20090314092631-bd074-b01256aeaf71e935851b3ecdbd623eaae8c9e8a1.gz
2009-03-14 10:26:31 +01:00

132 lines
4.3 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# slonlib.py
# ----------
# Copyright : (c) 2008, Jeremie Dimino <jeremie@dimino.org>
# 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 show(self, what):
u'''Raccourci pour: print slon.cmd("show <what>")'''
print self.cmd("show " + what)
def help(self, what):
u'''Raccourci pour: print slon.cmd("help <what>")'''
print self.cmd("help " + what)
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
def create_volume(self, name, size, unit="GB", vdisk="slon1"):
u'''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".'''
# Création du volume
self.cmd("create volume vdisk %s size %d%s %s" % (vdisk, size, unit, name))
# 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
# Mapping du volume
self.cmd("map volume %s lun %d" % (name, lun))
return lun
def delete_volume(self, name):
u'''Supprime un volume'''
self.cmd("delete volume %s")