# -*- 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
#
# prelude_rpc.py
#
# fonctions xmlrpc pour la gestion de prélude dans Zephir
#
###########################################################################
"""module de gestion de prelude
"""
from twisted.internet.utils import getProcessOutput
from zephir.backend.db_utils import *
from zephir.backend import config
from zephir.backend.config import u
from zephir.backend.xmlrpceole import XMLRPCEole as XMLRPC
from zephir.backend.lib_backend import ResourceAuthError
from zephir.eolerpclib import xmlrpclib, EoleProxy
import sys,os,shutil,time,base64
from zephir.backend.uucp_utils import uucp_pool

# FIXME : fonctionnalité non présente dans les versions récentes de creole
#
#from creole2 import cert
#from creole2.config import rsyslog_ca_file, rsyslog_ca_template

class RPCPrelude(XMLRPC):
    """serveur XMLRPC zephir pour la gestion de prélude
    """

    def __init__(self, parent):
        self.dbpool = db_connect()
        self.dbpool.noisy = 0
        XMLRPC.__init__(self)
        self.parent = parent

    def xmlrpc_register_server(self, cred_user, id_manager):
        """négocie l'enregistrement d'une sonde prelude dans prelude manager
        id_serveur : identifiant zephir du serveur sonde

        -génère un mot de passe aléatoire
        -demande le lancement de prelude-adduser sur le manager
        -renvoie le mot de passe pour permettre l'enregistrement côté sonde
        """
        # génération du mot de passe avec pwgen
        cmd_pass = getProcessOutput("/usr/bin/pwgen",
                                    args = ["-B","-s","-1"],
                                    env = {'LC_ALL': 'C'})
        return cmd_pass.addCallback(self._register_server, cred_user, id_manager)

    def _register_server(self, output, cred_user, id_manager):
        """
        Callback de la fonction xmlrpc_register_server.
        """
        passwd = output.strip()
        # lancement de prelude-adduser sur le manager
        try:
            # lecture de la clé du manager
            serv = self.parent.s_pool.get(cred_user, int(id_manager))
            key = open(os.path.join(serv.get_confdir(), 'cle_publique')).read()
            try:
                ip_manager = serv.parsedico()['adresse_ip_eth0']
            except:
                return 0, u("""Adresse ip du manager %s non disponible""" % id_manager)
            manager_rpc = EoleProxy('https://%s:%s' % (ip_manager, config.PRELUDE_PORT))
            res = manager_rpc.register_server(xmlrpclib.base64.encodebytes(key),passwd)
        except:
            import traceback
            traceback.print_exc()
            res = 0
        if res == 1:
            return 1, u(passwd)
        elif res == -1:
            return -1, u("""Un enregistrement est déjà en cours""")
        else:
            return 0, u("""Impossible de lancer prelude-adduser sur le manager""")

    def xmlrpc_get_managers(self, cred_user, module='preludemanager'):
        """renvoie l'adresse du manager défini sur zephir si il existe"""
        # on récupère la liste des managers disponibles
        if module == '':
            # nouvelle méthode, on reherche tous les serveurs ayant activé la réception des logs
            managers = {}
            for id_serv in self.parent.s_pool.keys():
                try:
                    serv = self.parent.s_pool.get(cred_user, id_serv)
                except:
                    # serveur non autorisé
                    continue
                conf = serv.parsedico()
                if conf.get('activer_reception_logs','non') == 'oui':
                    if conf.get('activer_reception_logs_tcp','non') == 'oui':
                        if conf.get('rsyslog_reception_tls','non') == 'oui':
                            managers[str(id_serv)] = [conf.get('adresse_ip_eth0',''), serv.libelle]
            return 1, u(managers)
        else:
            query = """select distinct(serveurs.id), serveurs.libelle from serveurs, modules where\
            serveurs.module_actuel=modules.id and modules.libelle like %s"""
            return self.dbpool.runQuery(query, ('%s-%%' % module, )).addCallbacks(self._get_managers, db_client_failed, callbackArgs=[cred_user])

    def _get_managers(self, data, cred_user):
        """
        Callback de la fonction xmlrpc_get_managers.
        """
        if data == []:
            # pas de serveurs preludemanager enregistrés
            return 1, {}
        else:
            managers = {}
            for manager in data:
                id_man = int(manager[0])
                libelle = manager[1]
                # récupération de l'adresse ip
                serv = self.parent.s_pool.get(cred_user, id_man)
                try:
                    ip = serv.parsedico()['adresse_ip_eth0']
                except:
                    # configuration inconnue pour ce manager
                    ip = ''
                if ip != '':
                    managers[str(id_man)]=[ip, libelle]

        return 1, u(managers)

    def xmlrpc_gen_certif(self, cred_user, request_data, id_serveur, id_zephirlog=None):
        """
        Récupère les données d'une requête et enregistre la configuration
        rsyslog dans le répertoire adéquat.
        @request_data : dictionnaire contenant le contenu de la requête
                        (entrée request), le modèle pour générer le
                        certificat (entrée template) et la configuration
                        pour rsyslog.
        @id_serveur : identifiant zephir du serveur demandant la génération
                        du certificat
        @id_zephirlog (optionnel) : identifiant zephir du zephirlog concerné
                        par l'appairage.
        """

        # FIXME
        return 0, "fonction non disponible sur Zéphir 2.6.0"

        #rsyslog_privkey = '/etc/ssl/private/rsyslog_privkey.pem'
        #serveur_rsyslog_conf = 'rsyslog/zephirlog'
        #client_rsyslog_conf = 'rsyslog/client'

        #if id_zephirlog:
        #    zephirlog_dest = self.parent.s_pool.get(cred_user, int(id_zephirlog))
        #    write_path_rsyslog_conf = os.path.join(zephirlog_dest.get_confdir(), client_rsyslog_conf)
        #    read_path_rsyslog_conf = os.path.join(zephirlog_dest.get_confdir(), serveur_rsyslog_conf)
        #else:
        #    zephirlog_dest = self.parent.s_pool.get(cred_user, int(id_serveur))
        #    write_path_rsyslog_conf = os.path.join(zephirlog_dest.get_confdir(), serveur_rsyslog_conf)
        #    read_path_rsyslog_conf = os.path.join(zephirlog_dest.get_confdir(), client_rsyslog_conf)

        #if not os.path.exists(write_path_rsyslog_conf):
        #    os.makedirs(write_path_rsyslog_conf, 0755)
        #if not os.path.exists(read_path_rsyslog_conf):
        #    os.makedirs(read_path_rsyslog_conf, 0755)

        #rsyslog_conf_file = os.path.join(write_path_rsyslog_conf, str(id_serveur) + '.peer')
        #rsyslog_file = open(rsyslog_conf_file, 'w')
        #rsyslog_file.write(xmlrpclib.base64.decodebytes(request_data['rsyslog']))
        #rsyslog_file.close()

        #if id_zephirlog and os.path.exists(rsyslog_conf_file):
        #    id_uucp = str(zephirlog_dest.get_rne()) + '-' + str(zephirlog_dest.id_s)
        #    res = uucp_pool.add_cmd(id_uucp, "zephir_client get_rsyslog_conf")

        #serv = self.parent.s_pool.get(cred_user, int(id_serveur))
        #path_request = os.path.join(serv.get_confdir(), "request.pem")
        #file_request = open(path_request, "w")
        #file_request.write(xmlrpclib.base64.decodebytes(request_data['request']))
        #file_request.close()
        #path_request_template = os.path.join(serv.get_confdir(), "request-template.tmpl")
        #file_request_template = open(path_request_template, "w")
        #file_request_template.write(xmlrpclib.base64.decodebytes(request_data['template']))
        #file_request_template.close()
        #path_cert = os.path.join(serv.get_confdir(), "rsyslog_cert.pem")

        #if not os.path.exists(rsyslog_privkey):
        #    cert.gen_privkey(rsyslog_privkey)
        #if not os.path.exists(rsyslog_ca_file):
        #    cert.gen_selfsigned_cert(rsyslog_ca_template, rsyslog_privkey, path_cert=rsyslog_ca_file)

        #cmd_pass = getProcessOutput("/usr/bin/certtool",
        #                            args = ["--generate-certificate",
        #                                "--load-request", path_request,
        #                                "--outfile", path_cert,
        #                                "--load-ca-certificate", rsyslog_ca_file,
        #                                "--load-ca-privkey", rsyslog_privkey,
        #                                "--template", path_request_template],
        #                            env = {'LC_ALL': 'C'},
        #                            errortoo=True)
        #return cmd_pass.addCallback(self._gen_certif, cred_user, path_cert, read_path_rsyslog_conf)

    def _gen_certif(self, output, cred_user, path_cert, path_rsyslog_conf):
        """
        Retourne le certificat et la configuration de rsyslog si elle est
        disponible.
        @path_cert : le chemin du certificat à retransmettre
        @path_rsyslog_conf : répertoire contenant les bouts de conf
            pour rsyslog. Les contenus de tous les fichiers présents sont
            concaténés pour être envoyés.
        """

        # FIXME
        return 0, "fonction non disponible sur Zéphir 2.6.0"

        #result = {}
        #ca_file = open(rsyslog_ca_file, 'r')
        #result['ca_data'] = xmlrpclib.base64.encodebytes(ca_file.read())
        #ca_file.close()
        #cert_file = open(path_cert, 'r')
        #result['cert_data'] = xmlrpclib.base64.encodebytes(cert_file.read())
        #cert_file.close()

        #if os.path.exists(path_rsyslog_conf):
        #    rsyslog_data = []
        #    for rsyslog_conf in [i for i in os.listdir(path_rsyslog_conf) if i[-5:] == '.peer']:
        #        rsyslog_conf = open(os.path.join(path_rsyslog_conf, rsyslog_conf), 'r')
        #        rsyslog_data.append(rsyslog_conf.read())
        #        rsyslog_conf.close()

        #result['rsyslog_data'] = xmlrpclib.base64.encodebytes('\n'.join(rsyslog_data))

        #return 1, result

    def xmlrpc_get_rsyslog_conf(self, cred_user,  id_serveur, id_zephirlog=None):
        """
        Récupère les données d'une requête et enregistre la configuration
        rsyslog dans le répertoire adéquat.
        @request_data : dictionnaire contenant le contenu de la requête
                        (entrée request), le modèle pour générer le
                        certificat (entrée template) et la configuration
                        pour rsyslog.
        @id_serveur : identifiant zephir du serveur demandant la génération
                        du certificat
        @id_zephirlog (optionnel) : identifiant zephir du zephirlog concerné
                        par l'appairage.
        """

        serveur_rsyslog_conf = 'rsyslog/zephirlog'
        client_rsyslog_conf = 'rsyslog/client'

        if id_zephirlog:
            zephirlog_dest = self.parent.s_pool.get(cred_user, int(id_zephirlog))
            read_path_rsyslog_conf = os.path.join(zephirlog_dest.get_confdir(), serveur_rsyslog_conf)
        else:
            zephirlog_dest = self.parent.s_pool.get(cred_user, int(id_serveur))
            read_path_rsyslog_conf = os.path.join(zephirlog_dest.get_confdir(), client_rsyslog_conf)

        return self._get_rsyslog_conf(1, cred_user, read_path_rsyslog_conf)

    def _get_rsyslog_conf(self, output, cred_user, path_rsyslog_conf):
        """
        Retourne la configuration de rsyslog.
        @path_rsyslog_conf : répertoire contenant les bouts de configuration.
        """
        rsyslog_data = []
        for rsyslog_conf in [i for i in os.listdir(path_rsyslog_conf) if i[-5:] == '.peer']:
            rsyslog_conf = open(os.path.join(path_rsyslog_conf, rsyslog_conf), 'r')
            rsyslog_data.append(rsyslog_conf.read())
            rsyslog_conf.close()

        return 1, xmlrpclib.base64.encodebytes('\n'.join(rsyslog_data))


    def xmlrpc_register_logger(self, cred_user, id_serveur):
        """permet de vérifier si des serveurs ont été modifiés
        """
        return 1, u("""Fonction non implémentée""")

