#!/usr/local/bin/python
#-
# Copyright (c) 2015 iXsystems, Inc.
# All rights reserved.
# This file is a part of TrueNAS
# and may not be copied and/or distributed
# without the express permission of iXsystems.

import os
import signal
import sys
import subprocess

sys.path.extend([
    '/usr/local/www',
    '/usr/local/www/freenasUI'
    ])

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'freenasUI.settings')

import django
django.setup()


def get_list_of_interfaces():
    """Returns a list of configured interfaces"""
    intlist = []
    from freenasUI.network.models import Interfaces
    qs = Interfaces.objects.all()
    for i in qs:
        intlist.append(i.int_interface)
    return intlist


def scan_for_vrrp(intlist=None, count=10, timeout=10):
    # Hack to allow this tool to be used as an importable
    # library. In that mode it will be imported and intlist
    # will be a string that is passed in. Otherwise when used
    # from the CLI a list gets passed in. (or a list is
    # returned by get_list_of_interfaces() )
    if not intlist:
        intlist = get_list_of_interfaces()
        auto = True
    else:
        auto = False
        # TODO: Rewrite this whole tool to not need this kind
        # of horrific type coersion.
        if not isinstance(intlist, list):
            intlist = intlist.split()
    for interface in intlist:
        if not interface.startswith("carp"):
            # magic command.  This runs tcpdump looking for VRRP packets.  If
            # none are seen we have a gun in the glovebox that times the
            # tcpdump out after 10 seconds. If we do see VRRP packets we stop
            # after seeing 10 of them.  This number is arbitrary, and if
            # there were more than 10 VRRP devices on the broadcast domain we
            # wouldn't get them all.
            proc = subprocess.Popen(
                "tcpdump -l -n %s -i %s vrrp 2>/dev/null "
                "| awk '{print $3, $9}' | sed -e 's/,$//' " % (
                    '-c %d' % count if count else '',
                    interface,
                ), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, encoding='utf8', preexec_fn=os.setsid)
            try:
                ret = proc.communicate(timeout=timeout)[0].split('\n')
            except subprocess.TimeoutExpired as e:
                ret = e.stdout or ''
                ret = ret.split('\n')
                try:
                    os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
                except Exception:
                    pass

            if auto:
                print("interface: %s" % interface)
                print()
            # The key is the IP, the value is a list of VHIDs.  If there's a
            # single VHID seen the value will be a list of:
            # ['10', '10', '10', '10', '10', '10', '10', '10', '10', '10']
            # not particularly useful but we'll unique that list with a set
            # later
            res = {}
            for item in ret:
                item = item.strip()
                # This should be an IP, VHID pair.  Sometimes it's not because
                # we are trying to parse the userland ouput of a tool by field
                # position.
                if len(item.split()) == 2:
                    ip, vhid = item.split()
                else:
                    continue
                # Check and see if the IP associated with this VHID is local
                # to this machine.  If it is replace the IP with "local"
                # We do this because otherwise it would be possible to get
                # confused between VHIDs we see out on the network and VHIDs
                # we are generating.
                osret = os.system("ifconfig %s | grep -q %s" % (interface, ip))
                if not osret:
                    ip = "local"
                # If we've seen this IP before blindly tack on the VHID to the
                # list of VHIDs.  We don't care if the VHID is a duplicate,
                # we're going to unique the list before displaying it anyways.
                # Otherwise create a new entry for the IP.
                if ip in list(res.keys()):
                    res[ip].append(vhid)
                else:
                    res[ip] = [vhid]
            # I couldn't bring myself to bring in yet another python module for
            # formatting, especially when we don't really have a formatting
            # framework, so this is all banging rocks together until it looks
            # pretty type of stuff.  It's full of magic numbers and arbitrary
            # spaces and...
            if auto:
                print("    source          || vhid")
                print("    =======================")
                if not list(res.keys()):
                    print("    No VHIDs seen on this interface")
                for i in list(res.keys()):
                    pad = 13 - len(i)
                    # join(list(set(res[i]))) gets us the unique vhids in the
                    # list and converts the list to a string which makes for
                    # prettier output.  I'm pretty sure this is an abuse of
                    # set and a list comprehension would be more pythonic.
                    print("   ", i, " " * pad, " || ", \
                          ', '.join(list(set(res[i]))))
                print()
            else:
                r = []
                for item in res:
                    for i in res[item]:
                        r.append(int(i))

                return list(set(r))

if __name__ == '__main__':
    # TODO: argparse
    if len(sys.argv) == 2:
        print(scan_for_vrrp([sys.argv[1]]))
    else:
        scan_for_vrrp()
