scripts/gestion/ressuscite.py
Michel Blockelet af7894e07e [ressuscite.py] Ajout barre de progression
Ignore-this: 28cbb12fb3cd3279dfe38cb8f9e817c9
On s'ennuie pendant qu'il cherche

darcs-hash:20111116121012-ddb99-401cce478dd0eb5762a9e64c865446f5b98006b9.gz
2011-11-16 13:10:12 +01:00

538 lines
20 KiB
Python

#!/usr/bin/env python
# -*- mode: python; coding: utf-8 -*-
#
# ressuscite.py
# -------------
#
# Copyright (C) 2008 Michel Blockelet <blockelet@crans.org>
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
u"""Outil pour ressusciter des objets du cimetière."""
import os, sys
import cPickle
import dialog
import time, pwd, ldap, ldap.modlist, random
from time import mktime, strptime
sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, MachineFixe, MachineWifi, Adherent, Club, date_format
from gest_crans import select, set_machine
from whos import aff
import affich_tools
import user_tests
db = crans_ldap()
isadm = user_tests.isadm()
cur_user = os.getenv('SUDO_USER') or pwd.getpwuid(os.getuid())[0]
dlg = dialog.Dialog()
dlg.setBackgroundTitle('Ressusciter une machine')
def menu_principal():
"""Menu principal de l'interface."""
choix = ''
while 1:
annul, choix = dlg.menu(u"Que souhaitez vous faire ?",
choices=[("A",u"Ressusciter à partir d'un adhérent",u"Rechercher les anciennes machines d'un adhérent"),
("D",u"Ressusciter à partir de la date",u"Rechercher à partir de la date de suppression de la machine"),
("F",u"Ressusciter à partir d'un fichier",u"Récupérer depuis un fichier du cimetière"),
("C",u"Ressusciter un adhérent",u"Ressusciter un adhérent depuis un fichier du cimetière"),
("K",u"Ressusciter un club",u"Ressusciter un club depuis un fichier du cimetière"),
],
item_help=1,title=u"Ressusciter")
if annul: break
if choix == 'A':
# Ressusciter à partir d'un adhérent
# On sélectionne l'adhérent
adh = select(db, u'Adhérent duquel rechercher les anciennes machines a', mde='ro')
if not adh: continue
# Est-ce que c'est bien une machine de l'adhérent ?
def condition(machine, date):
return (int(machine.dn.split(',', 3)[1].split('=', 2)[1])
== int(adh.id()) and str(machine.proprio) == ("%s %s"
% (adh.prenom(), adh.nom())))
choixmachine = choixrecherche(condition)
if choixmachine != None:
(machine, date) = choixmachine
adh = choixadherent(machine, adh)
if not adh: continue
ressuscite(adh, machine)
elif choix == 'D':
# Ressusciter à partir de la date
while 1:
debut = None
fin = None
annul, result = dlg.inputbox(width=54, height=10,
text=u"Entrez la plage de dates de recherche au format\nJJ/MM/AAAA:JJ/MM/AAAA :\n(Une des deux dates peut ne pas être spécifiée.)\n",
title=u"Sélection des dates")
if annul: break
try:
[strdebut, strfin] = result.strip().split(':', 1)
# On teste la validité des dates
# (strptime émet une erreur si le format est mauvais)
if len(strdebut) > 0:
debut = mktime(strptime(strdebut, '%d/%m/%Y'))
if len(strfin) > 0:
fin = mktime(strptime(strfin, '%d/%m/%Y')) + 24*60*60
break
except:
dlg.msgbox(text=u"Dates invalides",title=u"Sélection des dates")
continue
# On ne fait la recherche que si on a spécifié une date
# (c'est mieux de ne pas instancier en mémoire toutes les machines)
if debut != None or fin != None:
def condition(machine, date):
ok = True
unixdate = mktime(strptime(date, '%Y-%m-%d-%H:%M'))
if debut != None: ok = (unixdate >= debut)
if fin != None: ok = ok and (unixdate <= fin)
return ok
choixmachine = choixrecherche(condition)
if choixmachine != None:
(machine, date) = choixmachine
adh = choixadherent(machine)
if not adh: continue
ressuscite(adh, machine)
elif choix == 'F':
# Ressusciter à partir d'un fichier
fichier = None
while 1:
annul, result = dlg.inputbox(width=54, height=12,
text=u"Vous pouvez aussi exécuter le script sur le fichier\nressuscite [le fichier]\n\nFichier : ",
init=u"/home/cimetiere/Machine",
title=u"Sélection du fichier")
if annul: break
try:
fichier = open(result, 'r')
break
except:
dlg.msgbox(text=u"Fichier invalide",title=u"Sélection du fichier")
continue
if fichier != None:
machine = cPickle.load(fichier)
adh = choixadherent(machine)
if not adh: continue
ressuscite(adh, machine)
elif choix == 'C':
# Ressusciter à partir d'un fichier
fichier = None
while 1:
annul, result = dlg.inputbox(width=54, height=12,
text=u"Vous pourrez peut-être aussi exécuter le script sur le fichier\nressuscite [le fichier]\n\nFichier : ",
init=u"/home/cimetiere/Adherent",
title=u"Sélection du fichier")
if annul: break
try:
fichier = open(result, 'r')
break
except:
dlg.msgbox(text=u"Fichier invalide",title=u"Sélection du fichier")
continue
if fichier != None:
adh = cPickle.load(fichier)
if not adh: continue
ressuscite_adherent(adh)
elif choix == 'K':
# Ressusciter à partir d'un fichier
fichier = None
while 1:
annul, result = dlg.inputbox(width=54, height=12,
text=u"Vous pourrez peut-être aussi exécuter le script sur le fichier\nressuscite [le fichier]\n\nFichier : ",
init=u"/home/cimetiere/Club",
title=u"Sélection du fichier")
if annul: break
try:
fichier = open(result, 'r')
break
except:
dlg.msgbox(text=u"Fichier invalide",title=u"Sélection du fichier")
continue
if fichier != None:
club = cPickle.load(fichier)
if not club: continue
ressuscite_club(club)
continue
def choixrecherche(condition=None):
"""Demande les types de machines à chercher, et effectue la recherche avec
la condition."""
# On sélectionne le type de machine
annul, choix = dlg.menu(u"Type de machine ?",
choices=[("Fixe",u"Machine fixe"),
("Wifi",u"Machine wireless"),
("Tous",u"Rechercher les deux types")],
title=u"Recherche de machine")
if annul: return None
# On cherche les machines
machines = recherche(dlg,
choix == 'Fixe' or choix == 'Tous',
choix == 'Wifi' or choix == 'Tous',
condition)
# Pas de résultat
if not machines:
dlg.msgbox(text=u"Aucun résultat",title=u"Recherche")
return None
return choixmachine(machines)
def recherche(dlg, fixe=False, wifi=False, condition=None):
"""Recherche des machines du type demandé, et satisfaisant une condition :
la fonction condition doit être de la forme
condition(machine, date)
et retourner True ou False selon si l'on veut avoir la machine dans la
liste ou non."""
# Liste des fichiers à lire
cimetiere = []
if fixe: cimetiere = map(lambda s: "/home/cimetiere/MachineFixe/" + s,
os.listdir("/home/cimetiere/MachineFixe"))
if wifi: cimetiere += map(lambda s: "/home/cimetiere/MachineWifi/" + s,
os.listdir("/home/cimetiere/MachineWifi"))
# On regarde chacun des fichiers
valid = []
done = 0
dlg.gauge_start(text="Recherche en cours...")
for fichier in cimetiere:
try:
machine = cPickle.load(open(fichier, 'r'))
date = fichier[28:44]
if condition == None or condition(machine, date):
valid.append((machine, date))
except:
pass
done += 1
dlg.gauge_update(int(done*100/len(cimetiere)))
dlg.gauge_stop()
return valid
def choixadherent(machine, oldadh=None):
"""Permet de choisir l'adhérent à qui rattacher la machine."""
if oldadh == None:
oldadhl = db.search(machine.dn.split(',', 2)[1])['adherent']
if not oldadhl:
oldadhl = db.search(machine.dn.split(',', 2)[1])['club']
else:
oldadhl = [oldadh]
arg = u'--title "" '
arg += u'--menu "%s.' % machine.proprio
# Est-ce que l'adhérent existe encore ?
if (len(oldadhl) > 0 and machine.proprio == oldadhl[0].Nom()):
annul, choix = dlg.menu(u"Le propriétaire de la machine est %s" % machine.proprio,
choices=[("Garder",u"Ajouter à cet adhérent"),
("Autre",u"Ajouter à un autre adhérent")],
title=u"Adhérent auquel rattacher la machine")
annul = False
choix = "Garder"
else:
annul, choix = dlg.menu(u"Cet adhérent n'existe plus dans la base.",
choices=[("Autre",u"Ajouter à un autre adhérent")],
title=u"Adhérent auquel rattacher la machine")
if not annul:
if choix == "Garder":
adh = oldadhl[0]
else:
adh = select(db, u'Adhérent auquel ajouter la machine a', mde='ro')
else:
adh = None
return adh
def choixmachine(valid):
"""Choisit une machine dans une liste."""
# Pas de machines !
if len(valid) == 1:
# Une seule réponse
choix = valid[0]
else:
# Il faut choisir
while 1:
os.system('clear')
choix = None
print "Plusieurs réponses correspondant à votre requête ont été trouvées :"
data = []
i = 1
for (machine, date) in valid:
data.append([i, date, str(machine.__class__)[-4:], machine.nom().split('.', 1)[0], machine.mac()])
i += 1
print affich_tools.tableau(data,
titre=[u'id', u'Date destruction', u'Type', u'Nom de machine', u'Adresse MAC'],
largeur=[5, 16, 4, '*', 17],
alignement=['d', 'c', 'c', 'c', 'c'])
i = affich_tools.prompt(u'Votre choix ? (0 pour annuler) id =')
try:
i = int(i)
except:
print 'Choix invalide'
continue
if i == 0: break
if i > len(valid):
print 'Choix invalide'
continue
choix = valid[i-1]
if choix: break
if not choix:
# Retour à l'interface de recherche
return None
return choix
def ressuscite(adh, oldmachine):
"""Ressuscite une instance de machine."""
# On regarde quel type de machine c'était
if str(oldmachine.__class__)[-4:] == 'Fixe':
strmachine = u"Cette machine était une machine Fixe."
strdef = 'Fixe'
elif str(oldmachine.__class__)[-4:] == 'Wifi':
strmachine = u"Cette machine était une machine Wifi."
strdef = 'Wifi'
else:
strmachine = u"L'ancien type de cette machine est inconnu ..."
strdef = ''
# Certaines fois, on peut vouloir transformer une machine Fixe en Wifi,
# et inversement (erreurs d'ajout ...)
annul, choix = dlg.menu(strmachine,
choices=[("Fixe",u"Ressusciter en tant que machine Fixe"),
("Wifi",u"Ressusciter en tant que machine Wifi")],
default_item=strdef,
title=u"Nouveau type de machine")
if annul: return False
if choix == 'Fixe':
machine = MachineFixe(adh)
elif choix == 'Wifi':
machine = MachineWifi(adh)
err = ""
# On remet le nom
try: machine.nom(str(oldmachine.nom()))
except ValueError, c: err += c.args[0] + '\n'
except EnvironmentError, c: err += c.args[0] + '\n'
# On remet la MAC
try: machine.mac(str(oldmachine.mac()))
except ValueError, c:
if len(c.args)>1 and c.args[1] == 1 and isadm:
# Mac en double
no, res = dlg.yesno(text=u"L'adresse MAC existe déjà, continuer ?", title=u"Adresse MAC")
if not no:
try: machine.mac(str(oldmachine.mac()), 1)
except ValueError, c: err += c.args[0] + '\n'
except EnvironmentError, c: err += c.args[0] + '\n'
elif len(c.args)>1 and c.args[1] == 3 and isadm:
# Mac douteuse
no, res = dlg.yesno(text=u"L\'adresse MAC ne correspond à aucun constructeur, continuer ?",
title=u"Adresse MAC")
if not no:
try: machine.mac(str(oldmachine.mac()), 1)
except ValueError, c: err += c.args[0] + '\n'
except EnvironmentError, c: err += c.args[0] + '\n'
else:
err += c.args[0] + '\n'
except EnvironmentError, c: err += c.args[0] + '\n'
# On met une IP automatique
try: machine.ip('<automatique>')
except ValueError, c: err += c.args[0] + '\n'
except EnvironmentError, c: err += c.args[0] + '\n'
except RuntimeError, c: err += c.args[0] + '\n'
# Des erreurs ?
if err:
dlg.msgbox(text=u"%s" % err,title=u"Paramètres machine")
set_machine(machine)
return True
def ressuscite_adherent(old):
"""Ressuscite une instance d'adhérent"""
if not isinstance(old, Adherent):
dlg.msgbox(text=u"Ceci n'est pas un adhérent !",
title=u"Mauvais type d'objet")
return
if not isadm:
dlg.msgbox(text=u"Vous devez être nounou !",
title=u"Droits insuffisants")
return
# On contourne ldap_crans
data = old._data
# Ajout d'une entrée dans l'historique
timestamp = time.localtime()
hist = "%s, %s : " % (time.strftime(date_format, timestamp), cur_user)
hist += "resurrection"
data['historique'].append(hist)
# Entrées à vérifier :
# aid, canonicalAlias, homeDirectory, mail, mailAlias, uid, uidNumber
# On recherche les aid/uidNumber pris
used_aid = [0]
used_uidNumber = [0]
for r in db.conn.search_s(Adherent.base_dn, 1, Adherent.filtre_idn):
# r = ( dn, {} )
d = r[1]
if d.has_key('aid'):
used_aid.append(int(d['aid'][0]))
if d.has_key('uidNumber'):
used_uidNumber.append(int(d['uidNumber'][0]))
# Nouvelle valeur pour aid (peut mieux faire)
aid = max(used_aid) + random.randint(1, 10)
data['aid'] = [str(aid)]
dn = 'aid=%d,ou=data,dc=crans,dc=org' % aid
if 'posixAccount' in data['objectClass']:
# L'adhérent avait un compte, il faut changer/vérifier ses attributs
uidNumber = max(used_uidNumber) + random.randint(1, 10)
data['uidNumber'] = [str(uidNumber)]
# Disponibilité du login (vérification sommaire)
login = data['uid'][0]
if os.path.exists("/home/" + login):
no = dlg.yesno(text=u"Le compte %s existe déjà, continuer ?" % login,
title=u"Compte existant")
if no:
return
if True:
# On croise les doigts
try:
modlist = ldap.modlist.addModlist(data)
db.conn.add_s(dn, modlist)
dlg.msgbox(text=u"Résurrection effectée ! Veuillez maintenant restaurer le home et les mails",
title=u"Fin")
# Au cas où l'adhérent avait des droits
db.services_to_restart('droits')
# On notifie après une résurrection
db.services_to_restart('mail_modif', ['uid=' + login])
except Exception, e:
dlg.msgbox(text=unicode(e), title=u"Erreur")
else:
print data
raise ValueError("debug")
def ressuscite_club(old):
"""Ressuscite une instance d'un club"""
if not isinstance(old, Club):
dlg.msgbox(text=u"Ceci n'est pas un club !",
title=u"Mauvais type d'objet")
return
if not isadm:
dlg.msgbox(text=u"Vous devez être nounou !",
title=u"Droits insuffisants")
return
# On contourne ldap_crans
data = old._data
# Ajout d'une entrée dans l'historique
timestamp = time.localtime()
hist = "%s, %s : " % (time.strftime(date_format, timestamp), cur_user)
hist += "resurrection"
data['historique'].append(hist)
# Entrées à vérifier :
# aid, canonicalAlias, homeDirectory, mail, mailAlias, uid, uidNumber
# On recherche les aid/uidNumber pris
used_cid = [0]
used_uidNumber = [0]
for r in db.conn.search_s(Club.base_dn, 1, Club.filtre_idn):
# r = ( dn, {} )
d = r[1]
if d.has_key('cid'):
used_cid.append(int(d['cid'][0]))
if d.has_key('uidNumber'):
used_uidNumber.append(int(d['uidNumber'][0]))
# Nouvelle valeur pour cid (peut mieux faire)
cid = max(used_cid) + random.randint(1, 10)
data['cid'] = [str(cid)]
dn = 'cid=%d,ou=data,dc=crans,dc=org' % cid
if 'posixAccount' in data['objectClass']:
# L'adhérent avait un compte, il faut changer/vérifier ses attributs
uidNumber = max(used_uidNumber) + random.randint(1, 10)
data['uidNumber'] = [str(uidNumber)]
# Disponibilité du login (vérification sommaire)
login = data['uid'][0]
if os.path.exists("/home/" + login):
no = dlg.yesno(text=u"Le compte %s existe déjà, continuer ?" % login,
title=u"Compte existant")
if no:
return
if True:
# On croise les doigts
try:
modlist = ldap.modlist.addModlist(data)
db.conn.add_s(dn, modlist)
dlg.msgbox(text=u"Résurrection effectée ! Veuillez maintenant restaurer le home et les mails",
title=u"Fin")
# Au cas où l'adhérent avait des droits
db.services_to_restart('droits')
# On notifie après une résurrection
db.services_to_restart('mail_modif', ['uid=' + login])
except Exception, e:
dlg.msgbox(text=unicode(e), title=u"Erreur")
else:
print data
raise ValueError("debug")
if __name__ == '__main__':
if len(sys.argv) < 2:
menu_principal()
os.system("clear")
else:
for path in sys.argv[1:]:
fichier = open(path, 'r')
machine = cPickle.load(fichier)
adh = choixadherent(machine)
if adh:
ressuscite(adh, machine)