Пример #1
0
    def _common_cleaner(self, entry):
        chassis_type = entry.get('_chassisType', '')
        if not isinstance(chassis_type, str):
            if chassis_type == 7:
                chassis_type = 'peerHostname'
            else:
                chassis_type = 'unknown'
        chassis_type = chassis_type.lower()
        if chassis_type == 'mac address':
            entry['peerHostname'] = convert_macaddr_format_to_colon(
                entry.get('peerHostname', '0000.0000.0000'))

        subtype = str(entry.get('subtype', '')).lower()
        if subtype in ["interface name", '', '5', '7']:
            entry['peerMacaddr'] = '00:00:00:00:00:00'
            entry['peerIfindex'] = 0
            entry['subtype'] = 'interface name'  # IOS* don't provide subtype
        if subtype == 'mac address':
            entry['peerMacaddr'] = convert_macaddr_format_to_colon(
                entry.get('peerIfname', '0000.0000.0000'))
            entry['peerIfname'] = '-'
            entry['peerIfindex'] = 0
            entry['subtype'] = 'mac address'
        elif subtype.startswith(('locally', '1')):
            if not entry['peerIfname'].isnumeric():
                # lldpd assigns ifname, but calls it locally assigned
                entry['subtype'] = 'interface name'
                entry['peerIfindex'] = 0
                entry['peerMacaddr'] = '00:00:00:00:00:00'
            else:
                entry['peerIfindex'] = entry['peerIfname']
                entry['peerIfname'] = '-'
                entry['peerMacaddr'] = '00:00:00:00:00:00'
                entry['subtype'] = 'locally assigned'
Пример #2
0
    def _clean_nxos_data(self, processed_data, _):

        for entry in processed_data:
            entry['macaddr'] = convert_macaddr_format_to_colon(
                entry.get('macaddr', '0000.0000.0000'))
            vtepIP = re.match(r'(\S+)\(([0-9.]+)\)', entry['oif'])
            if vtepIP:
                entry['remoteVtepIp'] = vtepIP.group(2)
                entry['oif'] = vtepIP.group(1)
                entry['flags'] = 'remote'
            else:
                entry['oif'] = expand_nxos_ifname(entry['oif'])
                entry['remoteVtepIp'] = ''
            if entry.get('vlan', '-') == '-':
                entry['vlan'] = 0
            # Handling old NXOS
            if entry.get('_isStatic', 'disabled') == 'enabled':
                entry['flags'] = 'static'
            flags = entry.get('flags').strip()
            if not flags or (flags == '*'):
                entry['flags'] = 'dynamic'

            self._add_mackey_protocol(entry)

        return processed_data
Пример #3
0
    def find(self, **kwargs) -> pd.DataFrame():
        '''Find network attach point for a given address'''

        addresses = kwargs.get('address', '')

        if not self.ctxt.engine:
            raise AttributeError('No analysis engine specified')

        if not addresses:
            raise AttributeError('Must specify address or asn')

        for addr in addresses:
            try:
                ip_address(addr)
            except ValueError:
                addr = convert_macaddr_format_to_colon(addr)
                if not re.match(
                        "[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$",
                        addr):
                    return pd.DataFrame(
                        {'error': [f'Not valid IP or MAC address: {addr}']})
        try:
            self._check_input_for_valid_args(self._valid_find_args, **kwargs)
        except (ValueError, AttributeError) as error:
            df = pd.DataFrame({'error': [f'{error}']})
            return df

        return self.engine.find(**kwargs)
Пример #4
0
    def _clean_common_ios_data(self, processed_data, _):
        for entry in processed_data:
            if entry['macaddr'] is None:
                entry['state'] = "failed"
                entry['macaddr'] = '00:00:00:00:00:00'
            else:
                entry['macaddr'] = convert_macaddr_format_to_colon(
                    entry.get('macaddr', '0000.0000.0000'))
                entry['state'] = "reachable"
            if ':' in entry['ipAddress']:
                # We need to fix up the interface name for IPv6 ND entriie
                entry['oif'] = expand_ios_ifname(entry.get('oif', ''))

        return processed_data
Пример #5
0
    def _clean_eos_data(self, processed_data, _):
        for entry in processed_data:
            entry['macaddr'] = convert_macaddr_format_to_colon(
                entry.get('macaddr', '0000.0000.0000'))
            # EOS has entries with OIF of type: "Vlan4094, Port-Channel1"
            # We need only the first part, we pick up the second from the
            # MAC table
            if ',' in entry['oif']:
                ports = entry['oif'].split(',')
                entry['oif'] = ports[0].strip()
                if ports[1].strip() == 'Vxlan1':
                    entry['remote'] = True

        return processed_data
Пример #6
0
    def _clean_eos_data(self, processed_data, _):

        drop_indices = []

        for i, entry in enumerate(processed_data):
            entry['oif'] = expand_eos_ifname(entry['oif'])
            if (entry['oif'].startswith('Vxlan')
                    and 'remoteVtepIp' not in entry):
                drop_indices.append(i)
                continue
            if '.' in entry['macaddr']:
                entry['macaddr'] = convert_macaddr_format_to_colon(
                    entry.get('macaddr', '0000.0000.0000'))
            self._add_mackey_protocol(entry)

        processed_data = np.delete(processed_data, drop_indices).tolist()
        return processed_data
Пример #7
0
    def _clean_nxos_data(self, processed_data, _):

        drop_indices = []
        for i, entry in enumerate(processed_data):
            if not entry['ipAddress']:
                drop_indices.append(i)
                continue

            if entry['macaddr'] is None:
                entry['state'] = "failed"
                entry['macaddr'] = '00:00:00:00:00:00'
            else:
                entry['macaddr'] = convert_macaddr_format_to_colon(
                    entry.get('macaddr', '0000.0000.0000'))

        processed_data = np.delete(processed_data, drop_indices).tolist()
        return processed_data
Пример #8
0
    def _find_address(self, addr: str, **kwargs) -> pd.DataFrame:
        """Find the origin or the first hop network device that owns this addr

        Args:
            addr (str): address to search for

        Returns:
            pd.DataFrame: Dataframe with the relevant information
        """

        vlan = kwargs.pop('vlan', '')
        vrf = kwargs.pop('vrf', '')

        # Convert Cisco-style MAC address to standard MAC addr format,
        # and lowercase all letters of the alphabet
        if '.' in addr:
            addr = convert_macaddr_format_to_colon(addr)
        addr = addr.lower()

        addr_df = self._find_addr_arp(addr, **kwargs)
        if addr_df.empty:
            return addr_df
        addr_df = self._find_first_hop_attach(addr_df)
        if vlan and not addr_df.empty:
            addr_df = addr_df.query(f'vlan == {vlan}')
        if vrf and not addr_df.empty:
            addr_df = addr_df.query(f'vrf == "{vrf}"')

        if addr_df.empty:
            return addr_df

        # If routed interface and unnumbered interfaces are used, we need to
        # identify the primary interface
        addr_df = addr_df \
            .dropna() \
            .drop_duplicates(subset=['namespace', 'hostname', 'vrf']) \
            .reset_index(drop=True)

        if addr_df.type.unique().tolist() == ['routed']:
            addr_df = self._find_primary_interface(addr_df, addr)

        return addr_df
Пример #9
0
    def _clean_iosxe_data(self, processed_data, _):

        for entry in processed_data:
            entry['macaddr'] = convert_macaddr_format_to_colon(
                entry.get('macaddr', '0000.0000.0000'))
            oifs = ''
            for oif in entry.get('oif', '').split(','):
                # Handle multicast entries
                oifs += f'{expand_ios_ifname(oif)} '
            if oifs:
                entry['oif'] = oifs.strip()
            else:
                entry['oif'] = expand_ios_ifname(entry['oif'])
            entry['remoteVtepIp'] = ''
            if entry.get('vlan', ' ').strip() == "All":
                entry['vlan'] = 0
            entry['flags'] = entry.get('flags', '').lower()

            self._add_mackey_protocol(entry)

        return processed_data
Пример #10
0
    def _clean_iosxr_data(self, processed_data, raw_data):

        entry_dict = {}
        devtype = raw_data[0].get('devtype', 'iosxr')

        for _, entry in enumerate(processed_data):

            if entry.get('_entryType', '') == 'vrf':
                entry['master'] = ''
                entry['type'] = 'vrf'
                entry['mtu'] = -1
                entry['state'] = entry['adminState'] = 'up'
                entry['macaddr'] = "00:00:00:00:00:00"
                entry['speed'] = NO_SPEED
                continue

            if entry.get('_bondMbrs', ''):
                bond_mbrs = ' '.join(entry['_bondMbrs'])
            else:
                bond_mbrs = ''
            state = entry.get('state', '')
            if 'up' in state:
                # IOSVL2 images show up as up (connected)
                entry['state'] = 'up'
            elif 'down' in state:
                if 'notconnect' in state:
                    entry['state'] = 'notConnected'
                if 'Autostate Enabled' in state:
                    entry['state'] = 'down'
                    entry['reason'] = state.split(',')[1].strip()
                if 'err-disabled' in state:
                    entry['state'] = 'errDisabled'

            iftype = entry.get('type', 'ethernet').lower()
            if '.' in entry.get('ifname', ''):
                iftype = 'subinterface'
            elif iftype in [
                    'aggregated ethernet', 'gechannel', 'etherchannel'
            ]:
                iftype = 'bond'
            elif iftype in ['ethernet', 'igbe', 'csr']:
                iftype = 'ethernet'
            elif any(x in iftype
                     for x in ['gigabit ethernet', 'rp management']):
                iftype = 'ethernet'
            elif iftype.endswith('gige'):
                iftype = 'ethernet'
            elif iftype.endswith('ge'):
                # Is this safe, assuming just ge ending means GigE?
                iftype = 'ethernet'
            elif iftype.endswith('ethernet'):
                iftype = 'ethernet'

            # More iftype processing below before setting it in entry
            speed = self._textfsm_valid_speed_value(entry)
            if speed != MISSING_SPEED:
                speed = int(speed) / 1000  # is in Kbps
            entry['speed'] = speed

            if iftype == 'bond' and bond_mbrs:
                for mbr in bond_mbrs.split():
                    mbr = mbr.strip()
                    # expand the member name
                    mbr = expand_ios_ifname(mbr)
                    if mbr in entry_dict:
                        mbr_entry = entry_dict[mbr]
                        mbr_entry['type'] = 'bond_slave'
                        mbr_entry['master'] = entry['ifname']
                    else:
                        entry_dict[mbr] = {
                            'master': entry['ifname'],
                            'type': 'bond_slave'
                        }

            if entry['adminState'] == 'administratively down':
                entry['state'] = 'down'
                entry['adminState'] = 'down'

            entry['macaddr'] = convert_macaddr_format_to_colon(
                entry.get('macaddr', '0000.0000.0000'))
            if not entry['macaddr']:
                entry['macaddr'] = '00:00:00:00:00:00'
            if entry['type'] == 'null':
                entry['macaddr'] = "00:00:00:00:00:00"
            entry['interfaceMac'] = convert_macaddr_format_to_colon(
                entry.get('interfaceMac', '0000.0000.0000'))

            lastChange = parse(entry.get('statusChangeTimestamp', ''),
                               settings={
                                   'RELATIVE_BASE':
                                   datetime.fromtimestamp(
                                       (raw_data[0]['timestamp']) / 1000),
                               })
            if lastChange:
                entry['statusChangeTimestamp'] = int(lastChange.timestamp() *
                                                     1000)
            if 'ipAddressList' not in entry:
                entry['ipAddressList'] = []
                entry['ip6AddressList'] = []
            elif ':' in entry['ipAddressList']:
                entry['ip6AddressList'] = entry['ipAddressList']
                entry['ipAddressList'] = []
            elif devtype == 'iosxr':
                entry['ip6AddressList'] = []

            if entry['ifname'].startswith('Vlan'):
                iftype = 'vlan'
                if entry.get('vlan', '') == '':
                    entry['vlan'] = entry['ifname'].split('Vlan')[1].strip()
            if entry.get('vlan', '') and entry.get('innerVlan', ''):
                iftype = "qinq"

            entry['type'] = iftype
            # This is specifically for IOSXE/IOS devices where
            # the IPv6 address uses capital letters
            if devtype != 'iosxr':
                entry['ip6AddressList'] = [
                    x.lower() for x in entry.get('ip6AddressList', [])
                ]

            if entry['ifname'].endswith('.0'):
                entry['vlan'] = 0

            if entry['ipAddressList'] == 'Unknown':
                entry['ipAddressList'] = []
                entry['ip6AddressList'] = []

            if entry['ipAddressList'] or entry['ip6AddressList']:
                entry['master'] = entry.get('vrf', '')

            if entry['ifname'] in entry_dict:
                add_info = entry_dict[entry['ifname']]
                entry['master'] = add_info.get('master', '')
                entry['type'] = add_info.get('type', '')
            else:
                entry_dict[entry['ifname']] = entry
        return processed_data
Пример #11
0
    def _clean_nxos_data(self, processed_data, raw_data):
        """Complex cleanup of NXOS interface data"""
        def fix_nxos_speed(entry):
            speed = str(self._common_speed_field_value(entry))
            if isinstance(speed, str):
                speed = speed.strip()
                if speed.startswith("unknown enum") or (speed == "auto"):
                    speed = str(self._get_missing_speed_value(entry))
                elif speed.startswith('a-'):
                    speed = speed[2:]

                if speed.endswith('G'):
                    speed = int(speed[:-1]) * 1000
                elif speed.endswith('Kbit'):
                    speed = int(speed.split()[0]) / 1000
                else:
                    speed = int(speed)

            return speed

        new_entries = []
        unnum_intf = {}
        drop_indices = []
        entry_dict = defaultdict(dict)

        unnum_intf_entry_idx = []  # backtrack to interface to fix

        for entry_idx, entry in enumerate(processed_data):
            # if its the Linux ip link command output, massage the ifname
            # and copy over the values and drop the entry_dict
            if entry.get('_entryType', '') == 'mtumac':
                old_entry = entry_dict[entry['ifname']]
                if old_entry:
                    admin_state = entry['adminState'].lower()
                    if admin_state:
                        if admin_state == "administratively":
                            admin_state = "down"
                        old_entry['adminState'] = admin_state

                    old_entry['mtu'] = entry.get('mtu', 0) or old_entry['mtu']
                    macaddr = entry.get('macaddr', '')
                    if macaddr and not old_entry.get('_anycastMac', ''):
                        # VLAN MAC addr MUST not be replaced due to fabric SVI
                        old_entry['macaddr'] = convert_macaddr_format_to_colon(
                            macaddr)

                    old_entry['numChanges'] = entry['numChanges'] or 0
                    if entry.get('speed', ''):
                        old_entry['speed'] = fix_nxos_speed(entry)

                    lastChange = entry.get('statusChangeTimestamp', '')
                    if lastChange:
                        if any(x in lastChange for x in 'dwmy'):
                            lastChange = f'{lastChange} hours ago'

                        lastChange = parse(
                            lastChange,
                            settings={
                                'RELATIVE_BASE':
                                datetime.fromtimestamp(
                                    (raw_data[0]['timestamp']) / 1000),
                                'TIMEZONE':
                                'UTC'
                            })
                    if lastChange:
                        old_entry['statusChangeTimestamp'] = int(
                            lastChange.timestamp() * 1000)
                    else:
                        old_entry['statusChangeTimestamp'] = 0
                    old_entry['description'] = entry.get('description', '')

                drop_indices.append(entry_idx)
                continue

            entry_dict[entry['ifname']] = entry

            entry["statusChangeTimestamp1"] = entry.get(
                "statusChangeTimestamp", '')

            if entry.get('vrf', ''):
                entry['master'] = entry['vrf']

            if 'routeDistinguisher' in entry:
                # This is a VRF entry
                entry['macaddr'] = "00:00:00:00:00:00"
                entry['adminState'] = entry.get("state", "up").lower()
                entry['state'] = entry.get('state', 'down').lower()
                entry['speed'] = 0
                continue

            if 'reason' in entry:
                if entry['reason'] is not None:
                    entry['reason'] = entry['reason'].lower()

                if entry['reason'] == 'none' or not entry['reason']:
                    entry['reason'] = ''

                if entry['reason'] in [
                        "link not connected", "xcvr not inserted"
                ]:
                    entry['state'] = 'notConnected'

            if entry['reason'] == 'administratively down':
                entry['adminState'] = 'down'
            else:
                entry['adminState'] = 'up'
            portmode = entry.get('_portmode', '')
            if portmode in ['access', 'trunk']:
                entry['master'] = 'bridge'

            portchan = entry.get('_portchannel', 0)
            if portchan:
                entry['master'] = f'port-channel{portchan}'
                entry['type'] = 'bond_slave'

            if entry['ifname'].startswith('port-channel'):
                entry['type'] = 'bond'

            if not entry.get('macaddr', ''):
                entry['macaddr'] = "00:00:00:00:00:00"

            if entry.get('ipAddressList', None):
                pri_ipaddr = f"{entry['ipAddressList']}/{entry['_maskLen']}"
                ipaddr = [pri_ipaddr]
                for i, elem in enumerate(entry.get('_secIPs', [])):
                    if elem:
                        ipaddr.append(f"{elem}/{entry['_secmasklens'][i]}")
                entry['ipAddressList'] = ipaddr
            else:
                entry['ipAddressList'] = []

            if entry.get('ip6AddressList', None):
                if '_linklocal' in entry:
                    entry['ip6AddressList'].append(entry['_linklocal'])
            else:
                entry['ip6AddressList'] = []

            if entry.get('_anycastMac', ''):
                entry['interfaceMac'] = entry.get('macaddr', '')
                entry['macaddr'] = entry['_anycastMac']
                if entry.get('_forwardMode', '') != 'Anycast':
                    entry['reason'] += ', Fabric forwarding mode not enabled'

            entry['macaddr'] = convert_macaddr_format_to_colon(
                entry.get('macaddr', '0000.0000.0000'))

            unnum_if_parent = entry.get('_unnum_intf', '')
            if unnum_if_parent:
                if unnum_if_parent in unnum_intf:
                    # IPv6 has link local, so unnumbered is a v4 construct
                    entry['ipAddressList'] = [unnum_intf[unnum_if_parent]]
                else:
                    unnum_intf_entry_idx.append(entry_idx)

            if entry.get('_child_intf', []):
                unnum_intf[entry['ifname']] = [pri_ipaddr]

            if entry['ifname'] == "mgmt0":
                entry['type'] = "ethernet"

            entry['type'] = entry.get('type', '').lower()
            if entry['type'] == 'eth':
                entry['type'] = 'ethernet'

            if 'ethernet' in entry.get('type', ''):
                entry['type'] = 'ethernet'

            if entry['ifname'].startswith('Vlan'):
                entry['type'] = 'vlan'
            elif re.match(r'.\d+', entry['ifname']):
                entry['type'] = 'subinterface'
            elif entry['ifname'].startswith('nve'):
                entry['type'] = 'vxlan'
                entry['master'] = 'bridge'
            elif entry['ifname'].startswith('loopback'):
                entry['type'] = 'loopback'

            if entry['type'] == 'vlan' and entry['ifname'].startswith('Vlan'):
                entry['vlan'] = int(entry['ifname'].split('Vlan')[1])

            entry['speed'] = fix_nxos_speed(entry)
            # have this at the end to avoid messing up processing

        # Fix unnumbered interface references
        for idx in unnum_intf_entry_idx:
            entry = processed_data[idx]
            entry['ipAddressList'] = unnum_intf.get(entry['_unnum_intf'], [])

        if drop_indices:
            processed_data = np.delete(processed_data, drop_indices).tolist()

        if new_entries:
            processed_data.extend(new_entries)

        return processed_data
Пример #12
0
    def get(self, **kwargs) -> pd.DataFrame:
        """Retrieve the dataframe that matches a given IPv4/v6/MAC address"""

        addr = kwargs.pop("address", [])
        prefix = kwargs.pop("prefix", [])
        columns = kwargs.get("columns", [])
        ipvers = kwargs.pop("ipvers", "")
        user_query = kwargs.pop("query_str", "")

        if user_query:
            if user_query.startswith('"') and user_query.endswith('"'):
                user_query = user_query[1:-1]

        vrf = kwargs.pop("vrf", "")
        addnl_fields = ['master']
        drop_cols = []

        if prefix:
            addr_types = self.addr_type(prefix)
        else:
            addr_types = self.addr_type(addr)

        # Always include ip or mac addresses in the dataframe
        # if there is a filter on them

        if columns not in [['default'], ['*']]:
            if ((4 in addr_types or ipvers == "v4")
                    and 'ipAddressList' not in columns):
                addnl_fields.append('ipAddressList')
                drop_cols.append('ipAddressList')
            if ((6 in addr_types or ipvers == 'v6')
                    and 'ip6AddressList' not in columns):
                addnl_fields.append('ip6AddressList')
                drop_cols.append('ip6AddressList')
            if ((0 in addr_types or ipvers == "l2")
                    and 'macaddr' not in columns):
                addnl_fields.append('macaddr')
                drop_cols.append('macaddr')

        df = self.get_valid_df("address", addnl_fields=addnl_fields, **kwargs)

        if df.empty:
            return df

        df = df.rename({'master': 'vrf'}, axis=1) \
            .replace({'vrf': {'': 'default'}})

        df.loc[(df.vrf == 'bridge') | ((df.ipAddressList.str.len() == 0)
                                       & (df.ip6AddressList.str.len() == 0)),
               'vrf'] = ''

        query_str = build_query_str([], self.schema, vrf=vrf)

        addrcols = []
        if 4 in addr_types or ipvers in ["v4", ""]:
            # df = df.explode('ipAddressList').fillna({'ipAddressList': ''})
            addrcols.append('ipAddressList')

        if 6 in addr_types or ipvers in ["v6", ""]:
            # df = df.explode('ip6AddressList').fillna({'ip6AddressList': ''})
            addrcols.append('ip6AddressList')

        if ('ipAddress' in columns or (columns == ['*'])) and not ipvers:
            ndf = pd.DataFrame(df[addrcols].agg(self._merge_address_cols,
                                                axis=1),
                               columns=['ipAddress'])
            df = pd.concat([df, ndf], axis=1)

        v4addr = []
        v6addr = []
        filter_prefix = ''

        # Address and prefix filtering are mutual exclusive
        if addr:
            macaddr = []
            for i, a in enumerate(addr):
                if addr_types[i] == 0:
                    # convert the macaddr format to internal format
                    if '.' in a:
                        a = convert_macaddr_format_to_colon(a)
                    macaddr.append(a.lower())
                elif addr_types[i] == 4:
                    if '/' not in a:
                        a += '/'
                    v4addr.append(a)
                elif addr_types[i] == 6:
                    if '/' not in a:
                        a += '/'
                    v6addr.append(a)

            # IMPORTANT: Don't mess with this order of query.
            # Some bug in pandas prevents it from working if
            # macaddr isn't first and your query
            # contains both a macaddr and an IP address.
            dfmac = dfv4 = dfv6 = pd.DataFrame()

            if macaddr:
                dfmac = df[df.macaddr.isin(macaddr)]

            if v4addr:
                dfv4 = df[df.ipAddressList.apply(lambda x, addrs: any(
                    a.startswith(tuple(addrs)) for a in x),
                                                 args=(v4addr, ))]
            if v6addr:
                dfv6 = df[df.ip6AddressList.apply(lambda x, addrs: any(
                    a.startswith(tuple(addrs)) for a in x),
                                                  args=(v6addr, ))]
            if v4addr or v6addr or macaddr:
                df = pd.concat([dfv4, dfv6, dfmac])
        elif prefix:
            for i, a in enumerate(prefix):
                if addr_types[i] == 4:
                    v4addr.append(a)
                elif addr_types[i] == 6:
                    v6addr.append(a)

            if v4addr:
                for a in v4addr:
                    query_str += (f'{filter_prefix} '
                                  f'@self._is_in_subnet(ipAddressList,"{a}")')
                    filter_prefix = 'or'
            if v6addr:
                for a in v6addr:
                    query_str += (f'{filter_prefix} '
                                  f'@self._is_in_subnet(ip6AddressList,"{a}")')
                    filter_prefix = 'or'

        if not query_str:
            if ipvers == "v4":
                query_str = 'ipAddressList.str.len() != 0'
            elif ipvers == "v6":
                query_str = 'ip6AddressList.str.len() != 0'
            elif ipvers == "l2":
                query_str = 'macaddr.str.len() != 0'

        if query_str:
            df = df.query(query_str)

        df = self._handle_user_query_str(df, user_query)
        return df.drop(columns=drop_cols, errors='ignore')
Пример #13
0
    def _build_query(self, search_text: str):
        '''Build the appropriate query for the search'''

        state = self._state
        search_text = search_text.replace('\"', '').replace('\'', '')
        if not search_text:
            return '', {}, []

        unique_query = {}

        addrs = search_text.split()
        if not addrs:
            return '', {}, []

        query_str = disjunction = ''
        columns = ['default']

        if addrs[0] not in [
                'mac', 'macs', 'route', 'routes', 'arpnd', 'address', 'vtep',
                'vteps', 'asn', 'asns', 'vlan', 'vlans', 'mtu', 'mtus'
        ]:
            try:
                ip_address(addrs[0])
            except ValueError:
                if not validate_macaddr(addrs[0]):
                    raise ValueError('Invalid keyword or IP/Mac address '
                                     f'"{addrs[0]}"')

        if addrs[0].startswith('mac'):
            state.table = 'macs'
            addrs = addrs[1:]
        elif addrs[0].startswith('route'):
            state.table = 'routes'
            addrs = addrs[1:]
        elif addrs[0] == 'arpnd':
            state.table = 'arpnd'
            addrs = addrs[1:]
        elif addrs[0].startswith('address'):
            state.table = 'network'
            search_text = ' '.join(addrs[1:])
        elif addrs[0].startswith('vtep'):
            state.table = 'evpnVni'
            if addrs[0] != 'vteps':
                query_str = (f'priVtepIp.isin({addrs[1:]}) or '
                             f'secVtepIp.isin({addrs[1:]})')
                columns = ['namespace', 'hostname', 'priVtepIp', 'secVtepIp']
        elif addrs[0].startswith('vni'):
            state.table = 'evpnVni'
            if addrs[0] != 'vnis':
                try:
                    vnis = [int(x) for x in addrs[1:]]
                except ValueError:
                    vnis = []
                query_str = f'vni.isin({vnis})'
                columns = ['namespace', 'hostname', 'vni']
        elif addrs[0].startswith('asn'):
            state.table = 'bgp'
            if addrs[0] != "asns":
                try:
                    asns = [int(x) for x in addrs[1:]]
                except ValueError:
                    asns = []
                query_str = f'asn.isin({asns})'
                columns = ['namespace', 'hostname', 'asn']
        elif addrs[0].startswith('vlan'):
            state.table = 'vlan'
            if addrs[0] != "vlans":
                try:
                    vlans = [int(x) for x in addrs[1:]]
                except ValueError:
                    vlans = []
                query_str = f'vlan.isin({vlans})'
                columns = ['namespace', 'hostname', 'vlan']
        elif addrs[0].startswith('mtu'):
            state.table = 'interface'
            if addrs[0] != "mtus":
                try:
                    mtus = [int(x) for x in addrs[1:]]
                except ValueError:
                    mtus = []
                query_str = f'mtu.isin({mtus})'
                columns = ['namespace', 'hostname', 'mtu']
        else:
            state.table = 'network'

        if state.table == 'network':
            return search_text, unique_query, columns

        for addr in addrs:
            if addr.lower() == 'vteps':
                unique_query = {
                    'table': 'evpnVni',
                    'column': ['priVtepIp', 'secVtepIp'],
                    'colname': 'vteps'
                }
            elif addr.lower() == 'vnis':
                unique_query = {
                    'table': 'evpnVni',
                    'column': ['vni'],
                    'colname': 'vnis'
                }
            elif addr.lower() == 'asns':
                unique_query = {
                    'table': 'bgp',
                    'column': ['asn', 'peerAsn'],
                    'colname': 'asns'
                }
            elif addr.lower() == 'vlans':
                unique_query = {
                    'table': 'vlan',
                    'column': ['vlan'],
                    'colname': 'vlans'
                }
            elif addr.lower() == 'mtus':
                unique_query = {
                    'table': 'interfaces',
                    'column': ['mtu'],
                    'colname': 'mtus'
                }

            elif '::' in addr:
                if state.table == 'arpnd':
                    query_str += f' {disjunction} ipAddress == "{addr}" '
                elif state.table == 'routes':
                    query_str += f'{disjunction} prefix == "{addr}" '
                else:
                    query_str += f' {disjunction} ' \
                        f'ip6AddressList.str.startswith("{addr}/") '
            elif ':' in addr and state.table in ['macs', 'arpnd']:
                query_str += f' {disjunction} macaddr == "{addr}" '
            elif state.table in ['macs', 'arpnd', 'routes']:
                try:
                    addr = ip_address(addr)
                    macaddr = None
                except ValueError:
                    macaddr = convert_macaddr_format_to_colon(addr)
                    addr = None

                if state.table == "macs":
                    query_str = f'{disjunction} macaddr == "{macaddr}" '
                elif state.table == 'arpnd':
                    if addr:
                        query_str += f' {disjunction} ipAddress == "{addr}" '
                    elif macaddr:
                        query_str += f' {disjunction} macaddr == "{macaddr}" '
                elif state.table == 'routes':
                    query_str += f'{disjunction} prefix == "{addr}" '
                else:
                    query_str = ''

            if not disjunction:
                disjunction = 'or'

        state.query_str = query_str
        state.unique_query = unique_query
        return query_str, unique_query, columns
Пример #14
0
    def _clean_nxos_data(self, processed_data, _):
        """Merge peer records with VNI records to yield VNI-based records"""

        vni_dict = {}
        drop_indices = []

        for i, entry in enumerate(processed_data):
            if not entry['vni']:
                drop_indices.append(i)
                continue

            if entry['_entryType'] == 'VNI':
                etype, vrf = entry['type'].split()
                if etype == 'L3':
                    entry['vrf'] = vrf[1:-1]  # strip off '[' and ']'
                entry['type'] = etype
                if 'sviState' in entry:
                    entry['state'] = entry['sviState'].split()[0].lower()
                if re.search(r'[0-9.]+', entry.get('replicationType', '')):
                    entry['mcastGroup'] = entry['replicationType']
                    entry['replicationType'] = 'multicast'
                elif entry['type'] != 'L3':
                    entry['replicationType'] = 'ingressBGP'
                    entry['mcastGroup'] = "0.0.0.0"
                else:
                    entry['replicationType'] = ''
                    entry['mcastGroup'] = "0.0.0.0"

                # we'll fill this with the peers entries
                entry['remoteVtepList'] = []
                entry['state'] = entry['state'].lower()
                entry['vlan'] = int(entry['vlan'])
                vni_dict[entry['vni']] = entry

            elif entry['_entryType'] == 'peers':
                vni_list = convert_rangestring_to_list(
                    entry.get('_vniList', ''))
                for vni in vni_list:
                    vni_entry = vni_dict.get(vni, None)
                    if vni_entry:
                        vni_entry['remoteVtepList'].append(entry['vni'])
                drop_indices.append(i)

            elif entry['_entryType'] == 'iface':
                if entry.get('encapType', '') != "VXLAN":
                    continue

                for vni, val in vni_dict.items():
                    if val['ifname'] != entry['ifname']:
                        continue
                    val['priVtepIp'] = entry.get('priVtepIp', '')
                    secIP = entry.get('secVtepIp', '')
                    if secIP == '0.0.0.0':
                        secIP = ''
                    val['secVtepIp'] = secIP
                    val['routerMac'] = \
                        convert_macaddr_format_to_colon(
                        entry.get('routerMac', '00:00:00:00:00:00'))

                drop_indices.append(i)

        processed_data = np.delete(processed_data, drop_indices).tolist()

        return processed_data