#! /usr/bin/python3
# -*- coding: utf-8 -*-
###########################################################################
# Eole NG - 2007
# Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
# Licence CeCill  cf /root/LicenceEole.txt
# eole@ac-dijon.fr
#
# enregistrement_zephir
#
# procédure d'enregistrement d'un serveur sur Zéphir
#
###########################################################################
import argparse
import math
from zephir.lib_zephir import *
import ssl, socket
import time,os,sys,shutil,getpass
from creole.config import eoledirs, distrib_dir, dicos_dir
from pyeole.ansiprint import print_red, print_green, print_orange
from creole.client import CreoleClient, NotFoundError
from pyeole.process import system_out, system_code
from pyeole.service import manage_services, unmanaged_service
import importlib

# répertoire publique d'uucp
public_dir = '/var/spool/uucppublic'
migration_ok = 0

# droits permettant l'ajout/édition de serveur
write_perms = set([2, 9, 21])
# droits permettant l'enregistrement d'un serveur
min_perms = set([8])
min_perms.update(write_perms)

creole_client = CreoleClient()
try:
    eole_module = creole_client.get_creole('eole_module')
    eole_version = creole_client.get_creole('eole_release')
except Exception as exc:
    print_red("\nErreur d'accès au service creoled :\n\n")
    print(str(exc))
    exit(1)

# cas particulier, eole 2.4.0 est vue comme eole 2.4 dans Zéphir
if eole_version == "2.4.0":
    eole_version = "2.4"

def socket_error(err_msg):
    """message d'erreur en cas d'erreur de connexion à Zéphir (XMLRPC)
    """
    exit_err("Erreur réseau lors de l'appel au serveur Zéphir : %s" % str(err_msg))

def recup_conf(resultat, id_serveur, zephir_proxy, no_conf=0, conf_saved=0):
    """récupération de la configuration définie sur le serveur Zéphir"""
    if no_conf == 0:
        print ('\n --récupération de la configuration en cours (veuillez patienter)-- ')
    else:
        print ('\n --récupération des patchs et dictionnaires (veuillez patienter)-- ')

    if no_conf == 0:
        file_conf=open("/root/zephir.eol","wb")
        file_conf.write(xmlrpclib.base64.decodebytes(resultat[5].encode()))
        file_conf.close()

    # récupération de la conf complete
    try:
        res = zephir_proxy.uucp.configure(id_serveur)
    except socket.error as e:
        socket_error(e)
    if res[0] == 1:
        system_out(['%s/scripts/zephir_client' % zephir_dir, 'call'])
    else:
        exit_err("Erreur lors de la récupération de la configuration : %s" % res[1])
    # if os.path.exists('/etc/eole/config.eol'):
    if no_conf == 0:
        vars_not_ok=""
        print ("** attente de la mise en place des fichiers **")
        # on attend que les fichiers soient mis en place
        # (timeout de 20 secondes au cas ou la procédure échoue)
        wait = 0
        while wait < 40:
            time.sleep(0.5)
            wait += 1
            if os.path.exists(public_dir+'/config-zephir.tar.ok'):
                wait = 100
        get_paqs_from_logs()
        if wait != 100:
            print_orange("\nUne erreur s'est produite lors de la mise en place de la configuration.\n")
            print_orange("\nLes fichiers suivants peuvent contenir des informations plus détaillées:")
            print("* /tmp/rapport.zephir")
            print("* /var/log/zephir/last_action.log")
            print("* /var/log/zephir/actions.log")
            exit_err("!!  La mise en place de la configuration s'est mal terminée !!")
        else:
            # on vérifie si toutes les variables sont saisies dans zephir.eol
            print ("** Vérification des dictionnaires et de la configuration **\n")
            try:
                from creole.eosfunc import load_funcs
                load_funcs(force_reload=True)
                from creole.loader import creole_loader, config_save_values
                cfg = creole_loader(force_configeol='/root/zephir.eol')
                config_save_values(cfg, 'creole', eol_file='/dev/null')
            except Exception as err:
                vars_not_ok = str(err)

        if vars_not_ok:
            print_red ("\n*******************************************************************")
            print_red ("**   !! Certains paramètres n'ont pas encore été saisis !!       **")
            print_red ("**   Lancez la procédure gen_config pour les renseigner          **")
            print_red ("**   et ré-instancez le serveur                                  **")
            print_red ("**                                                               **")
            print_red ("**   >gen_config                                                 **")
            print_red ("**   >instance                                                   **")
            print_red ("**                                                               **")
            print_red ("*******************************************************************")
            print ("")
            print_orange(vars_not_ok)
            print ("")
            return id_serveur

        if no_conf == 0 and conf_saved == 0:
            # on prévient que la configuration a changé
            print ("**************************************************************************")
            print ("** la configuration du serveur a été récupérée depuis le serveur Zéphir **")
            if not os.path.isfile('/etc/eole/config.eol'):
                print ("** Lancez l'instanciation du serveur à la fin de cette procédure        **")
                print ("**                                                                      **")
                print ("** >instance                                                            **")
            else:
                print ("** Reconfigurez le serveur en fin de procédure                          **")
                print ("** (certaines variables peuvent nécessiter une instance)                **")
                print ("**                                                                      **")
                print ("** > reconfigure                                                        **")
            print ("**                                                                      **")
            print ("** La commande diagnose permet de vérifier l'état du serveur            **")
            print ("**************************************************************************")
            print ("")

        # mise en place automatique de config.eol depuis zephir.eol
        if no_conf == 0 and not os.path.isfile('/etc/eole/config.eol'):
            shutil.copy('/root/zephir.eol', '/etc/eole/config.eol')

    return id_serveur

def save_conf(id_serveur):
    """sauvegarde de la configuration locale sur zephir"""

    print ('\n  -- sauvegarde en cours (veuillez patienter) -- ')
    res = system_code(['%s/scripts/zephir_client' % zephir_dir, 'save_files'])
    if res == 0:
        print_green ('  -- OK --\n')
    else:
        print_orange('\nErreur lors de la remontée de la configuration locale sur Zephir')
        print_orange('voir le fichier /var/log/zephir/last_action.log (actions.log si il est vide)')
        exit_err('Erreur de sauvegarde sur le serveur Zéphir')
    return id_serveur

def msg_no_conf():
    # aucune configuration définie
    print ("**********************************************************************")
    print ("** Pas de configuration définie sur le serveur Zéphir ou localement **")
    print ("** Pour configurer localement le serveur, utilisez:                 **")
    print ("**                                                                  **")
    print ("**   >gen_config                                                    **")
    print ("**   >instance                                                      **")
    print ("**                                                                  **")
    print ("**********************************************************************")
    print ("")


def conf_uucp(zephir_proxy, adresse_zephir, user, user_perms, id_serveur=None, choix_defaut=None, force_enregistrement=False):
    """fonction de mise en place de la configuration UUCP sur un serveur EOLE"""
    force_default = id_serveur is not None
    hw_infos = {}
    migration_ok = 0
    module_local = "%s-%s" % (eole_module, eole_version)
    # on réinitialise le spool uucp
    try:
        shutil.rmtree("/var/spool/uucp/zephir")
    except:
        pass
    # préparation de la configuration ssh (mode clé rsa1)
    if not os.path.isdir("/var/spool/uucp/.ssh/"):
        try:
            os.makedirs("/var/spool/uucp/.ssh/")
        except:
            exit_err("Erreur à la création du répertoire /var/spool/uucp/.ssh/")
    else:
        for old_fic in ['eole', 'eole.pub', 'known_hosts']:
            if os.path.isfile(os.path.join("/var/spool/uucp/.ssh",old_fic)):
                os.unlink(os.path.join("/var/spool/uucp/.ssh",old_fic))
    # récupération de l'uid de l'utilisateur uucp
    result, output, err = system_out(['/usr/bin/id', 'uucp'])
    result = output.split('\n')[0]
    uucp_uid = int(result[result.index('uid=')+4:result.index('(uucp)')])
    # récupération du gid du groupe uucp
    result=result[result.index('gid=')+4:]
    uucp_gid = int(result[:result.index('(uucp)')])
    # mise en place des droits sur le répertoire .ssh d'uucp
    os.chown("/var/spool/uucp/.ssh/",uucp_uid,uucp_gid)
    cmd = ['/bin/chmod', '700', '/var/spool/uucp/.ssh']
    system_code(cmd)

    # génération de la clé rsa
    cmd = ['/usr/sbin/eole-ssh-keygen', '-f', '/var/spool/uucp/.ssh/eole', '-c', '"uucp@%s"' % adresse_zephir]
    result, out, err = system_out(cmd)
    if result == 0:
        # déclaration de la clé dans ssh_config
        with open("/var/spool/uucp/.ssh/config", "w") as ssh_config_fh:
            ssh_config_fh.write('\n'.join([
                'Host *',
                '\tIdentityFile ~/.ssh/eole']))
        # mise en place des droits
        os.chown("/var/spool/uucp/.ssh/eole",uucp_uid,uucp_gid)
        os.chown("/var/spool/uucp/.ssh/eole.pub",uucp_uid,uucp_gid)
        os.chown("/var/spool/uucp/.ssh/config",uucp_uid,uucp_gid)
        cmd = ['/bin/chmod', '600', '/var/spool/uucp/.ssh/eole']
        system_code(cmd)
        # lecture de la cle
        fic_cle=open("/var/spool/uucp/.ssh/eole.pub","r")
        cle_pub=fic_cle.readlines()[0]
        fic_cle.close()
        # on demande si le serveur existe déjà :
        if not force_default and write_perms.intersection(set(user_perms)):
            saisie_serveur = ""
            while saisie_serveur.upper() not in ['O','N','OUI','NON']:
                saisie_serveur = input('\ncréer le serveur dans la base du serveur Zéphir (O/N) : ')
        else:
            # Pas de droit en écriture: serveur existant seulement
            saisie_serveur = "NON"
        if saisie_serveur.upper().startswith('N'):
            print("\n** utilisation d'un serveur existant dans la base du serveur Zéphir **\n")
            id_ok = 0
            while id_ok != 1:
                res=[1,[]]
                if not force_default:
                    while res[1] == []:
                        print ("entrez le RNE de l'établissement correspondant au serveur")
                        id_rne = saisie("etablissement","""(rien pour saisir directement un n° de serveur)""")
                        if id_rne != "":
                            # recherche de l'établissement
                            try:
                                res = convert(zephir_proxy.etabs.get_etab(u(id_rne)))
                            except xmlrpclib.ProtocolError:
                                exit_err("Vous n'êtes pas autorisé à accéder à ces données")
                            except socket.error as e:
                                socket_error(e)
                            if res[0]==0:
                                exit_err("Erreur lors de la recherche de l'établissement %s" % str(res[1]))
                            if res[1]==[]:
                                print_red ("\n** Établissement inexistant dans la base du serveur Zéphir **\n\n")
                            else:
                                # on récupère le rne de la base pour éviter les pb de casse
                                id_rne = res[1][0]['rne']
                                nom_etab = '%s (%s)' % (res[1][0]['libelle'], res[1][0]['ville'])
                            # affichage des serveur correspondants
                            try:
                                res =  convert(zephir_proxy.serveurs.serveurs_etab(id_rne))
                            except xmlrpclib.ProtocolError:
                                exit_err("Vous n'êtes pas autorisé à accéder à ces données")
                            except socket.error as e:
                                socket_error(e)
                            if res[0]==0:
                                exit_err("Erreur lors de la recherche des serveurs de l'établissement %s" % id_rne)
                            if len(res[1]) != 0:
                                print("\n Serveurs de l'établissement %s : \n" % (nom_etab))
                                for serv in res[1]:
                                    print(" %s - %s" % (serv['id'], serv['libelle']))
                                print("\n")
                        else:
                            # pas de RNE demandé, on passe à la saisie directe du n° de serveur
                            break

                    id_serveur = saisie("id_serveur","entrez le n° identifiant le serveur l'application Zéphir")
                    print("\n")
                # on vérifie que le module correspond
                try:
                    id_serveur = int(id_serveur)
                    etat_serveur = convert(zephir_proxy.serveurs.get_status(id_serveur))
                    data_serveur = convert(zephir_proxy.serveurs.get_serveur(id_serveur))[1][0]
                except xmlrpclib.ProtocolError:
                    exit_err("Vous n'êtes pas autorisé à effectuer cette opération !")
                except socket.error as e:
                    socket_error(e)
                except ValueError:
                    print_red ("  l'identifiant doit être un nombre entier \n")
                except:
                    print_red ("\n!! serveur inconnu !!\n\n")
                else:
                    id_module = data_serveur['module_actuel']
                    try:
                        timeout = int(data_serveur['timeout'])
                    except:
                        timeout = 1800
                    # infos sur les modules dans zephir (id, libelle)
                    nom_module = None
                    id_mod_actuel = None
                    try:
                        modules = convert(zephir_proxy.modules.get_module())[1]
                    except xmlrpclib.ProtocolError:
                        exit_err("Vous n'êtes pas autorisé à accéder à ces données")
                    except socket.error as e:
                        socket_error(e)
                    for mod in modules:
                        if mod['id'] == id_module:
                            nom_module = mod['libelle']
                            version_module = mod['version']
                        if mod['libelle'] == module_local:
                            id_mod_actuel = mod['id']
                            version_mod_actuel = mod['version']
                    if id_mod_actuel is None:
                        exit_err("""!! Le module %s n'est pas connu dans la base de l'application Zéphir !!""" % module_local)
                    # récupération des infos matérielles au cas où le serveur serait remplacé
                    print("""\nVérification des informations sur le matériel\n""")
                    defaults.update(scan_hardware({}))
                    # on alerte si il ne correspond pas
                    if nom_module.upper() != module_local.upper():
                        rep=""
                        print_orange ("!! Vous êtes actuellement sur un module %s !!" % module_local)
                        while rep.upper() not in ["O","N","OUI","NON"]:
                            # cas particulier migration d'un serveur Eole1 -> EoleNG, ou upgrade Eole2.X -> Eole2.X+1
                            if nom_module.upper().split('-')[:-1] == module_local.upper().split('-')[:-1]:
                                # Vérification de la commpatibilité des versions
                                # on interdit l'upgrade avec plus d'une version d'écart
                                if (version_mod_actuel > version_module) or version_module == 1:
                                    rep = input("\nLe module du serveur choisi est %s, \n\nVoulez vous migrer le serveur vers le module %s dans l'application Zéphir (O/N) ? " % (nom_module,module_local))
                                    if rep.upper() in ["O","OUI"]:
                                        msg = "erreur lors de la migration"
                                        try:
                                            # on met à jour les données du serveur
                                            defaults['installateur'] = user
                                            hw_infos['materiel'] =  saisie('materiel', "matériel")
                                            hw_infos['processeur'] = saisie('processeur', "processeur")
                                            hw_infos['disque_dur'] = saisie('disque_dur', "disque dur")
                                            hw_infos['installateur'] = saisie('installateur', "nom de l'installateur")
                                            hw_infos['date_install'] = str(time.ctime(os.stat("/etc/eole")[9]))
                                            code_ret, msg = convert(zephir_proxy.serveurs.migrate_serveur(id_serveur, hw_infos, id_mod_actuel))
                                            assert code_ret == 1
                                            migration_ok = 1
                                            # affichage de la variante du serveur migré
                                            try:
                                                code_ret, data = convert(zephir_proxy.serveurs.get_serveur(id_serveur))
                                                if code_ret == 1:
                                                    code_ret, var_info = convert(zephir_proxy.modules.get_variante(data[0]['variante']))
                                                    if code_ret == 1:
                                                        print_green("\nLe serveur a été basculé dans Zéphir sur la variante %d (%s) du module %s" \
                                                        % (data[0]['variante'], var_info[0]['libelle'], module_local))
                                            except:
                                                print_red("\n!! Erreur lors de la vérification des données du serveur sur Zéphir !!")
                                        except socket.error as e:
                                            socket_error(e)
                                        except xmlrpclib.ProtocolError:
                                            exit_err("Vous n'êtes pas autorisé à effectuer cette opération !")
                                            rep="N"
                                            if force_default:
                                                sys.exit(1)
                                        except:
                                            print_red ("\n!! erreur lors de la migration : %s !!\n" % msg)
                                            rep="N"
                                            if force_default:
                                                sys.exit(1)
                                else:
                                    print_red ("\n!! Migration non gérée depuis le module %s !!\n" % nom_module)
                                    rep="N"
                                    if force_default:
                                        sys.exit(1)
                            else:
                                if force_default:
                                    print_red("Impossible de continuer l'enregistrement")
                                    sys.exit(1)
                                rep = input("Le module du serveur choisi est %s, continuer (O/N) ? " % nom_module)
                        if rep.upper() in ["O","OUI"]:
                            id_ok = 1
                    else:
                        id_ok = 1
                        if defaults.get('id_serveur', 0) == 0:
                            try:
                                # enregistrement d'un nouveau serveur sur un ancien numéro, on met à jour les infos hardware
                                print("""\nMise à jour des informations sur le matériel""")
                                hw_infos['materiel'] =  saisie('materiel', "matériel", force_default=force_default)
                                hw_infos['processeur'] = saisie('processeur', "processeur", force_default=force_default)
                                hw_infos['disque_dur'] = saisie('disque_dur', "disque dur", force_default=force_default)
                            except:
                                print_red("\n!! erreur lors de la mise à jour des informations !!\n")

            if etat_serveur[0] == 1 and migration_ok != 1:
                if etat_serveur[1]['cle_ok'] == 1:
                    # serveur déjà enregistré
                    confirm = ""
                    # on demande confirmation si ce serveur possède déjà une clé
                    while confirm.upper() not in ['O','N','OUI','NON']:
                        print("le serveur %s a déjà  une clé RSA sur le serveur Zéphir" % id_serveur)
                        msg = "(une procédure d'enregistrement à déjà eu lieu pour ce serveur)"
                        if force_enregistrement:
                            print(msg)
                            confirm = "oui"
                        elif force_default:
                            print_red(msg)
                            sys.exit(1)
                        else:
                            print(msg)
                            confirm = input("continuer l'enregistrement (O/N) ? ")
                    if confirm.upper() in ['N','NON']:
                        sys.exit("\nAbandon de l'enregistrement\n")
            try:
                resultat = convert(zephir_proxy.serveurs.get_conf_uucp(id_serveur, xmlrpclib.base64.encodebytes(cle_pub.encode()), hw_infos))
            except socket.error as e:
                socket_error(e)
            except xmlrpclib.Fault:
                # cas ou Zéphir ne gère pas encore hw_infos sur cette méthode
                if write_perms.intersection(set(user_perms)):
                    try:
                        code_ret, msg = convert(zephir_proxy.serveurs.edit_serveur(id_serveur, hw_infos))
                        assert code_ret == 1
                    except:
                        print_red("Les informations sur le matériel n'ont pas pu être modifiées dans l'application Zéphir")
                try:
                    resultat = convert(zephir_proxy.serveurs.get_conf_uucp(id_serveur, xmlrpclib.base64.encodebytes(cle_pub.encode())))
                except:
                    exit_err("Erreur de génération de la configuration sur le serveur Zéphir")
            except socket.error as e:
                socket_error(e)
            except xmlrpclib.ProtocolError:
                exit_err("Vous n'êtes pas autorisé à effectuer cette opération")
            except:
                exit_err("Erreur de génération de la configuration sur le serveur Zéphir")
        else:
            # enregistrement du serveur
            # saisie des données du serveur
            res=[1,[]]
            while res[1] == []:
                rne = saisie("rne","Etablissement du serveur (n° RNE)")
                libel_etab = rne
                # on vérifie si le RNE existe dans la base
                if rne != "":
                    try:
                        res = convert(zephir_proxy.etabs.get_etab(u(rne)))
                    except xmlrpclib.ProtocolError:
                        exit_err("Vous n'êtes pas autorisé à effectuer cette opération")
                    except socket.error as e:
                        socket_error(e)
                if res[0]==0:
                    exit_err("Erreur de recherche de l'établissement %s" % str(res[1]))
                if res[1]==[]:
                    print_red ("\n** Avant l'enregistrement, l'établissement doit être renseigné via l'application Zéphir **\n")
                else:
                    # on récupère le rne de la base pour éviter les pb de casse
                    rne = res[1][0]['rne']
                    libel_etab = res[1][0]['libelle']

            defaults.update(scan_hardware(defaults))

            if 'installateur' not in defaults:
                # installateur
                defaults['installateur'] = user
            if 'libelle' not in defaults:
                defaults['libelle'] = module_local.split('-')[0] + " " + libel_etab
            # saisie des données
            libelle = saisie('libelle', "libellé du serveur")
            materiel =  saisie('materiel', "matériel")
            processeur = saisie('processeur', "processeur")
            disque_dur = saisie('disque_dur', "disque dur")
            installateur = saisie('installateur', "nom de l'installateur")
            telephone = saisie('telephone',"telephone de l'installateur")
            commentaire = saisie('commentaire', "commentaires")
            print("Délai entre deux connexions à zephir")
            timeout = saisie('timeout', "minutes")
            try:
                timeout = int(timeout) * 60
            except:
                timeout = 1800
            # on affiche la liste des modules disponibles
            try:
                try:
                    # on essaye d'abord de ne récupérer que les modules associés
                    # à cette version de la distribution
                    liste_modules = convert(zephir_proxy.modules.modules_distrib(eole_version))
                except:
                    liste_modules = convert(zephir_proxy.modules.get_module())
            except xmlrpclib.ProtocolError:
                exit_err("Vous n'êtes pas autorisé à accéder à ces données")
            except socket.error as e:
                socket_error(e)
            choix = []
            default_mod = None
            if liste_modules[0] == 1:
                print('\n** liste des modules disponibles **\n')
                mods={}
                for mod in liste_modules[1]:
                    print(mod['id'],mod['libelle'])
                    choix.append(str(mod['id']))
                    mods[str(mod['id'])] = mod['libelle']
                    if mod['libelle'].upper() == module_local.upper():
                        default_mod = mod
            else:
                exit_err('Erreur : '+str(liste_modules[1]))
            mod_ok = 0
            while mod_ok == 0:
                if default_mod is None:
                    module = input("\nmodule : ")
                else:
                    module = input("\nmodule (%s par défaut): " % default_mod['libelle'])
                    if module == "":
                        module = str(default_mod['id'])
                if module in choix:
                    if mods[module].upper() != module_local.upper():
                        conf = input("\n!! Ce serveur est basé sur le module %s, utiliser %s (O/N) ? " % (module_local,mods[module]))
                        if conf.upper() in ["O","OUI"]:
                            mod_ok = 1
                    else:
                        mod_ok = 1
                else:
                    print_red ("\n** choix non valide **\n")


            try:
                variante  = get_module_var(zephir_proxy, module)
                resultat = convert(zephir_proxy.serveurs.add_serveur(
                            u(rne), u(libelle), u(materiel), u(processeur), u(disque_dur), str(time.ctime(os.stat("/etc/eole")[9])), u(installateur),
                            u(telephone), u(commentaire), module, module, int(timeout), variante, xmlrpclib.base64.encodebytes(cle_pub.encode())))
            except socket.error as e:
                socket_error(e)
            except xmlrpclib.ProtocolError:
                exit_err("Vous n'êtes pas autorisé à effectuer cette opération")
            except:
                exit_err("Erreur d'enregistrement sur le serveur Zéphir")

        if resultat[0] == 1:
            id_serveur = resultat[1]
        else:
            exit_err("Erreur d'enregistrement sur le serveur Zéphir: %s" % resultat[1])

    else:
        # erreur de la commande ssh-keygen
        exit_err(f"Erreur de création de la clé rsa : {out} - {err}")

    update_conf(id_serveur, adresse_zephir)
    # changement des droits sur le répertoire uucppublic
    # pour permettre la réception des fichiers depuis zephir
    # (tout le monde doit avoir les droits d'écriture)
    system_code(['/bin/chmod', '777', '/var/spool/uucppublic'])

    # création des fichiers de conf uucp
    print("\n** Configuration des communications vers le serveur Zéphir **\n")
    confs=[]
    # fix : dans config, on vérifie que la ligne 'lockdir /tmp' est présente
    config_data = xmlrpclib.base64.decodebytes(resultat[2].encode()).decode()
    if config_data.count('lockdir') == 0:
        config_data = config_data + "\nlockdir /tmp"
    confs.append([config_data,'config'])
    confs.append([xmlrpclib.base64.decodebytes(resultat[3].encode()).decode(),'sys'])
    confs.append([xmlrpclib.base64.decodebytes(resultat[4].encode()).decode(),'port'])
    try:
        for conf in confs:
            file_conf=open("/etc/uucp/"+conf[1],"w")
            file_conf.write(conf[0].replace('%%zephir%%',adresse_zephir))
            file_conf.close()
    except:
        exit_err("Erreur d'écriture des fichiers de configuration uucp")

    if os.path.isfile('/var/log/uucp/Log'):
        system_out(['/bin/chown','-R', 'uucp', '/var/log/uucp/'])

    # si le fichier config.eol a été envoyé, on le met en place également
    menu = ["Ne rien faire","Non disponible","Non disponible","Modifier la variante du serveur"]
    dispo = ["1","4"]
    no_conf = 1
    if migration_ok == 1 and etat_serveur[1]['migration_ok'] != 0:
        # on a migré le serveur mais la configuration de migration n'est pas définie
        dispo.append("2")
        menu[1] = "Récupérer les fichiers de variante sur le serveur Zéphir"
    else:
        if resultat[5] != "":
            no_conf = 0
            dispo.append("2")
            menu[1] = "Utiliser la configuration définie sur le serveur Zéphir"
        else:
            dispo.append("2")
            menu[1] = "Récupérer les fichiers de variante sur le serveur Zéphir"
    # on regarde si un fichier local existe
    if os.path.isfile('/etc/eole/config.eol'):
        dispo.append("3")
        menu[2] = "Sauver la configuration actuelle sur le serveur Zéphir"
    # on propose le choix entre config locale et distante
    rep=""
    if len(dispo) > 1:
        while str(rep) not in dispo:
            if choix_defaut is None:
                print("\n%s -> %s" % ("1", menu[0]))
                print("%s -> %s" % ("2", menu[1]))
                print("%s -> %s" % ("3", menu[2]))
                print("%s -> %s" % ("4", menu[3]))
                rep = input("\n  Entrez le numéro de votre choix : ")
            else:
                rep = choix_defaut
            # gestion de la modification de variante
            if rep == "4":
                try:
                    # recherche du module actuel
                    server_data = convert(zephir_proxy.serveurs.get_serveur(int(id_serveur)))
                    server_mod = server_data[1][0]['module_actuel']
                    server_var = server_data[1][0]['variante']
                    # saisie du n° de variante
                    new_var = get_module_var(zephir_proxy, server_mod, server_var)
                    if int(server_var) != int(new_var):
                        res = convert(zephir_proxy.serveurs.edit_serveur(int(id_serveur),u({'variante':int(new_var)})))
                        if res[0] != 1:
                            exit_err('Erreur lors du changement de variante')
                        variante = new_var
                        if migration_ok == 1:
                            print_orange("\nAttention, veuillez vérifier la configuration avec gen_config")
                            print_orange("après l'enregistrement puis reconfigurez le serveur.\n")
                except xmlrpclib.ProtocolError:
                    exit_err("Vous n'êtes pas autorisé à effectuer cette opération")
                except socket.error as e:
                    socket_error(e)
                rep = ""

    if rep in ["2","3"]:
        conf_saved=0
        # si on a migré le serveur dans cette session, on récupère
        # la configuration, puis on remonte les fichiers locaux
        if migration_ok == 1:
            # on regarde si la migration de données est possible
            try:
                code_ret, available = migrate_data(zephir_proxy, id_serveur, check=True)
            except socket.error as e:
                exit_err("Erreur lors de l'appel au serveur Zéphir (%s)" % str(e))
            if code_ret == 1 and available == True:
                print_orange("""\nCertaines données utilisateur peuvent être récupérées\n(fichiers divers définis sur Zéphir)\n""")
                rep_mig = input("""Voulez vous migrer ces données (O/N) ?""")
                if rep_mig.upper() in ['O','OUI']:
                    migration_ok = 2
        if rep == "3":
            save_conf(id_serveur)
            conf_saved=1
        # si migration des données, on l'effectue avant la récupération
        if migration_ok == 2:
            print_orange ("\n -- migration des données utilisateur --\n")
            try:
                code_ret, infos = migrate_data(zephir_proxy, id_serveur)
            except socket.error as e:
                exit_err("Erreur lors de l'appel au serveur Zéphir (%s)" % str(e))
            if code_ret == 0:
                print_red ("!! erreur lors de la migration des données :\n %s" % infos)
                rep_migr = input('Continuer la synchronisation avec le serveur Zéphir (O/N) ?')
                if not rep_migr.upper() in ['O','OUI']:
                    migration_ok = -1
        if migration_ok != -1:
            # dans le cas où le serveur n'a jamais été instancié, on exécute
            # les scripts de preinstance aclmount et makedirs (horus/scribe)
            preinst_msg = True
            config_eol_exists = True
            if not os.path.isfile('/etc/eole/config.eol'):
                config_eol_exists = False
                for preinst_script in ['aclmount', 'makedirs']:
                    if os.path.isfile(os.path.join('/usr/share/eole/preinstance', preinst_script)):
                        if preinst_msg:
                            print("\n*****************************************************************")
                            print("** Execution des scripts de préparation du système de fichiers **")
                            print("*****************************************************************\n")
                            preinst_msg = False
                        system_code([os.path.join('/usr/share/eole/preinstance', preinst_script)])
            # mise en place de la configuration et des fichiers de variante
            id_serveur = recup_conf(resultat,id_serveur,zephir_proxy,no_conf,conf_saved)
            if migration_ok in [1,2]:
                if rep == "3":
                    # en cas de migration avec sauvegarde, on relance une sauvegarde
                    # après récupération de la variante
                    save_conf(id_serveur)
                # dans le cas où le serveur n'est pas encore instancié,
                # suppression de config.eol pour éviter les  warnings à l'instance
            if rep == "2":
                # on effectue une sauvegarde pour remonter les fichiers à sauvegarder sur le serveur Zéphir
                save_conf(id_serveur)
                if no_conf == 1 and not os.path.isfile('/etc/eole/config.eol'):
                    msg_no_conf()
        else:
            # la migration a échoué, on reset le flag
            migration_ok = 1

    return id_serveur

def main(use_pppoe, force_conf_net, adresse_zephir=None, user=None, password=None, id_serveur=None, choix=None, force_enregistrement=None):
    """ programme principal """
    print("\n  Procédure d'enregistrement sur le serveur Zéphir \n\n")
    stats_running = False
    if eole_module == 'zephir':
        # XXX FIXME : pour l'instant il n'est pas possible d'enregistrer
        # un serveur Zéphir (la configuration UUCP n'est pas compatible)
        #
        #stats_service = 'zephir'
        #if os.path.isfile('/var/run/zephir_backend.pid'):
        #    stats_running = True
        print_red("Erreur, l'enregistrement n'est pas possible sur un module Zéphir.\n\n\n")
        sys.exit(1)
    else:
        stats_service = 'z_stats'
        if os.path.isfile('/var/run/z_stats.pid'):
            stats_running = True
    try:
        from zephir.zephir_conf import zephir_conf
    except:
        zephir_conf = None
    else:
        # on vérifie d'abord si des locks sont positionnés
        tags=['maj','configure','reconfigure','sauvegarde','uucp']
        if is_locked(tags):
            print("\ndes verrous ont été trouvés dans /var/lock/")
            # suppression du verrou
            unlock(tags)
            # log sur zephir
            print_orange ("verrous supprimés\n\n")
            log('LOCK',0,'enregistrement: supression des verrous dans /var/lock/')

        rep = ""
        msg = """** Ce serveur est déjà enregistré sur le serveur Zéphir **\n\n - n°identifiant : %s\n - adresse de Zéphir : %s \n""" % (zephir_conf.id_serveur,zephir_conf.adresse_zephir)
        if id_serveur is not None:
            print_red(msg)
            sys.exit(1)
        print(msg)
        print("1 -> Désinscrire ce serveur du serveur Zéphir")
        print("2 -> Relancer l'enregistrement")
        print("3 -> Ne rien faire\n")
        while str(rep) not in ["1","2","3"]:
            rep = input("  Entrez le numéro de votre choix : ")


        if str(rep) == "3":
            sys.exit()
        elif str(rep) == "1":
            if stats_running:
                manage_services('stop', stats_service)
            if eole_module != 'zephir':
                if zephir_conf is not None:
                    # agents de surveillance : on réinitialise le n° de l'agent à 0 pour les stats
                    # si il existe déjà
                    stats_dir = '%s/monitor/stats/' % zephir_dir
                    # ancien répertoire de stockage
                    old_id = str(zephir_conf.id_serveur)
                    if os.path.isdir(stats_dir + old_id):
                        shutil.move(stats_dir + old_id, stats_dir + '0')
            try:
                os.unlink("%s/zephir_conf/zephir_conf.py" % zephir_path)
            except:
                print_red ("\n !! le fichier %s/zephir_conf/zephir_conf.py n'a pas pu être supprimé !!\n" % zephir_path)
            try:
                os.unlink("%s/zephir_conf/zephir_conf.pyc" % zephir_path)
                try:
                    f = open("%s/deffered_logs" % zephir_dir, "w").close()
                    shutil.rmtree("/var/spool/uucp/zephir")
                except:
                    pass
            except:
                pass
            if stats_running:
                manage_services('start', stats_service)
            # FIXME proposer la suppression du serveur dans zephir ?
            sys.exit("\nDésinscription auprès du serveur Zéphir terminée\n")

    # TRAITEMENT DES VALEURS PAR DEFAUT
    # unmanaged_service(u'restart', u'creoled', u'service')
    # 1 - lecture de la conf locale
    if zephir_conf is not None:
        defaults['id_serveur'] = zephir_conf.id_serveur
        defaults['adresse_zephir'] = zephir_conf.adresse_zephir
    # 2 - lecture du dictionnaire
    if os.path.exists('/etc/eole/config.eol'):
        num_etab = creole_client.get_creole('numero_etab', None)
        if num_etab:
            defaults['rne'] = num_etab
    # 3 - essai de lecture de données sur une clé usb
    if os.path.exists('/mnt/removable/zephir.conf'):
        print("Clé USB détectée, lecture des données...")
        fic_conf = open("/mnt/removable/zephir.conf")
        content = fic_conf.readlines()
        fic_conf.close()
        # mise en forme des variables (valeurs par défaut)
        for line in content:
            if not line.strip().startswith('#'):
                var,val = line.strip().split('=')
                defaults[var]=eval(val)
    conf_net = ""
    try:
        if not force_conf_net and os.path.exists('/etc/eole/config.eol'):
            ip_eth0 = creole_client.get_creole('numero_etab', None)
            if ip_eth0:
                conf_net = "N"
    except:
        pass

    while conf_net[:1].upper() not in ["O","N"]:
        conf_net = saisie("conf_net","Voulez-vous établir une configuration réseau minimale (O/N)")

    if conf_net.upper() in ['O','OUI']:
        conf_network(use_pppoe)

    if adresse_zephir is None:
        adresse_zephir = saisie("adresse_zephir","Entrez l'adresse (nom DNS) du serveur Zéphir")
    if use_pppoe:
        conn_ok = False
        # cas d'une connexion ppp : on attend le montage de la connexion
        print_orange("\nattente de la connexion par PPPoE ...")
        test_conn = True
        retries = 0
        while test_conn:
            try:
                # essai de connexion non authentifiée
                zephir_proxy = EoleProxy("https://zephir:zephir@"+adresse_zephir+":7080",transport=TransportEole())
                locks = convert(zephir_proxy.serveurs.get_locks())
                print_green("connexion établie\n")
                conn_ok = True
                test_conn = False
            except socket.error:
                retries += 1
                if retries > 4:
                    test_conn = False
                else:
                    # on attend 2 secondes avant de réessayer
                    time.sleep(2)
            except:
                # erreur non liée à un pb réseau
                conn_ok = True
                test_conn = False
        if not conn_ok:
            exit_err("La connexion n'a pas pu être établie")
    login_ok = 0
    user_perms = []
    has_login = user != None
    while login_ok == 0 and user != "":
        if user is None:
            user = input("Entrez votre login pour l'application Zéphir (rien pour sortir) : ")
        if user != "":
            if password is None:
                password = getpass.getpass("Mot de passe pour l'application Zéphir pour %s : " % user)
            zephir_proxy = EoleProxy("https://"+user+":"+password+"@"+adresse_zephir+":7080",transport=TransportEole())
            login_ok = 1
            try:
                res = convert(zephir_proxy.get_permissions(user))
                if res[0] == 1:
                    user_perms = res[1]
            except xmlrpclib.ProtocolError:
                login_ok = 0
                print_red("\n Erreur d'authentification \n")
                if has_login:
                    exit(1)
                user = None
                password = None
            except (ssl.SSLError, ssl.CertificateError) as e:
                if "certificate verify failed" in str(e):
                    print_red("\nCertificat de Zéphir non validé !\n\n"),
                    print_orange(' utiliser sur Zéphir un certificat signé par une autorité reconnue,')
                    print_orange('  ou')
                    print_orange(' Copier le fichier /etc/ssl/certs/ca_local.crt de Zéphir dans')
                    print_orange(' /usr/local/share/ca-certificates et lancer update-ca-certificates.')
                    sys.exit(1)
                elif "doesn't match" in str(e):
                    print_red("\nLe certificat présenté par Zéphir ne correspond pas à l'adresse fournie.\n\n")
                    print_orange(" Assurez vous que le nom DNS {} est bien présent comme sujet principal".format(adresse_zephir))
                    print_orange(" ou nom DNS alternatif dans le certificat présenté par l'application Zéphir.")
                    sys.exit(1)
            except socket.error as e:
                socket_error(e)
        else:
            sys.exit("! abandon de la procédure !")

    # Vérification que les droits minimaux sont présents pour l'enregistrement
    if not min_perms.intersection(set(user_perms)):
        print_red("\nVos droits dans l'application Zéphir ne vous permettent pas d'enregister un serveur.\n")
        sys.exit(1)
    # la connexion à zephir est valide
    # on regarde si une mise à jour est diponible
    try:
        res=maj_client_zephir(zephir_proxy, adresse_zephir)
    except socket.error as e:
        exit_err("Erreur lors de l'appel au serveur Zéphir (%s)" % str(e))
    if res != 2:
        if res != 0:
            exit_err("Erreur lors de la mise à jour !")
        else:
            sys.exit("\n\n** Client mis à jour, relancez la procédure d'enregistrement **\n")

    # arrêt du client zephir pour éviter les transferts uucp concurrents
    if stats_running:
        manage_services('stop', stats_service)
    # mise en place de la configuration
    try:
        id_serveur = conf_uucp(zephir_proxy, adresse_zephir, user, user_perms, id_serveur, choix, force_enregistrement)
    except socket.error as e:
        exit_err("Erreur lors de l'appel au serveur Zéphir (%s)" % str(e))
    # si nécessaire, on enregistre la sonde prélude
    unmanaged_service('restart', 'creoled', 'service')
    # enregistrement des sondes prélude si demandé
    if eole_module != 'preludemanager':
        if creole_client.get_creole('activer_sonde_prelude', 'non').lower() == 'oui' or eole_module == 'zephirlogs':
            register_prelude(zephir_proxy)
    if eole_module != 'zephir':
        # agents de surveillance : on met à jour le nom du répertoire des statistiques
        # si il existe déjà
        stats_dir = '%s/monitor/stats/' % zephir_dir
        # ancien répertoire de stockage
        if 'id_serveur' in defaults and str(rep) != "1":
            old_id = str(defaults['id_serveur'])
        else:
            old_id = '0'
        if old_id != str(id_serveur) and os.path.isdir(stats_dir + old_id):
            shutil.move(stats_dir + old_id, stats_dir + str(id_serveur))
    if stats_running:
        # démarrage du service si le serveur est instancié
        manage_services('start', stats_service)
    print_green ("** le numéro attribué à ce serveur sur le serveur Zéphir est : %s **" % id_serveur)

def scan_hardware(data_dict):
    # recherche d'informations par défaut
    # type de machine (si dispo)
    result, hw_info, hw_err = system_out(['/usr/bin/lshw', '-C', 'system', '-short'])
    # matériel (première ligne du premier élément de classe 'system')
    sys_name_lines = hw_info.split('system')[1]
    sys_name = sys_name_lines.split('\n')[0].strip()
    if 'materiel' not in data_dict:
        if sys_name.upper() != 'COMPUTER':
            data_dict['materiel'] = sys_name
    # modèle cpu
    cpu_info = open('/proc/cpuinfo')
    if 'processeur' not in data_dict:
        for line in cpu_info.read().split('\n'):
            if line.startswith('model name'):
                processeur = line.split(':')[1]
                processeur.strip()
                data_dict['processeur'] = processeur
            if line.startswith('cpu MHz'):
                speed = line.split(':')[1]
                speed.strip()
                data_dict['processeur'] += " %d MHz" % int(float(speed))
        cpu_info.close()
    # disque dur (pas de /proc/partitions sur serveur virtualisé)
    if 'disque_dur' not in data_dict:
        result = system_out(['/usr/bin/lsblk', '-b', '-n',
                             '--output', 'SIZE,TYPE'])
        sizes = [s.strip().split() for s in result[1].strip().split('\n')]
        disk_sizes = [int(s[0]) for s in sizes if s[1] == 'disk']
        size = int(sum(disk_sizes) / math.pow(1024, 3))
        data_dict['disque_dur'] = "%s Go" % size
    return data_dict

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Procédure d'enregistrement sur un serveur Zéphir")
    parser.add_argument('-c', '--check', action='store_true',
                        help="Vérification seulement, affiche l'identifiant du serveur stocké dans l'application Zéphir et retourne 0 si le serveur est enregistré, 1 sinon")
    parser.add_argument('-p', '--pppoe', action='store_true',
                        help="Si le réseau n'est pas encore configuré, cette option permet la mise en place d'une connexion par PPPoE")
    parser.add_argument('-f', '--force', action='store_true',
                        help="Force la mise en place d'un configuration minimale du réseau même si le serveur est déjà configuré")
    parser.add_argument('--adresse_zephir', help='Nom DNS du serveur Zéphir')
    parser.add_argument('--user', help="Login pour l'application Zéphir")
    parser.add_argument('--password', help="Mot de passe pour l'application Zéphir")
    parser.add_argument('--id_serveur', help="N° identifiant le serveur l'application Zéphir")
    parser.add_argument('--choix', help="Numéro de votre choix d'échange avec le Zéphir", choices=['1', '2', '3', '4'])
    parser.add_argument('--force_enregistrement', action='store_true',
                        help="Force l'enregistrement même si un serveur est déjà enregistré")

    args = parser.parse_args()
    if args.check:
        try:
            from zephir.zephir_conf.zephir_conf import id_serveur
            print("\nServeur enregistré (identifiant : %d)\n" % id_serveur)
        except:
            print("\nServeur non enregistré\n")
            sys.exit(1)
    else:
        if os.geteuid() != 0:
            print("\nCe script est réservé à l'utilisateur root\n")
            sys.exit(1)
        main(args.pppoe, args.force, args.adresse_zephir, args.user, args.password, args.id_serveur, args.choix, args.force_enregistrement)
    sys.exit(0)
