From f6fa9fb896db5db5149a9a61a7fb49a7e45aa3fb Mon Sep 17 00:00:00 2001 From: Daniel STAN Date: Thu, 21 Jun 2012 10:56:45 +0200 Subject: [PATCH] [liberer_ips] ajout du fichier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ignore-this: 400f6467db3efea2f9d2e59828bbde60 Très utile à l'occasion (surtout à la rentrée prochaine, sic) darcs-hash:20120621085645-28565-c43ec933e031ada1a20fdc5f7435750f9c840d27.gz --- gestion/liberer_ips.py | 532 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 532 insertions(+) create mode 100755 gestion/liberer_ips.py diff --git a/gestion/liberer_ips.py b/gestion/liberer_ips.py new file mode 100755 index 00000000..5d66d73d --- /dev/null +++ b/gestion/liberer_ips.py @@ -0,0 +1,532 @@ +#!/usr/bin/env python +# -*- mode: python; coding: utf-8 -*- +# +# liberer_ips.py +# ------------- +# +# Copyright (C) 2011 Michel Blockelet +# +# 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 libérer des adresses IP.""" + +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 +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(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(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 = [] + 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 + 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('') + 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)