import json
from networkCheck import networkCheck


class checkvLans(networkCheck):
    
    def runCheck(self,config, debug):

        # lots to check here.

        # confirm list of vLanDefinitions and vLanAccess match one for one.
        if "vLanDefinitions" in config["environment"]:

            # then do a bunch of check!
            
            for vLanDef in config["environment"]["vLanDefinitions"]:
                # make sure there is an entry for this vLan in each server
                if vLanDef["name"] != "":
                    # no space in there right?
                    if " " in vLanDef["name"]:
                        # thats a problem.
                        self.addFailure('No whitespace allowed in vLan Names. "'+vLanDef["name"]+'" is invalid')

                    if vLanDef["name"].lower()=="private" or vLanDef["name"].lower()=='customer':
                        self.addFailure("vLan names 'private' and 'customer' are reserved")
                        
                    for server in config["environment"]["servers"]:
                        foundIt=False
                        for vLanAcc in server["vLanAccess"]:
                            if vLanAcc["name"]==vLanDef["name"]:
                                foundIt=True
                        if not foundIt:
                            self.addFailure('No access found for defined vLan '+vLanDef["name"]+' on host '+server["accessIP"]+'. Add a vLan Access entry for this vLan on this host')

            # now make sure every vLan refered to on each host is defined in the environment
            for server in config["environment"]["servers"]:
                for vLanAcc in server["vLanAccess"]:
                    if vLanAcc["name"] != "":
                        # does this vLanAcc name exist in the definition?
                        foundIt=False
                        for vLanDef in config["environment"]["vLanDefinitions"]:
                            if vLanAcc["name"]==vLanDef["name"]:
                                foundIt=True
                        if not foundIt:
                            self.addFailure('vLan '+vLanAcc["name"]+' accessed from server '+server["accessIP"]+' does not exist in the vLanDefinitions.  Add to defintions or remove from access')

            # now make sure every vLan refered to by a VM is actually listed in the definitions
            for server in config["environment"]["servers"]:
                for vm in server["vms"]:
                    for vLan in vm["vLans"]:
                        if vLan["name"] != "":
                            # is this a valid vLan name?
                            foundIt=False
                            for vLanDef in config["environment"]["vLanDefinitions"]:
                                if vLanDef["name"] == vLan["name"]:
                                    foundIt=True
                            if not foundIt:
                                self.addFailure('vLan '+vLan["name"]+' connected to vm '+vm["name"]+' is not defined in the vLanDefinitions. Define the vLan or remove the connection on the vm')
                                    
            # ensure network IP's are different.
            networks = {}
            networks[config["environment"]["privateNetwork"]]="Private"

            for vLanDef in config["environment"]["vLanDefinitions"]:
                # make sure we are not repeating any vLan networks
                if vLanDef["name"] != "":
                    if vLanDef["network"] in networks:
                        # this is bad.
                        self.addFailure('vLan '+vLanDef["name"]+' assigned network address '+vLanDef["network"]+' is already in use by vLan '+networks[vLanDef["network"]]+'. Select a different network')
                    else:
                        networks[vLanDef["network"]]=vLanDef["name"]

            # ensure there is only one databaseVIP assigned
            foundIt=False
            for vLanDef in config["environment"]["vLanDefinitions"]:
                if vLanDef["databaseVIP"] != "":
                    if foundIt:
                        # we have a problem.
                        self.addFailure('Only assign the optional databaseVIP to one of the vLanDefinitions.')
                    else:
                        foundIt=True
            
            # no duplciate netNics per server
            for server in config["environment"]["servers"]:
                netNic={}
                netNic[server["privateNetNIC"]]="Private"
                for vLanAcc in server["vLanAccess"]:
                    if vLanAcc["name"] != "":
                        if vLanAcc["netNic"] != "":
                            if vLanAcc["netNic"] in netNic:
                                # we have a problem
                                self.addFailure('Each vLan needs a unique netNIC per server. vLan '+vLanAcc["name"]+' is using netNic '+vLanAcc["netNic"]+' which is also assigned to '+netNic[vLanAcc["netNic"]]+'. Select a different netNic')
                            else:
                                netNic[vLanAcc["netNic"]]=vLanAcc["name"]
                        else:
                            # its empty - ok if we're ONE server
                            if len(config["environment"]["servers"]) > 1:
                                # not right.
                                self.addFailure('With more than 1 server, physical wiring is needed for vLans.  Provide wiring and netNIC values for each vLan defined')
                    

            # valid network ips assign to servers
            for vLanDef in config["environment"]["vLanDefinitions"]:
                network=vLanDef["network"]
                netmask=vLanDef["netmask"]
                name=vLanDef["name"]
                # find the matching vLanAccess for each server
                for server in config["environment"]["servers"]:
                    # you will find this vLan in here - we check above for that.
                    for vLanAcc in server["vLanAccess"]:
                        if vLanAcc["name"]==name:
                            # this is the one!
                            if vLanAcc["netNicIP"] == "":
                                # problem.
                                self.addFailure('Each server needs a static IP in the vLans defined. Provide a static address for server '+server["accessIP"]+' on vLan '+vLanAcc["name"])
                            elif vLanAcc["netNicIP"] == 'dhcp':
                                    # nope.
                                    self.addFailure('Each server needs a static IP in the vLans defined - dhcp is not supported. Provide a static address for server '+server["accessIP"]+' on vLan '+vLanAcc["name"])
                            else:
                                if not self.checkNetwork(vLanAcc["netNicIP"],network,netmask):
                                    self.addFailure('Supplied static IP '+vLanAcc["netNicIP"]+' for server '+server["accessIP"]+' in vLan '+name+' is invalid in network '+network+' with netmask '+netmask)
                    # valid vlan ips assigned to vms
                    for vm in server["vms"]:
                        for vLan in vm["vLans"]:
                            if vLan["name"]!="":
                                # does this assigned ip fit?
                                if vLan["name"]==name:
                                    vmIP=vLan["IP"]
                                    if vmIP == "":
                                        # no.  must provide IP
                                        self.addFailure('vLan '+vLan["name"]+' on vm '+vm["name"]+' must supply a vLan IP or specify dhcp')
                                    elif vmIP != "dhcp":
                                        # then its static
                                        if not self.checkNetwork(vmIP, network, netmask):
                                            self.addFailure('Supplied static IP '+vmIP+' for vLan '+vLan["name"]+' on vm '+vm["name"]+' is invalid in network '+network+' with netmask '+netmask)
                                                    
            # if using a vLan for db access - make sure all db related clustertypes are ON that vLan
            dbvLanName=""
            for vLanDef in config["environment"]["vLanDefinitions"]:
                if vLanDef["databaseVIP"] != "":
                    dbvLanName=vLanDef["name"]
                    if not self.checkNetwork(vLanDef["databaseVIP"],vLanDef["network"],vLanDef["netmask"]):
                        self.addFailure('Supplied databaseVIP '+vLanDef["databaseVIP"]+' is invalid for network '+vLanDef["network"]+' with netmask '+vLanDef["netmask"])

            if dbvLanName != "":
                # then check that every vm that needs access to the db is a member of this vLan
                dbClusterGroups = [ 'edb','app','es','pt' ]
                for server in config["environment"]["servers"]:
                    for vm in server["vms"]:
                        if vm["clusterGroup"] in dbClusterGroups:
                            # then this vm needs to be on the db vLan
                            foundIt=False
                            for vLan in vm["vLans"]:
                                if vLan["name"]==dbvLanName:
                                    foundIt=True
                            if not foundIt:
                                # this is a problem
                                self.addFailure('VM '+vm["name"]+' needs access to the database and therefore must be a part of vLan '+dbvLanName+'. Add this vLan to this VM')
                                
        return 0
    
    def getHumanName(self):
        return "Check vLan Configuration"
