#!/usr/bin/env python3
# -*- coding: utf8 -*-
"""
diagnose du rvp
"""
import subprocess
import shlex
import re
import time
from subprocess import getstatusoutput
from os.path import isfile
from creole import config
from creole.client import CreoleClient
from zephir.monitor.agents.rvp import parse_ipsec_statusall

def parse_swanctl_list_sas(output):
    """Parse a minimal swanctl --list-sas output for diagnose.

    The legacy parser used ipsec statusall and returned a detailed tunnel
    list.  For swanctl, diagnose only needs enough information to decide
    whether there are active SAs on Sphynx/Eolebase.
    """
    lines = []
    for line in output.splitlines():
        line = line.strip()
        if not line:
            continue
        if line.startswith("agent plugin requires"):
            continue
        if line.startswith("plugin 'agent': failed"):
            continue
        lines.append(line)

    child_sas = [line for line in lines if "INSTALLED" in line]
    ike_sas = [line for line in lines if "ESTABLISHED" in line]
    tunnels = child_sas or ike_sas
    total = len(tunnels)
    up = total
    down = 0
    idle_threads = None
    return tunnels, total, up, down, idle_threads


def run_status_command(command):
    """Run a status command without letting diagnose crash if it is absent."""
    try:
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
        ret, err_output = process.communicate()
        return process.returncode, ret.decode(errors='replace'), err_output.decode(errors='replace')
    except FileNotFoundError as err:
        return 1, '', str(err)


dico_eole = CreoleClient().get_creole()
install_rvp = dico_eole.get('install_rvp', 'non')
cmd = [". /usr/lib/eole/diagnose.sh"]
cmd.append('EchoGras "*** Réseau virtuel privé"')

# test du RVP si configuré
if install_rvp == "oui":
    tunnels = []
    total = 0
    up = 0
    down = 0
    idle_threads = None

    if dico_eole.get('type_amon') is not None:
        statusall_err, ret, err_output = run_status_command(['ipsec', 'statusall'])
        if statusall_err == 0:
            tunnels, total, up, down, idle_threads = parse_ipsec_statusall(ret)
    else:
        statusall_err, ret, err_output = run_status_command(['swanctl', '--list-sas'])
        if statusall_err == 0:
            tunnels, total, up, down, idle_threads = parse_swanctl_list_sas(ret + '\n' + err_output)

    if dico_eole.get('type_amon') is not None:
        # diagnose Amon
        TEST_RVP = "/usr/share/eole/test-rvp"
        if isfile(TEST_RVP):
            if statusall_err == 0:
                if total == 0:
                    cmd.append('printf ".  %${len_pf}s =>" "RVP"')
                    cmd.append('EchoOrange " Aucun tunnel actif"')
                else:
                    for tunnel in tunnels:
                        if tunnel['child_name'] != '':
                            tested_ip = tunnel['dst'].split('--')
                            if len(tested_ip) > 1:
                                for ip in tested_ip:
                                    if "injoignable" in ip:
                                        cmd_line = 'printf ".  %${len_pf}s => " "RVP '
                                        cmd_line += str(ip.split('injoignable')[0].strip())\
                                                    +'"'+'\nEchoRouge " Erreur"'
                                        if cmd_line not in cmd:
                                            cmd.append(cmd_line)
                                    elif "joignable" in ip:
                                        cmd_line = 'printf ".  %${len_pf}s => " "RVP '
                                        cmd_line += str(ip.split('joignable')[0].strip())\
                                                    +'"'+'\nEchoVert " OK"'
                                        if cmd_line not in cmd:
                                            cmd.append(cmd_line)
            else:
                cmd.append('printf ".  %${len_pf}s => " "RVP"')
                cmd.append('EchoRouge " Erreur"')
        else:
            cmd.append('NoConfig "RVP"')
    else:
        # diagnose Eolebase ou Sphynx
        activer_haute_dispo = dico_eole.get('activer_haute_dispo', 'non')
        local_ipsec = True
        remote_ipsec = False
        if activer_haute_dispo != 'non':
            crm_cmd = ['crm', 'resource', 'show', 'ipsec_rsc']
            crm_process = subprocess.Popen(crm_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
            crm_output, err_output = crm_process.communicate()
            rc_crm = crm_process.returncode
            if rc_crm == 0:
                if isinstance(crm_output, bytes):
                    crm_output = crm_output.decode()
                crm_output = crm_output.split('\n')[0]
                local_node = dico_eole['nom_machine']
                if dico_eole['activer_haute_dispo'] == 'maitre':
                    remote_node = dico_eole['nom_machine_esclave']
                elif dico_eole['activer_haute_dispo'] == 'esclave':
                    remote_node = dico_eole['nom_machine_maitre']
                find_line = "^resource ipsec_rsc is running on: {0} $"
                if re.match(find_line.format(local_node), crm_output):
                    local_ipsec = True
                    remote_ipsec = False
                elif re.match(find_line.format(remote_node), crm_output):
                    local_ipsec = False
                    remote_ipsec = True
            else:
                local_ipsec = False
                remote_ipsec = False
        if local_ipsec:
            cmd.append('printf ".  %${len_pf}s =>" "VPN"')
            if statusall_err == 0:
                if total == 0:
                    cmd.append('EchoVert " Aucun tunnel"')
                elif up < total:
                    cmd.append('EchoOrange " {0} tunnel{1} actif{1} sur {2}"'.format(up, '' if up < 2 else 's',total))
                else:
                    cmd.append('EchoVert " Ok ({0} tunnel{1} actif{1} sur {2})"'.format(up, '' if up < 2 else 's',total))
            else:
                cmd.append('EchoRouge " Erreur"')
            cmd.append('TestService ARV $(CreoleGet adresse_ip_eth0):$(CreoleGet arv_port)')
        elif remote_ipsec:
            cmd.append('printf ".  %${len_pf}s =>" ""')
            cmd.append('EchoBleu "  IPsec sur noeud distant"')
        else:
            cmd.append('printf ".  %${len_pf}s =>" ""')
            cmd.append('EchoRouge "  IPsec sur aucun noeud du cluster"')
else:
    cmd.append('Inactif "RVP"')
cmd.append('echo')
# Exécution des commandes
cmd_string = "\n".join(cmd)
err, ret = getstatusoutput(cmd_string)
print(ret)
exit(0)
