import json
import re
import os
from time import sleep
import subprocess
from baseCheck import baseCheck

class nicLink(baseCheck):

    linkregexp = re.compile("\s*Link detected:\s+(\S+)")

    def getHumanName(self):
        return "Check link status across ethernet NICs"
 
    def setUpState(self, server, nic, state):
        try:
            with open(os.devnull,'w') as fnull:
                retval=subprocess.call(['ssh',server,'-o','StrictHostKeyChecking=no','ip','link','set',nic,state],stdout=fnull,stderr=fnull)
                if retval == 0:
                    return True
        except Exception as e:
            self.logMsg("Exception: %s" % str(e))
        self.logMsg("Unable to set %s status of %s to %s on server %s." % (state,nic,state,server))
        return False

    def isLinkUP(self, server, nic):
        try:
            returnstr = subprocess.Popen(['ssh',server,'-o','StrictHostKeyChecking=no','ip','link','show',nic], stdout=subprocess.PIPE).communicate()[0]
            for line in returnstr.split("\n"):
                index1 = line.find('<')
                index2 = line.find('>',index1)
                if (index1 != -1) and (index2 != -1):
                    for attr in line[index1+1:index2].split(','):
                        if attr == 'UP':
                            return True
        except Exception as e:
            self.logMsg("Unable to determine up/down status of %s on server %s." % (nic,server))
            self.logMsg("Exception: %s" % str(e))
        return False

    def getLinkStatus(self, server, nic):
        try:
            returnstr = subprocess.Popen(['ssh',server,'-o','StrictHostKeyChecking=no','ethtool',nic], stdout=subprocess.PIPE).communicate()[0]
            for line in returnstr.split("\n"):
                m = self.linkregexp.match(line)
                if m != None:
                    if m.group(1) == 'yes':
                        return True
                    else:
                        return False
        except Exception as e:
            self.addFailure("Unable to determine link status of %s on server %s." % (nic,server))
            self.logMsg("Exception: %s" % str(e))
        return False

    def addLinkFailure(self, server, nic):
        self.addFailure("Ethernet NIC %s on KVM host server %s does not current have a link.  Please verify your network configuration and connections on this host." % (nic,server))

    def checkLink(self, server, nic):

        # Check if the nic has link already
        if not self.getLinkStatus(server, nic):

            # If the nic is already up, this is a failure
            if self.isLinkUP(server, nic):
                self.addLinkFailure(server,nic)

            # Otherwise, "up" the nic
            elif self.setUpState(server, nic, 'up'):

                # Wait until the NIC is up
                sleep(6)

                # Now that the link is up, get the link status again
                if not self.getLinkStatus(server, nic):
                    self.addLinkFailure(server,nic)

                # Set the nic back down
                self.setUpState(server, nic, 'down')

    def runCheck(self, config, debug):
        # do whatever is desired to check here.
        # return non-zero if an internal error is detected (equivilent to raising an exception)
        # return 0 for both check pass and check fail.
        #    call self.addWarning(text) or self.addWarning(rawText,humanText) for every warning to be logged
        #    call self.addFailure(text) or self.addFailure(rawText,humanText) for every failure to be logged

        # make sure the
        returnCode=0

        for server in config["environment"]["servers"]:

            nic = server["customerNetNIC"]
            if nic != '':
                self.checkLink(server["accessIP"], nic)

            nic = server["privateNetNIC"]
            if nic != '':
                self.checkLink(server["accessIP"], nic)

        return 0
