Study and respond to PyLint
Add a reasonably tolerant .pylintrc and fix most pylint errors and warnings. ------------------------------------------------------------------ Your code has been rated at 9.78/10
This commit is contained in:
		@@ -29,6 +29,8 @@ try:
 | 
			
		||||
except ImportError:
 | 
			
		||||
    print("ERROR: install yamale manually: sudo pip install yamale")
 | 
			
		||||
    sys.exit(-2)
 | 
			
		||||
from yamale.validators import DefaultValidators, Validator
 | 
			
		||||
 | 
			
		||||
from config.loopback import validate_loopbacks
 | 
			
		||||
from config.bondethernet import validate_bondethernets
 | 
			
		||||
from config.interface import validate_interfaces
 | 
			
		||||
@@ -36,8 +38,6 @@ from config.bridgedomain import validate_bridgedomains
 | 
			
		||||
from config.vxlan_tunnel import validate_vxlan_tunnels
 | 
			
		||||
from config.tap import validate_taps
 | 
			
		||||
 | 
			
		||||
from yamale.validators import DefaultValidators, Validator
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IPInterfaceWithPrefixLength(Validator):
 | 
			
		||||
    """Custom IPAddress config - takes IP/prefixlen as input:
 | 
			
		||||
@@ -50,22 +50,22 @@ class IPInterfaceWithPrefixLength(Validator):
 | 
			
		||||
 | 
			
		||||
    def _is_valid(self, value):
 | 
			
		||||
        try:
 | 
			
		||||
            network = ipaddress.ip_interface(value)
 | 
			
		||||
            _network = ipaddress.ip_interface(value)
 | 
			
		||||
        except:
 | 
			
		||||
            return False
 | 
			
		||||
        if not isinstance(value, str):
 | 
			
		||||
            return False
 | 
			
		||||
        if not "/" in value:
 | 
			
		||||
            return False
 | 
			
		||||
        e = value.split("/")
 | 
			
		||||
        if not len(e) == 2:
 | 
			
		||||
        elems = value.split("/")
 | 
			
		||||
        if not len(elems) == 2:
 | 
			
		||||
            return False
 | 
			
		||||
        if not e[1].isnumeric():
 | 
			
		||||
        if not elems[1].isnumeric():
 | 
			
		||||
            return False
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Validator(object):
 | 
			
		||||
class Validator:
 | 
			
		||||
    def __init__(self, schema):
 | 
			
		||||
        self.logger = logging.getLogger("vppcfg.config")
 | 
			
		||||
        self.logger.addHandler(logging.NullHandler())
 | 
			
		||||
@@ -81,52 +81,52 @@ class Validator(object):
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def validate(self, yaml):
 | 
			
		||||
        ret_rv = True
 | 
			
		||||
        ret_retval = True
 | 
			
		||||
        ret_msgs = []
 | 
			
		||||
        if not yaml:
 | 
			
		||||
            return ret_rv, ret_msgs
 | 
			
		||||
            return ret_retval, ret_msgs
 | 
			
		||||
 | 
			
		||||
        validators = DefaultValidators.copy()
 | 
			
		||||
        validators[IPInterfaceWithPrefixLength.tag] = IPInterfaceWithPrefixLength
 | 
			
		||||
        if self.schema:
 | 
			
		||||
            fn = self.schema
 | 
			
		||||
            self.logger.debug(f"Validating against --schema {fn}")
 | 
			
		||||
            fname = self.schema
 | 
			
		||||
            self.logger.debug(f"Validating against --schema {fname}")
 | 
			
		||||
        elif hasattr(sys, "_MEIPASS"):
 | 
			
		||||
            ## See vppcfg.spec data_files that includes schema.yaml into the bundle
 | 
			
		||||
            self.logger.debug("Validating against built-in schema")
 | 
			
		||||
            fn = os.path.join(sys._MEIPASS, "schema.yaml")
 | 
			
		||||
            fname = os.path.join(sys._MEIPASS, "schema.yaml")
 | 
			
		||||
        else:
 | 
			
		||||
            fn = "./schema.yaml"
 | 
			
		||||
            self.logger.debug(f"Validating against fallthrough default schema {fn}")
 | 
			
		||||
            fname = "./schema.yaml"
 | 
			
		||||
            self.logger.debug(f"Validating against fallthrough default schema {fname}")
 | 
			
		||||
 | 
			
		||||
        if not os.path.isfile(fn):
 | 
			
		||||
            self.logger.error(f"Cannot file schema file: {fn}")
 | 
			
		||||
        if not os.path.isfile(fname):
 | 
			
		||||
            self.logger.error(f"Cannot file schema file: {fname}")
 | 
			
		||||
            return False, ret_msgs
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            schema = yamale.make_schema(fn, validators=validators)
 | 
			
		||||
            schema = yamale.make_schema(fname, validators=validators)
 | 
			
		||||
            data = yamale.make_data(content=str(yaml))
 | 
			
		||||
            yamale.validate(schema, data)
 | 
			
		||||
            self.logger.debug("Schema correctly validated by yamale")
 | 
			
		||||
        except ValueError as e:
 | 
			
		||||
            ret_rv = False
 | 
			
		||||
            ret_retval = False
 | 
			
		||||
            for result in e.results:
 | 
			
		||||
                for error in result.errors:
 | 
			
		||||
                    ret_msgs.extend([f"yamale: {error}"])
 | 
			
		||||
            return ret_rv, ret_msgs
 | 
			
		||||
            return ret_retval, ret_msgs
 | 
			
		||||
 | 
			
		||||
        self.logger.debug("Validating Semantics...")
 | 
			
		||||
 | 
			
		||||
        for v in self.validators:
 | 
			
		||||
            rv, msgs = v(yaml)
 | 
			
		||||
        for validator in self.validators:
 | 
			
		||||
            retval, msgs = validator(yaml)
 | 
			
		||||
            if msgs:
 | 
			
		||||
                ret_msgs.extend(msgs)
 | 
			
		||||
            if not rv:
 | 
			
		||||
                ret_rv = False
 | 
			
		||||
            if not retval:
 | 
			
		||||
                ret_retval = False
 | 
			
		||||
 | 
			
		||||
        if ret_rv:
 | 
			
		||||
        if ret_retval:
 | 
			
		||||
            self.logger.debug("Semantics correctly validated")
 | 
			
		||||
        return ret_rv, ret_msgs
 | 
			
		||||
        return ret_retval, ret_msgs
 | 
			
		||||
 | 
			
		||||
    def valid_config(self, yaml):
 | 
			
		||||
        """Validate the given YAML configuration in 'yaml' against syntax
 | 
			
		||||
@@ -135,10 +135,10 @@ class Validator(object):
 | 
			
		||||
        Returns True if the configuration is valid, False otherwise.
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        rv, msgs = self.validate(yaml)
 | 
			
		||||
        if not rv:
 | 
			
		||||
            for m in msgs:
 | 
			
		||||
                self.logger.error(m)
 | 
			
		||||
        retval, msgs = self.validate(yaml)
 | 
			
		||||
        if not retval:
 | 
			
		||||
            for msg in msgs:
 | 
			
		||||
                self.logger.error(msg)
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        self.logger.info("Configuration validated successfully")
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,6 @@
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
import config.interface as interface
 | 
			
		||||
import ipaddress
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -27,8 +25,8 @@ def get_all_addresses_except_ifname(yaml, except_ifname):
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            if "addresses" in iface:
 | 
			
		||||
                for a in iface["addresses"]:
 | 
			
		||||
                    ret.append(ipaddress.ip_interface(a))
 | 
			
		||||
                for addr in iface["addresses"]:
 | 
			
		||||
                    ret.append(ipaddress.ip_interface(addr))
 | 
			
		||||
            if "sub-interfaces" in iface:
 | 
			
		||||
                for subid, sub_iface in iface["sub-interfaces"].items():
 | 
			
		||||
                    sub_ifname = f"{ifname}.{int(subid)}"
 | 
			
		||||
@@ -36,24 +34,24 @@ def get_all_addresses_except_ifname(yaml, except_ifname):
 | 
			
		||||
                        continue
 | 
			
		||||
 | 
			
		||||
                    if "addresses" in sub_iface:
 | 
			
		||||
                        for a in sub_iface["addresses"]:
 | 
			
		||||
                            ret.append(ipaddress.ip_interface(a))
 | 
			
		||||
                        for addr in sub_iface["addresses"]:
 | 
			
		||||
                            ret.append(ipaddress.ip_interface(addr))
 | 
			
		||||
    if "loopbacks" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["loopbacks"].items():
 | 
			
		||||
            if ifname == except_ifname:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            if "addresses" in iface:
 | 
			
		||||
                for a in iface["addresses"]:
 | 
			
		||||
                    ret.append(ipaddress.ip_interface(a))
 | 
			
		||||
                for addr in iface["addresses"]:
 | 
			
		||||
                    ret.append(ipaddress.ip_interface(addr))
 | 
			
		||||
    if "bridgedomains" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["bridgedomains"].items():
 | 
			
		||||
            if ifname == except_ifname:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            if "addresses" in iface:
 | 
			
		||||
                for a in iface["addresses"]:
 | 
			
		||||
                    ret.append(ipaddress.ip_interface(a))
 | 
			
		||||
                for addr in iface["addresses"]:
 | 
			
		||||
                    ret.append(ipaddress.ip_interface(addr))
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
@@ -99,8 +97,8 @@ def is_allowed(yaml, ifname, iface_addresses, ip_interface):
 | 
			
		||||
        if my_ip_network.subnet_of(ipaddress.ip_network(ipi, strict=False)):
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    for ip in iface_addresses:
 | 
			
		||||
        ipi = ipaddress.ip_interface(ip)
 | 
			
		||||
    for addr in iface_addresses:
 | 
			
		||||
        ipi = ipaddress.ip_interface(addr)
 | 
			
		||||
        if ipi.version != my_ip_network.version:
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,15 +12,15 @@
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
import config.interface as interface
 | 
			
		||||
import config.mac as mac
 | 
			
		||||
from config import interface
 | 
			
		||||
from config import mac
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_bondethernets(yaml):
 | 
			
		||||
    """Return a list of all bondethernets."""
 | 
			
		||||
    ret = []
 | 
			
		||||
    if "bondethernets" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["bondethernets"].items():
 | 
			
		||||
        for ifname, _iface in yaml["bondethernets"].items():
 | 
			
		||||
            ret.append(ifname)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
@@ -30,7 +30,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
    try:
 | 
			
		||||
        if ifname in yaml["bondethernets"]:
 | 
			
		||||
            return ifname, yaml["bondethernets"][ifname]
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return None, None
 | 
			
		||||
 | 
			
		||||
@@ -38,7 +38,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
def is_bondethernet(yaml, ifname):
 | 
			
		||||
    """Returns True if the interface name is an existing BondEthernet."""
 | 
			
		||||
    ifname, iface = get_by_name(yaml, ifname)
 | 
			
		||||
    return not iface == None
 | 
			
		||||
    return iface is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def is_bond_member(yaml, ifname):
 | 
			
		||||
@@ -46,7 +46,7 @@ def is_bond_member(yaml, ifname):
 | 
			
		||||
    if not "bondethernets" in yaml:
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    for bond, iface in yaml["bondethernets"].items():
 | 
			
		||||
    for _bond, iface in yaml["bondethernets"].items():
 | 
			
		||||
        if not "interfaces" in iface:
 | 
			
		||||
            continue
 | 
			
		||||
        if ifname in iface["interfaces"]:
 | 
			
		||||
@@ -78,7 +78,7 @@ def mode_to_int(mode):
 | 
			
		||||
    ret = {"round-robin": 1, "active-backup": 2, "xor": 3, "broadcast": 4, "lacp": 5}
 | 
			
		||||
    try:
 | 
			
		||||
        return ret[mode]
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return -1
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +92,7 @@ def int_to_mode(mode):
 | 
			
		||||
    ret = {1: "round-robin", 2: "active-backup", 3: "xor", 4: "broadcast", 5: "lacp"}
 | 
			
		||||
    try:
 | 
			
		||||
        return ret[mode]
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return ""
 | 
			
		||||
 | 
			
		||||
@@ -109,7 +109,7 @@ def get_lb(yaml, ifname):
 | 
			
		||||
    if not iface:
 | 
			
		||||
        return None
 | 
			
		||||
    mode = get_mode(yaml, ifname)
 | 
			
		||||
    if not mode in ["xor", "lacp"]:
 | 
			
		||||
    if mode not in ["xor", "lacp"]:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    if not "load-balance" in iface:
 | 
			
		||||
@@ -117,7 +117,7 @@ def get_lb(yaml, ifname):
 | 
			
		||||
    return iface["load-balance"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lb_to_int(lb):
 | 
			
		||||
def lb_to_int(loadbalance):
 | 
			
		||||
    """Returns the integer representation in VPP of a given load-balance strategy,
 | 
			
		||||
    or -1 if 'lb' is not a valid string.
 | 
			
		||||
 | 
			
		||||
@@ -133,13 +133,13 @@ def lb_to_int(lb):
 | 
			
		||||
        "active-backup": 5,
 | 
			
		||||
    }
 | 
			
		||||
    try:
 | 
			
		||||
        return ret[lb]
 | 
			
		||||
    except:
 | 
			
		||||
        return ret[loadbalance]
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return -1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def int_to_lb(lb):
 | 
			
		||||
def int_to_lb(loadbalance):
 | 
			
		||||
    """Returns the string representation in VPP of a given load-balance strategy,
 | 
			
		||||
    or "" if 'lb' is not a valid int.
 | 
			
		||||
 | 
			
		||||
@@ -155,8 +155,8 @@ def int_to_lb(lb):
 | 
			
		||||
        5: "active-backup",
 | 
			
		||||
    }
 | 
			
		||||
    try:
 | 
			
		||||
        return ret[lb]
 | 
			
		||||
    except:
 | 
			
		||||
        return ret[loadbalance]
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return ""
 | 
			
		||||
 | 
			
		||||
@@ -186,7 +186,7 @@ def validate_bondethernets(yaml):
 | 
			
		||||
            )
 | 
			
		||||
            result = False
 | 
			
		||||
        if (
 | 
			
		||||
            not get_mode(yaml, bond_ifname) in ["xor", "lacp"]
 | 
			
		||||
            get_mode(yaml, bond_ifname) not in ["xor", "lacp"]
 | 
			
		||||
            and "load-balance" in iface
 | 
			
		||||
        ):
 | 
			
		||||
            msgs.append(
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,8 @@
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
import config.interface as interface
 | 
			
		||||
import config.loopback as loopback
 | 
			
		||||
import config.lcp as lcp
 | 
			
		||||
import config.address as address
 | 
			
		||||
from config import interface
 | 
			
		||||
from config import loopback
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_bridgedomains(yaml):
 | 
			
		||||
@@ -23,7 +21,7 @@ def get_bridgedomains(yaml):
 | 
			
		||||
    ret = []
 | 
			
		||||
    if not "bridgedomains" in yaml:
 | 
			
		||||
        return ret
 | 
			
		||||
    for ifname, iface in yaml["bridgedomains"].items():
 | 
			
		||||
    for ifname, _iface in yaml["bridgedomains"].items():
 | 
			
		||||
        ret.append(ifname)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
@@ -33,7 +31,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
    try:
 | 
			
		||||
        if ifname in yaml["bridgedomains"]:
 | 
			
		||||
            return ifname, yaml["bridgedomains"][ifname]
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return None, None
 | 
			
		||||
 | 
			
		||||
@@ -41,7 +39,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
def is_bridgedomain(yaml, ifname):
 | 
			
		||||
    """Returns True if the name (bd*) is an existing bridgedomain."""
 | 
			
		||||
    ifname, iface = get_by_name(yaml, ifname)
 | 
			
		||||
    return not iface == None
 | 
			
		||||
    return iface is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_bridge_interfaces(yaml):
 | 
			
		||||
@@ -51,7 +49,7 @@ def get_bridge_interfaces(yaml):
 | 
			
		||||
    if not "bridgedomains" in yaml:
 | 
			
		||||
        return ret
 | 
			
		||||
 | 
			
		||||
    for ifname, iface in yaml["bridgedomains"].items():
 | 
			
		||||
    for _ifname, iface in yaml["bridgedomains"].items():
 | 
			
		||||
        if "interfaces" in iface:
 | 
			
		||||
            ret.extend(iface["interfaces"])
 | 
			
		||||
 | 
			
		||||
@@ -75,11 +73,11 @@ def bvi_unique(yaml, bviname):
 | 
			
		||||
    """Returns True if the BVI identified by bviname is unique among all BridgeDomains."""
 | 
			
		||||
    if not "bridgedomains" in yaml:
 | 
			
		||||
        return True
 | 
			
		||||
    n = 0
 | 
			
		||||
    for ifname, iface in yaml["bridgedomains"].items():
 | 
			
		||||
    ncount = 0
 | 
			
		||||
    for _ifname, iface in yaml["bridgedomains"].items():
 | 
			
		||||
        if "bvi" in iface and iface["bvi"] == bviname:
 | 
			
		||||
            n += 1
 | 
			
		||||
    return n < 2
 | 
			
		||||
            ncount += 1
 | 
			
		||||
    return ncount < 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_settings(yaml, ifname):
 | 
			
		||||
@@ -141,7 +139,6 @@ def validate_bridgedomains(yaml):
 | 
			
		||||
            result = False
 | 
			
		||||
 | 
			
		||||
        if "bvi" in iface:
 | 
			
		||||
            bviname = iface["bvi"]
 | 
			
		||||
            bvi_ifname, bvi_iface = loopback.get_by_name(yaml, iface["bvi"])
 | 
			
		||||
            if not bvi_unique(yaml, bvi_ifname):
 | 
			
		||||
                msgs.append(f"bridgedomain {ifname} BVI {bvi_ifname} is not unique")
 | 
			
		||||
 
 | 
			
		||||
@@ -12,14 +12,14 @@
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
import config.bondethernet as bondethernet
 | 
			
		||||
import config.bridgedomain as bridgedomain
 | 
			
		||||
import config.loopback as loopback
 | 
			
		||||
import config.vxlan_tunnel as vxlan_tunnel
 | 
			
		||||
import config.lcp as lcp
 | 
			
		||||
import config.address as address
 | 
			
		||||
import config.mac as mac
 | 
			
		||||
import config.tap as tap
 | 
			
		||||
from config import bondethernet
 | 
			
		||||
from config import bridgedomain
 | 
			
		||||
from config import loopback
 | 
			
		||||
from config import vxlan_tunnel
 | 
			
		||||
from config import lcp
 | 
			
		||||
from config import address
 | 
			
		||||
from config import mac
 | 
			
		||||
from config import tap
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_qinx_parent_by_name(yaml, ifname):
 | 
			
		||||
@@ -28,7 +28,7 @@ def get_qinx_parent_by_name(yaml, ifname):
 | 
			
		||||
 | 
			
		||||
    if not is_qinx(yaml, ifname):
 | 
			
		||||
        return None, None
 | 
			
		||||
    qinx_ifname, qinx_iface = get_by_name(yaml, ifname)
 | 
			
		||||
    _qinx_ifname, qinx_iface = get_by_name(yaml, ifname)
 | 
			
		||||
    if not qinx_iface:
 | 
			
		||||
        return None, None
 | 
			
		||||
 | 
			
		||||
@@ -54,12 +54,17 @@ def get_qinx_parent_by_name(yaml, ifname):
 | 
			
		||||
 | 
			
		||||
def get_parent_by_name(yaml, ifname):
 | 
			
		||||
    """Returns the sub-interface's parent, or None,None if the sub-int doesn't exist."""
 | 
			
		||||
    if not ifname:
 | 
			
		||||
        return None, None
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        parent_ifname, subid = ifname.split(".")
 | 
			
		||||
        subid = int(subid)
 | 
			
		||||
        iface = yaml["interfaces"][parent_ifname]
 | 
			
		||||
        return parent_ifname, iface
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    except ValueError:
 | 
			
		||||
        pass
 | 
			
		||||
    return None, None
 | 
			
		||||
 | 
			
		||||
@@ -88,20 +93,22 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
            subid = int(subid)
 | 
			
		||||
            iface = yaml["interfaces"][phy_ifname]["sub-interfaces"][subid]
 | 
			
		||||
            return ifname, iface
 | 
			
		||||
        except:
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            return None, None
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            return None, None
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        iface = yaml["interfaces"][ifname]
 | 
			
		||||
        return ifname, iface
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return None, None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def is_sub(yaml, ifname):
 | 
			
		||||
    """Returns True if this interface is a sub-interface"""
 | 
			
		||||
    parent_ifname, parent_iface = get_parent_by_name(yaml, ifname)
 | 
			
		||||
    _parent_ifname, parent_iface = get_parent_by_name(yaml, ifname)
 | 
			
		||||
    return isinstance(parent_iface, dict)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -153,11 +160,11 @@ def get_l2xc_target_interfaces(yaml):
 | 
			
		||||
    """Returns a list of all interfaces that are the target of an L2 CrossConnect"""
 | 
			
		||||
    ret = []
 | 
			
		||||
    if "interfaces" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["interfaces"].items():
 | 
			
		||||
        for _ifname, iface in yaml["interfaces"].items():
 | 
			
		||||
            if "l2xc" in iface:
 | 
			
		||||
                ret.append(iface["l2xc"])
 | 
			
		||||
            if "sub-interfaces" in iface:
 | 
			
		||||
                for subid, sub_iface in iface["sub-interfaces"].items():
 | 
			
		||||
                for _subid, sub_iface in iface["sub-interfaces"].items():
 | 
			
		||||
                    if "l2xc" in sub_iface:
 | 
			
		||||
                        ret.append(sub_iface["l2xc"])
 | 
			
		||||
 | 
			
		||||
@@ -200,11 +207,7 @@ def valid_encapsulation(yaml, ifname):
 | 
			
		||||
        return False
 | 
			
		||||
    if "inner-dot1q" in encap and not ("dot1ad" in encap or "dot1q" in encap):
 | 
			
		||||
        return False
 | 
			
		||||
    if (
 | 
			
		||||
        "exact-match" in encap
 | 
			
		||||
        and encap["exact-match"] == False
 | 
			
		||||
        and has_lcp(yaml, ifname)
 | 
			
		||||
    ):
 | 
			
		||||
    if "exact-match" in encap and not encap["exact-match"] and has_lcp(yaml, ifname):
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    return True
 | 
			
		||||
@@ -227,10 +230,10 @@ def get_encapsulation(yaml, ifname):
 | 
			
		||||
    if not iface:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    parent_ifname, parent_iface = get_parent_by_name(yaml, ifname)
 | 
			
		||||
    _parent_ifname, parent_iface = get_parent_by_name(yaml, ifname)
 | 
			
		||||
    if not iface or not parent_iface:
 | 
			
		||||
        return None
 | 
			
		||||
    parent_ifname, subid = ifname.split(".")
 | 
			
		||||
    _parent_ifname, subid = ifname.split(".")
 | 
			
		||||
 | 
			
		||||
    dot1q = 0
 | 
			
		||||
    dot1ad = 0
 | 
			
		||||
@@ -265,7 +268,7 @@ def get_phys(yaml):
 | 
			
		||||
    ret = []
 | 
			
		||||
    if not "interfaces" in yaml:
 | 
			
		||||
        return ret
 | 
			
		||||
    for ifname, iface in yaml["interfaces"].items():
 | 
			
		||||
    for ifname, _iface in yaml["interfaces"].items():
 | 
			
		||||
        if is_phy(yaml, ifname):
 | 
			
		||||
            ret.append(ifname)
 | 
			
		||||
    return ret
 | 
			
		||||
@@ -275,7 +278,7 @@ def is_phy(yaml, ifname):
 | 
			
		||||
    """Returns True if the ifname is the name of a physical network interface."""
 | 
			
		||||
 | 
			
		||||
    ifname, iface = get_by_name(yaml, ifname)
 | 
			
		||||
    if iface == None:
 | 
			
		||||
    if iface is None:
 | 
			
		||||
        return False
 | 
			
		||||
    if is_sub(yaml, ifname):
 | 
			
		||||
        return False
 | 
			
		||||
@@ -300,7 +303,7 @@ def get_interfaces(yaml):
 | 
			
		||||
        ret.append(ifname)
 | 
			
		||||
        if not "sub-interfaces" in iface:
 | 
			
		||||
            continue
 | 
			
		||||
        for subid, sub_iface in iface["sub-interfaces"].items():
 | 
			
		||||
        for subid, _sub_iface in iface["sub-interfaces"].items():
 | 
			
		||||
            ret.append(f"{ifname}.{int(subid)}")
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
@@ -351,7 +354,7 @@ def unique_encapsulation(yaml, sub_ifname):
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    ncount = 0
 | 
			
		||||
    for subid, sibling_iface in parent_iface["sub-interfaces"].items():
 | 
			
		||||
    for subid, _sibling_iface in parent_iface["sub-interfaces"].items():
 | 
			
		||||
        sibling_ifname = f"{parent_ifname}.{int(subid)}"
 | 
			
		||||
        sibling_encap = get_encapsulation(yaml, sibling_ifname)
 | 
			
		||||
        if sub_encap == sibling_encap and new_ifname != sibling_ifname:
 | 
			
		||||
@@ -391,16 +394,12 @@ def get_mtu(yaml, ifname):
 | 
			
		||||
    """Returns MTU of the interface. If it's not set, return the parent's MTU, and
 | 
			
		||||
    return 1500 if no MTU was set on the sub-int or the parent."""
 | 
			
		||||
    ifname, iface = get_by_name(yaml, ifname)
 | 
			
		||||
    if not iface:
 | 
			
		||||
        return 1500
 | 
			
		||||
 | 
			
		||||
    parent_ifname, parent_iface = get_parent_by_name(yaml, ifname)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
    if iface and "mtu" in iface:
 | 
			
		||||
        return iface["mtu"]
 | 
			
		||||
 | 
			
		||||
    _parent_ifname, parent_iface = get_parent_by_name(yaml, ifname)
 | 
			
		||||
    if parent_iface and "mtu" in parent_iface:
 | 
			
		||||
        return parent_iface["mtu"]
 | 
			
		||||
    except:
 | 
			
		||||
        pass
 | 
			
		||||
    return 1500
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -451,7 +450,7 @@ def validate_interfaces(yaml):
 | 
			
		||||
        iface_address = has_address(yaml, ifname)
 | 
			
		||||
 | 
			
		||||
        if ifname.startswith("tap"):
 | 
			
		||||
            tap_ifname, tap_iface = tap.get_by_name(yaml, ifname)
 | 
			
		||||
            _tap_ifname, tap_iface = tap.get_by_name(yaml, ifname)
 | 
			
		||||
            if not tap_iface:
 | 
			
		||||
                msgs.append(f"interface {ifname} is a TAP but does not exist in taps")
 | 
			
		||||
                result = False
 | 
			
		||||
@@ -489,10 +488,10 @@ def validate_interfaces(yaml):
 | 
			
		||||
            result = False
 | 
			
		||||
 | 
			
		||||
        if "addresses" in iface:
 | 
			
		||||
            for a in iface["addresses"]:
 | 
			
		||||
                if not address.is_allowed(yaml, ifname, iface["addresses"], a):
 | 
			
		||||
            for addr in iface["addresses"]:
 | 
			
		||||
                if not address.is_allowed(yaml, ifname, iface["addresses"], addr):
 | 
			
		||||
                    msgs.append(
 | 
			
		||||
                        f"interface {ifname} IP address {a} conflicts with another"
 | 
			
		||||
                        f"interface {ifname} IP address {addr} conflicts with another"
 | 
			
		||||
                    )
 | 
			
		||||
                    result = False
 | 
			
		||||
 | 
			
		||||
@@ -624,12 +623,12 @@ def validate_interfaces(yaml):
 | 
			
		||||
                            f"sub-interface {sub_ifname} is in L2 mode but has an address"
 | 
			
		||||
                        )
 | 
			
		||||
                        result = False
 | 
			
		||||
                    for a in sub_iface["addresses"]:
 | 
			
		||||
                    for addr in sub_iface["addresses"]:
 | 
			
		||||
                        if not address.is_allowed(
 | 
			
		||||
                            yaml, sub_ifname, sub_iface["addresses"], a
 | 
			
		||||
                            yaml, sub_ifname, sub_iface["addresses"], addr
 | 
			
		||||
                        ):
 | 
			
		||||
                            msgs.append(
 | 
			
		||||
                                f"sub-interface {sub_ifname} IP address {a} conflicts with another"
 | 
			
		||||
                                f"sub-interface {sub_ifname} IP address {addr} conflicts with another"
 | 
			
		||||
                            )
 | 
			
		||||
                            result = False
 | 
			
		||||
                if not valid_encapsulation(yaml, sub_ifname):
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_lcps(yaml, interfaces=True, loopbacks=True, bridgedomains=True):
 | 
			
		||||
@@ -20,20 +19,20 @@ def get_lcps(yaml, interfaces=True, loopbacks=True, bridgedomains=True):
 | 
			
		||||
 | 
			
		||||
    ret = []
 | 
			
		||||
    if interfaces and "interfaces" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["interfaces"].items():
 | 
			
		||||
        for _ifname, iface in yaml["interfaces"].items():
 | 
			
		||||
            if "lcp" in iface:
 | 
			
		||||
                ret.append(iface["lcp"])
 | 
			
		||||
            if "sub-interfaces" in iface:
 | 
			
		||||
                for subid, sub_iface in iface["sub-interfaces"].items():
 | 
			
		||||
                for _subid, sub_iface in iface["sub-interfaces"].items():
 | 
			
		||||
                    if "lcp" in sub_iface:
 | 
			
		||||
                        ret.append(sub_iface["lcp"])
 | 
			
		||||
 | 
			
		||||
    if loopbacks and "loopbacks" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["loopbacks"].items():
 | 
			
		||||
        for _ifname, iface in yaml["loopbacks"].items():
 | 
			
		||||
            if "lcp" in iface:
 | 
			
		||||
                ret.append(iface["lcp"])
 | 
			
		||||
    if bridgedomains and "bridgedomains" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["bridgedomains"].items():
 | 
			
		||||
        for _ifname, iface in yaml["bridgedomains"].items():
 | 
			
		||||
            if "lcp" in iface:
 | 
			
		||||
                ret.append(iface["lcp"])
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,16 +12,16 @@
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
import config.lcp as lcp
 | 
			
		||||
import config.address as address
 | 
			
		||||
import config.mac as mac
 | 
			
		||||
from config import lcp
 | 
			
		||||
from config import address
 | 
			
		||||
from config import mac
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_loopbacks(yaml):
 | 
			
		||||
    """Return a list of all loopbacks."""
 | 
			
		||||
    ret = []
 | 
			
		||||
    if "loopbacks" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["loopbacks"].items():
 | 
			
		||||
        for ifname, _iface in yaml["loopbacks"].items():
 | 
			
		||||
            ret.append(ifname)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
@@ -41,7 +41,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
    try:
 | 
			
		||||
        if ifname in yaml["loopbacks"]:
 | 
			
		||||
            return ifname, yaml["loopbacks"][ifname]
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return None, None
 | 
			
		||||
 | 
			
		||||
@@ -49,7 +49,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
def is_loopback(yaml, ifname):
 | 
			
		||||
    """Returns True if the interface name is an existing loopback."""
 | 
			
		||||
    ifname, iface = get_by_name(yaml, ifname)
 | 
			
		||||
    return not iface == None
 | 
			
		||||
    return iface is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_loopbacks(yaml):
 | 
			
		||||
@@ -75,10 +75,10 @@ def validate_loopbacks(yaml):
 | 
			
		||||
            )
 | 
			
		||||
            result = False
 | 
			
		||||
        if "addresses" in iface:
 | 
			
		||||
            for a in iface["addresses"]:
 | 
			
		||||
                if not address.is_allowed(yaml, ifname, iface["addresses"], a):
 | 
			
		||||
            for addr in iface["addresses"]:
 | 
			
		||||
                if not address.is_allowed(yaml, ifname, iface["addresses"], addr):
 | 
			
		||||
                    msgs.append(
 | 
			
		||||
                        f"loopback {ifname} IP address {a} conflicts with another"
 | 
			
		||||
                        f"loopback {ifname} IP address {addr} conflicts with another"
 | 
			
		||||
                    )
 | 
			
		||||
                    result = False
 | 
			
		||||
        if "mac" in iface and mac.is_multicast(iface["mac"]):
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
import netaddr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -19,7 +18,7 @@ def is_valid(mac):
 | 
			
		||||
    """Return True if the string given in `mac` is a valid (6-byte) MAC address,
 | 
			
		||||
    as defined by netaddr.EUI"""
 | 
			
		||||
    try:
 | 
			
		||||
        addr = netaddr.EUI(mac)
 | 
			
		||||
        _addr = netaddr.EUI(mac)
 | 
			
		||||
    except:
 | 
			
		||||
        return False
 | 
			
		||||
    return True
 | 
			
		||||
 
 | 
			
		||||
@@ -12,14 +12,14 @@
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
import config.mac as mac
 | 
			
		||||
from config import mac
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_taps(yaml):
 | 
			
		||||
    """Return a list of all taps."""
 | 
			
		||||
    ret = []
 | 
			
		||||
    if "taps" in yaml:
 | 
			
		||||
        for ifname, iface in yaml["taps"].items():
 | 
			
		||||
        for ifname, _iface in yaml["taps"].items():
 | 
			
		||||
            ret.append(ifname)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
@@ -29,7 +29,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
    try:
 | 
			
		||||
        if ifname in yaml["taps"]:
 | 
			
		||||
            return ifname, yaml["taps"][ifname]
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return None, None
 | 
			
		||||
 | 
			
		||||
@@ -40,7 +40,7 @@ def is_tap(yaml, ifname):
 | 
			
		||||
    a TAP belonging to a Linux Control Plane (LCP) will return False.
 | 
			
		||||
    """
 | 
			
		||||
    ifname, iface = get_by_name(yaml, ifname)
 | 
			
		||||
    return not iface == None
 | 
			
		||||
    return iface is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def is_host_name_unique(yaml, hostname):
 | 
			
		||||
@@ -48,7 +48,7 @@ def is_host_name_unique(yaml, hostname):
 | 
			
		||||
    if not "taps" in yaml:
 | 
			
		||||
        return True
 | 
			
		||||
    host_names = []
 | 
			
		||||
    for tap_ifname, tap_iface in yaml["taps"].items():
 | 
			
		||||
    for _tap_ifname, tap_iface in yaml["taps"].items():
 | 
			
		||||
        host_names.append(tap_iface["host"]["name"])
 | 
			
		||||
    return host_names.count(hostname) < 2
 | 
			
		||||
 | 
			
		||||
@@ -78,14 +78,14 @@ def validate_taps(yaml):
 | 
			
		||||
            result = False
 | 
			
		||||
 | 
			
		||||
        if "rx-ring-size" in iface:
 | 
			
		||||
            n = iface["rx-ring-size"]
 | 
			
		||||
            if n & (n - 1) != 0:
 | 
			
		||||
            ncount = iface["rx-ring-size"]
 | 
			
		||||
            if ncount & (ncount - 1) != 0:
 | 
			
		||||
                msgs.append(f"tap {ifname} rx-ring-size must be a power of two")
 | 
			
		||||
                result = False
 | 
			
		||||
 | 
			
		||||
        if "tx-ring-size" in iface:
 | 
			
		||||
            n = iface["tx-ring-size"]
 | 
			
		||||
            if n & (n - 1) != 0:
 | 
			
		||||
            ncount = iface["tx-ring-size"]
 | 
			
		||||
            if ncount & (ncount - 1) != 0:
 | 
			
		||||
                msgs.append(f"tap {ifname} tx-ring-size must be a power of two")
 | 
			
		||||
                result = False
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ class TestInterfaceMethods(unittest.TestCase):
 | 
			
		||||
    def test_mtu(self):
 | 
			
		||||
        self.assertEqual(interface.get_mtu(self.cfg, "GigabitEthernet1/0/1"), 9216)
 | 
			
		||||
        self.assertEqual(interface.get_mtu(self.cfg, "GigabitEthernet1/0/1.200"), 9000)
 | 
			
		||||
        self.assertEqual(interface.get_mtu(self.cfg, "GigabitEthernet1/0/1.201"), 1500)
 | 
			
		||||
        self.assertEqual(interface.get_mtu(self.cfg, "GigabitEthernet1/0/1.201"), 9216)
 | 
			
		||||
 | 
			
		||||
    def test_encapsulation(self):
 | 
			
		||||
        self.assertTrue(
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
import logging
 | 
			
		||||
import config.interface as interface
 | 
			
		||||
import ipaddress
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -21,7 +20,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
    try:
 | 
			
		||||
        if ifname in yaml["vxlan_tunnels"]:
 | 
			
		||||
            return ifname, yaml["vxlan_tunnels"][ifname]
 | 
			
		||||
    except:
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return None, None
 | 
			
		||||
 | 
			
		||||
@@ -29,7 +28,7 @@ def get_by_name(yaml, ifname):
 | 
			
		||||
def is_vxlan_tunnel(yaml, ifname):
 | 
			
		||||
    """Returns True if the interface name is an existing VXLAN Tunnel."""
 | 
			
		||||
    ifname, iface = get_by_name(yaml, ifname)
 | 
			
		||||
    return not iface == None
 | 
			
		||||
    return iface is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vni_unique(yaml, vni):
 | 
			
		||||
@@ -38,7 +37,7 @@ def vni_unique(yaml, vni):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    ncount = 0
 | 
			
		||||
    for ifname, iface in yaml["vxlan_tunnels"].items():
 | 
			
		||||
    for _ifname, iface in yaml["vxlan_tunnels"].items():
 | 
			
		||||
        if iface["vni"] == vni:
 | 
			
		||||
            ncount = ncount + 1
 | 
			
		||||
 | 
			
		||||
@@ -51,7 +50,7 @@ def get_vxlan_tunnels(yaml):
 | 
			
		||||
    if not "vxlan_tunnels" in yaml:
 | 
			
		||||
        return ret
 | 
			
		||||
 | 
			
		||||
    for ifname, iface in yaml["vxlan_tunnels"].items():
 | 
			
		||||
    for ifname, _iface in yaml["vxlan_tunnels"].items():
 | 
			
		||||
        ret.append(ifname)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user