#!/usr/bin/env python3
# -*- coding:utf-8 -*-
try:
    import sys
    import importlib

    importlib.reload(sys)
    import os
    import subprocess
    from gspylib.inspection.common import SharedFuncs
    from gspylib.inspection.common.CheckItem import BaseItem
    from gspylib.inspection.common.CheckResult import ResultStatus
    from gspylib.os.gsnetwork import g_network
    from gspylib.os.gsfile import g_file
    from gspylib.os.gsplatform import g_Platform
except ImportError as ie:
    raise Exception("[GAUSS-52200] : Unable to import module: %s." % str(ie))

networkCardNums = []
netWorkLevel = 10000


class CheckMultiQueue(BaseItem):
    def __init__(self):
        super(CheckMultiQueue, self).__init__(self.__class__.__name__)

    def getTeamCardInfo(self, networkNum):
        result = []
        cmd = "export PATH=/bin:/usr/local/bin:/usr/bin:/sbin:/usr/sbin:$PATH && teamdctl %s stat" % networkNum
        status, output = subprocess.getstatusoutput(cmd)
        if status == 0:
            for line in output.splitlines():
                if line.find(":") < 0:
                    result.append(line.strip())
        else:
            result.append(output)
        return status, result

    def adapt_mlx_network(self, networkNum):
        """
        function: adapting for mlx network card
        input: network card name
        return: bus info string or ""
        """
        network_card_cmd = "%s -i %s" % (g_Platform.getEthtoolCmd(), networkNum)
        (status, network_card_info) = subprocess.getstatusoutput(network_card_cmd)
        if status == 0 and network_card_info and network_card_info.find("mlx") >= 0:
            for line in network_card_info.splitlines():
                if line.find("bus-info") >= 0 and len(line.split(": ")) == 2:
                    return line.split(": ")[1]
            return ""
        else:
            return ""

    def getNetworkCard(self):
        networkCard = []
        self.ipAddr, self.service_network_adapt, self.service_network_adapts = \
            SharedFuncs.getLocalIP(self.nodes, self.all_network_info)
        networkNum = self.service_network_adapt.NICNum
        confFile = SharedFuncs.getNetWorkConfFile(networkNum)
        BondMode = g_Platform.getNetworkBondModeInfo(confFile, networkNum)

        if not networkNum or not BondMode or not confFile:
            raise Exception("Failed to obtain network card information.")
        if BondMode != "BondMode Null":
            bondFile = '/proc/net/bonding/%s' % networkNum
            bondInfoList = g_file.readFile(bondFile, "Slave Interface")
            for bondInfo in bondInfoList:
                networkNum = bondInfo.split(':')[-1].strip()
                networkCard.append(networkNum)
        elif g_file.readFile(confFile, "DEVICETYPE=Team") or g_file.readFile(confFile, "TEAM_CONFIG"):
            status, teamInfo = self.getTeamCardInfo(networkNum)
            if status != 0 or not teamInfo:
                raise Exception("Failed to obtain team network card information.")
            networkCard.extend(teamInfo)
        else:
            networkCard.append(networkNum)
        return networkCard

    def parseInterrupt(self, interruptLines):
        lineList = []
        for _ in range(len(interruptLines.splitlines()[0]) - 1):
            for eachLine in interruptLines.splitlines():
                eachLine = eachLine.replace(",", "")
                if not eachLine.lstrip("0") or eachLine.find("f") < 0:
                    lineList.append(eachLine.lstrip("0"))
        return lineList

    def doCheck(self):
        global networkCardNums
        self.result.val = ""
        self.result.raw = ""
        networkCardNums = self.getNetworkCard()

        result = True
        for networkCardNum in networkCardNums:
            lineList = []
            cmdGetSpeedStr = "%s %s | grep 'Speed:'" % (g_Platform.getEthtoolCmd(), networkCardNum)
            (status, output) = subprocess.getstatusoutput(cmdGetSpeedStr)
            if len(output.split('\n')) > 1:
                for line in output.split('\n'):
                    if line.find("Speed:") >= 0:
                        output = line
                        break
            if output.find("Speed:") >= 0 and output.find("Mb/s") >= 0:
                netLevel = int(output.split(':')[1].strip()[:-4])
                if netLevel >= int(netWorkLevel):
                    mlx_bus_info = self.adapt_mlx_network(networkCardNum)
                    if mlx_bus_info:
                        cmd = "for i in `cat /proc/interrupts | grep -w '%s' | awk -F ' ' '{print $1}' | " \
                              "awk -F ':' '{print $1}'`; do cat /proc/irq/$i/smp_affinity ; done" % mlx_bus_info
                    else:
                        cmd = "for i in `cat /proc/interrupts | grep -w '%s' | awk -F ' ' '{print $1}' | " \
                              "awk -F ':' '{print $1}'`; do cat /proc/irq/$i/smp_affinity ; done" % networkCardNum
                    (status, output) = subprocess.getstatusoutput(cmd)
                    self.result.raw += "%s: \n %s \n" % (networkCardNum, output)
                    if status != 0 or not output:
                        self.result.val += "Failed to obtain network card [%s] interrupt value. " \
                                           "Commands for getting interrupt value: %s.\n" % (networkCardNum, cmd)
                        result = False
                        continue
                    try:
                        lineList = self.parseInterrupt(output)
                    except Exception as ex:
                        self.result.val += "Failed to parse the [%s]'s interrupt value." \
                                           "Reason: %s.\nOutput:%s\n" % (networkCardNum, str(ex), output)
                        result = False
                        continue
                else:
                    result = False
                    self.result.val += "Warning: The speed of current card \"%s\" is less than %s Mb/s.\n" % (
                        networkCardNum, netWorkLevel)
            else:
                if output.find("Speed:") >= 0:
                    result = False
                    self.result.val += "Failed to obtain the network card [%s] speed value. " \
                                       "Maybe the network card is not working.\n" % networkCardNum
                else:
                    result = False
                    self.result.val += "Failed to obtain the network card [%s] speed value. Commands for obtain the " \
                                       "network card speed: %s. Error:\n%s\n" % (networkCardNum, cmdGetSpeedStr, output)
            if len(output.splitlines()) * 0.8 > len(set(lineList)):
                result = False
                self.result.val += "Network card [%s] multi-queue support is not enabled.\n" % networkCardNum
        if not result:
            self.result.rst = ResultStatus.NG
        else:
            self.result.rst = ResultStatus.OK

    def doSet(self):
        self.result.val = ""
        cmd = "ps ax | grep -v grep | grep -q irqbalance; echo $?"
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0 and output.strip() == "0":
            kill_irqbalance_cmd = "%s irqbalance" % g_Platform.getKillallCmd()
            os.system(kill_irqbalance_cmd)
        for networkCardNum in networkCardNums:
            mlx_bus_info = self.adapt_mlx_network(networkCardNum)
            if mlx_bus_info:
                cmd = "cat /proc/interrupts | grep -w '%s' | wc -l" % mlx_bus_info
            else:
                cmd = "cat /proc/interrupts | grep -w '%s' | wc -l" % networkCardNum
            (status, output) = subprocess.getstatusoutput(cmd)
            if status != 0:
                self.result.val += " Failed to obtain network card interrupt count numbers. "
            if not str(output.strip()).isdigit():
                count = 0
            else:
                count = int(output.strip())
            i = 0
            while i < count:
                # the dev name type like this: eth1-1, eth1-rx-1, eth1-tx-1, eth1-TxRx-1
                # eth1-rx1, eth-tx1 in arm, get all network name interrupt
                if mlx_bus_info:
                    cmd_IRQ = "cat /proc/interrupts | grep -w '%s' | awk -F ' ' '{print $1}' |" \
                              " awk -F ':' '{print $1}'|awk 'NR==%s'" % (mlx_bus_info, str(i + 1))
                else:
                    cmd_IRQ = "cat /proc/interrupts | grep -w '%s' | awk -F ' ' '{print $1}' |" \
                              " awk -F ':' '{print $1}'|awk 'NR==%s'" % (networkCardNum, str(i + 1))
                (status, output) = subprocess.getstatusoutput(cmd_IRQ)
                if status != 0 or output.strip() == "":
                    self.result.val = "Failed to obtain network card interrupt value." \
                                      " Commands for getting interrupt value: %s." % cmd_IRQ
                else:
                    IRQ = output.strip()
                    self.result.raw += "The network '%s' interrupt configuration path: /proc/irq/%s/smp_affinity." \
                                       % (networkCardNum, IRQ)
                    num = 2 ** i
                    # Under SuSE platform, when the length is greater than 8, the ',' must be used.
                    value = str(hex(num))[2:]
                    # Decimal 63 or more long number sending in L
                    if len(value) > 16 and value[-1] == 'L':
                        value = value[:-1]
                    result_value = ''
                    while len(value) > 8:
                        result_value = ",%s%s" % (value[-8:], result_value)
                        value = value[:-8]
                    result_value = "%s%s" % (value, result_value)

                    cmd_set = "echo '%s'> /proc/irq/%s/smp_affinity" % (result_value, IRQ)
                    (status, output) = subprocess.getstatusoutput(cmd_set)
                    if status != 0:
                        self.result.val += "Failed to set network '%s' IRQ. Commands for setting: %s." \
                                           % (networkCardNum, cmd_set)
                    else:
                        self.result.val += "Set network card '%s' IRQ to \"%s\"." % (networkCardNum, result_value)
                i += 1
