#!/usr/bin/python3
# -*- mode: python; coding: utf-8 -*-
#
##########################################################################
# eole-purge-interfaces - flush IP addresses and delete virtual devices
# Copyright © 2018 Pôle de compétences EOLE <eole@ac-dijon.fr>
#
# License CeCILL:
#  * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
#  * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
##########################################################################
"""Flush IP addresses and delete virtual devices

"""

import sys
import os
import glob

from subprocess import Popen, PIPE

from pyeole.i18n import i18n


_ = i18n('eole-purge-interfaces')

IGNORE_INTERFACE = "/etc/eole/ignore-interfaces.csv"

ENCODING = sys.stdout.encoding
if ENCODING is None:
    ENCODING = 'UTF-8'


def _exec(cmd):
    """Execute a command and return the retcode, stdout and stderr

    :param list cmd: command to execute
    :returns tuple: return code, standard output and standard error
    """
    process = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    stdout, stderr = process.communicate(None)
    return_code = process.returncode

    return return_code, stdout.decode(ENCODING), stderr.decode(ENCODING)


def get_ip_interfaces():
    """Return the list of all interface names with an IP address

    """
    cmd = ['/sbin/ip', '-o', 'addr', 'show']
    code, stdout, stderr = _exec(cmd)

    if code != 0:
        raise Exception(_('Error running command {0} : {1}').format(' '.join(cmd), stderr))

    devs = set()
    for line in stdout.splitlines():
        dev = line.strip().split()
        if dev[1] == 'lo':
            continue

        devs.add(dev[1])

    return list(devs)


def get_virtual_devices():
    """Return the list of all virtual interface names

    """
    virtual_devices = []
    for dirname in glob.glob('/sys/class/net/*'):
        name = os.path.basename(dirname)
        if name == 'lo' or not os.path.islink(dirname) or os.path.islink(os.path.join(dirname, 'device', 'driver')):
            continue

        virtual_devices.append(name)

    virtual_devices.sort()
    return virtual_devices


def get_ignore_list():
    """Return the list of interfaces to ignore
       We have to ignore OpenNebula managed interafaces
    """

    devs = {"ovs-system"}

    if os.path.isfile(IGNORE_INTERFACE):
        f = open(IGNORE_INTERFACE,'r')
        for line in f.readlines():
            if line.startswith('BRIDGE'):
                continue
            devs.add(line.strip())

    return devs


def down_interface(interface):
    """Disable the interface `interface`

    :param str interface: name of the interface
    :return bool: if the down command was sucessfull
    """
    prom_cmd = ['ip', 'link', 'set', interface, 'promisc', 'off']
    down_cmd = ['ip', 'link', 'set', interface, 'down']
    msg = _("Disable the interface '{interface}'... ")
    print(msg.format(interface=interface), end='')
    _exec(prom_cmd)
    code, stdout, stderr = _exec(down_cmd)
    if code == 0:
        print("OK")
        return True

    print(_("error: {error}").format(error=stderr))
    return False


def flush_interface(interface):
    """Flush all IP addresses of the interface `interface`

    :param str interface: name of the interface
    :return bool: if the flush command was sucessfull
    """
    flush_cmd = ['ip', 'addr', 'flush', interface]
    msg = _("Flush IP addresses of the interface '{interface}'... ")
    print(msg.format(interface=interface), end='')
    code, stdout, stderr = _exec(flush_cmd)
    if code == 0:
        print("OK")
        return True

    print(_("error: {error}").format(error=stderr))
    return False


def delete_interface(interface):
    """Delete the interface `interface`

    :param str interface: name of the interface
    :return bool: if the delete command was sucessfull
    """
    delete_cmd = ['ip', 'link', 'delete', interface]
    msg = _("Delete the interface '{interface}'... ")
    print(msg.format(interface=interface), end='')
    code, stdout, stderr = _exec(delete_cmd)
    if code == 0:
        print("OK")
        return True

    print(_("error: {error}").format(error=stderr))
    return False


def main():
    """Flush the IP addresses and delete virtual interfaces

    """
    print(_("Purge all interfaces... "))
    ip_interfaces = get_ip_interfaces()
    virtual_interfaces = get_virtual_devices()
    ignore_interfaces = get_ignore_list()

    for interface in ip_interfaces:
        if interface in ignore_interfaces:
            continue
        down_interface(interface)
        flush_interface(interface)

    for interface in virtual_interfaces:
        if interface in ignore_interfaces:
            continue
        if interface.startswith('one-'):
            continue

        delete_interface(interface)

if __name__ == '__main__':
    main()
