Example #1
0
def compare(src, dst):
    if isinstance(src, py23_compat.string_types):
        src = py23_compat.text_type(src)

    if isinstance(src, dict):
        mode = _mode(src.pop('_mode', ''))
        if 'list' in src.keys():
            if not isinstance(dst, list):
                # This can happen with nested lists
                return False

            return _compare_getter_list(src['list'], dst, mode)
        return _compare_getter_dict(src, dst, mode)

    elif isinstance(src, py23_compat.string_types):
        if src.startswith('<') or src.startswith('>'):
            cmp_result = _compare_numeric(src, dst)
            return cmp_result
        else:
            m = re.search(src, py23_compat.text_type(dst))
            if m:
                return bool(m)
            else:
                return src == dst

    elif(type(src) == type(dst) == list):
        pairs = zip(src, dst)
        diff_lists = [[(k, x[k], y[k])
                      for k in x if not re.search(x[k], y[k])]
                      for x, y in pairs if x != y]
        return empty_tree(diff_lists)

    else:
        return src == dst
Example #2
0
    def get_bgp_neighbors(self):
        results = {}
        bgp_state_dict = {
            'Idle': {'is_up': False, 'is_enabled': True},
            'Active': {'is_up': False, 'is_enabled': True},
            'Open': {'is_up': False, 'is_enabled': True},
            'Established': {'is_up': True, 'is_enabled': True},
            'Closing': {'is_up': True, 'is_enabled': True},
            'Shutdown': {'is_up': False, 'is_enabled': False},
        }

        try:
            cmd = 'show bgp sessions vrf all'
            vrf_list = self._get_command_table(cmd, 'TABLE_vrf', 'ROW_vrf')
        except CLIError:
            vrf_list = []

        for vrf_dict in vrf_list:
            result_vrf_dict = {}
            result_vrf_dict['router_id'] = py23_compat.text_type(vrf_dict['router-id'])
            result_vrf_dict['peers'] = {}
            neighbors_list = vrf_dict.get('TABLE_neighbor', {}).get('ROW_neighbor', [])

            if isinstance(neighbors_list, dict):
                neighbors_list = [neighbors_list]

            for neighbor_dict in neighbors_list:
                neighborid = napalm.base.helpers.ip(neighbor_dict['neighbor-id'])
                remoteas = napalm.base.helpers.as_number(neighbor_dict['remoteas'])
                state = py23_compat.text_type(neighbor_dict['state'])

                bgp_state = bgp_state_dict[state]

                result_peer_dict = {
                    'local_as': int(vrf_dict['local-as']),
                    'remote_as': remoteas,
                    'remote_id': neighborid,
                    'is_enabled': bgp_state['is_enabled'],
                    'uptime': -1,
                    'description': '',
                    'is_up': bgp_state['is_up'],
                }
                result_peer_dict['address_family'] = {
                    'ipv4': {
                        'sent_prefixes': -1,
                        'accepted_prefixes': -1,
                        'received_prefixes': -1
                    }
                }
                result_vrf_dict['peers'][neighborid] = result_peer_dict

            vrf_name = vrf_dict['vrf-name-out']
            if vrf_name == 'default':
                vrf_name = 'global'
            results[vrf_name] = result_vrf_dict
        return results
Example #3
0
 def test_context_manager(self):
     with pytest.raises(napalm.base.exceptions.ConnectionException) as e, \
             driver("blah", "bleh", "blih", optional_args=fail_args) as d:
         pass
     assert "You told me to do this" in py23_compat.text_type(e.value)
     with pytest.raises(AttributeError) as e, \
             driver("blah", "bleh", "blih", optional_args=optional_args) as d:
         assert d.is_alive() == {u'is_alive': True}
         d.__fake_call()
     assert d.is_alive() == {u'is_alive': False}
     assert "object has no attribute" in py23_compat.text_type(e.value)
Example #4
0
    def get_config(self, retrieve='all'):
        config = {
            'startup': '',
            'running': '',
            'candidate': ''
        }  # default values

        if retrieve.lower() in ('running', 'all'):
            command = 'show running-config'
            config['running'] = py23_compat.text_type(self._send_command(command, raw_text=True))
        if retrieve.lower() in ('startup', 'all'):
            command = 'show startup-config'
            config['startup'] = py23_compat.text_type(self._send_command(command, raw_text=True))
        return config
Example #5
0
    def get_facts(self):
        """Return a set of facts from the devices."""
        # default values.
        vendor = "Mellanox"
        uptime = -1
        os_version, hostname, model = ("", ) * 3

        # obtain output from device
        show_ver = self._send_command("show version")
        show_hosts = self._send_command("show hosts")
        show_int_status = self._send_command("show interface status")

        # uptime/serial_number/IOS version
        for line in show_ver.splitlines():
            if "Uptime:" in line:
                _, uptime_str = line.split("Uptime:")
                uptime = self.parse_uptime(uptime_str)

            if "Product release:" in line:
                line = line.strip()
                os_version = line.split()[2]
                os_version = os_version.strip()

            if "Product model:" in line:
                line = line.strip()
                model = line.split()[2]

        for line in show_hosts.splitlines():
            if "Hostname: " in line:
                _, hostname = line.split("Hostname: ")
                break

        interface_list = []
        for line in show_int_status.splitlines():
            if line == '':
                continue
            elif line.startswith('E') or line.startswith('m'):
                interface = line.split()[0]
                # Return canonical interface name
                interface_list.append(
                    helpers.canonical_interface_name(interface))

        return {
            "uptime": int(uptime),
            "vendor": vendor,
            "os_version": py23_compat.text_type(os_version),
            "model": py23_compat.text_type(model),
            "hostname": py23_compat.text_type(hostname),
            "interface_list": interface_list,
        }
Example #6
0
    def get_config(self, retrieve='all'):
        config = {
            'startup': '',
            'running': '',
            'candidate': ''
        }  # default values

        if retrieve.lower() in ('running', 'all'):
            _cmd = 'show running-config'
            config['running'] = py23_compat.text_type(self.cli([_cmd]).get(_cmd))
        if retrieve.lower() in ('startup', 'all'):
            _cmd = 'show startup-config'
            config['startup'] = py23_compat.text_type(self.cli([_cmd]).get(_cmd))
        return config
Example #7
0
    def test_not_mocking_getters(self):
        d = driver("blah", "bleh", "blih", optional_args=optional_args)
        d.open()

        with pytest.raises(NotImplementedError) as excinfo:
            d.get_route_to()
        expected = "You can provide mocked data in {}/get_route_to.1".format(optional_args["path"])
        assert expected in py23_compat.text_type(excinfo.value)

        with pytest.raises(NotImplementedError) as excinfo:
            d.get_route_to()
        expected = "You can provide mocked data in {}/get_route_to.2".format(optional_args["path"])
        assert expected in py23_compat.text_type(excinfo.value)

        d.close()
Example #8
0
    def get_network_instances(self, name=''):
        """ get_network_instances implementation for NX-OS """

        # command 'show vrf detail' returns all VRFs with detailed information
        # format: list of dictionaries with keys such as 'vrf_name' and 'rd'
        command = u'show vrf detail'
        vrf_table_raw = self._get_command_table(command, u'TABLE_vrf', u'ROW_vrf')

        # command 'show vrf interface' returns all interfaces including their assigned VRF
        # format: list of dictionaries with keys 'if_name', 'vrf_name', 'vrf_id' and 'soo'
        command = u'show vrf interface'
        intf_table_raw = self._get_command_table(command, u'TABLE_if', u'ROW_if')

        # create a dictionary with key = 'vrf_name' and value = list of interfaces
        vrf_intfs = defaultdict(list)
        for intf in intf_table_raw:
            vrf_intfs[intf[u'vrf_name']].append(py23_compat.text_type(intf['if_name']))

        vrfs = {}
        for vrf in vrf_table_raw:
            vrf_name = py23_compat.text_type(vrf.get('vrf_name'))
            vrfs[vrf_name] = {}
            vrfs[vrf_name][u'name'] = vrf_name

            # differentiate between VRF type 'DEFAULT_INSTANCE' and 'L3VRF'
            if vrf_name == u'default':
                vrfs[vrf_name][u'type'] = u'DEFAULT_INSTANCE'
            else:
                vrfs[vrf_name][u'type'] = u'L3VRF'

            vrfs[vrf_name][u'state'] = {u'route_distinguisher':
                                        py23_compat.text_type(vrf.get('rd'))}

            # convert list of interfaces (vrf_intfs[vrf_name]) to expected format
            # format = dict with key = interface name and empty values
            vrfs[vrf_name][u'interfaces'] = {}
            vrfs[vrf_name][u'interfaces'][u'interface'] = dict.fromkeys(vrf_intfs[vrf_name], {})

        # if name of a specific VRF was passed as an argument
        # only return results for this particular VRF
        if name:
            if name in vrfs.keys():
                return {py23_compat.text_type(name): vrfs[name]}
            else:
                return {}
        # else return results for all VRFs
        else:
            return vrfs
Example #9
0
    def get_lldp_neighbors(self):
        """ProCurve implementation of get_lldp_neighbors."""
        lldp = {}
        command = 'show lldp info remote-device'
        output = self._send_command(command)

        # Check if system supports the command
        if 'Invalid input:' in output:
            return {}

        # Process the output to obtain just the LLDP entries
        try:
            split_output = re.split(r'^.*--------.*$', output, flags=re.M)[1]
        except IndexError:
            return {}

        split_output = split_output.strip()

        for lldp_entry in split_output.splitlines():
            # Example, 1         | 00 25 90 3d c3 1f         eth0   eth0      (none).(none)
            # Example Arubat,   A4        | 000ce6-38d120      00 0c e6 38 d1 20  eth0      blnap013

            local_port = lldp_entry.strip().split(' ', 1)[0].strip()

            if '...' in lldp_entry:
                # ... means something got truncated, we need to look at
                # the details to get the full output
                remote_port, device_id = self._get_lldp_neighbors_detail(
                    local_port)
            else:
                try:
                    (local_port, delim, chassis_id, r_01, r_02, r_03, r_04,
                     r_05, r_06, remote_port_desc,
                     device_id) = lldp_entry.split()
                    port_id = '{}:{}:{}:{}:{}:{}'.format(
                        r_01, r_02, r_03, r_04, r_05, r_06)
                except ValueError:
                    remote_port, device_id = self._get_lldp_neighbors_detail(
                        local_port)

            entry = {
                'port': py23_compat.text_type(remote_port_desc),
                'hostname': py23_compat.text_type(device_id)
            }
            lldp.setdefault(local_port, [])
            lldp[local_port].append(entry)

        return lldp
Example #10
0
def ip(addr, version=None):
    """
    Converts a raw string to a valid IP address. Optional version argument will detect that \
    object matches specified version.

    Motivation: the groups of the IP addreses may contain leading zeros. IPv6 addresses can \
    contain sometimes uppercase characters. E.g.: 2001:0dB8:85a3:0000:0000:8A2e:0370:7334 has \
    the same logical value as 2001:db8:85a3::8a2e:370:7334. However, their values as strings are \
    not the same.

    :param raw: the raw string containing the value of the IP Address
    :param version: (optional) insist on a specific IP address version.
    :type version: int.
    :return: a string containing the IP Address in a standard format (no leading zeros, \
    zeros-grouping, lowercase)

    Example:

    .. code-block:: python

        >>> ip('2001:0dB8:85a3:0000:0000:8A2e:0370:7334')
        u'2001:db8:85a3::8a2e:370:7334'
    """
    addr_obj = IPAddress(addr)
    if version and addr_obj.version != version:
        raise ValueError("{} is not an ipv{} address".format(addr, version))
    return py23_compat.text_type(addr_obj)
Example #11
0
def canonical_interface_name(interface, addl_name_map=None):
    """Function to return an interface's canonical name (fully expanded name).

    Use of explicit matches used to indicate a clear understanding on any potential
    match. Regex and other looser matching methods were not implmented to avoid false
    positive matches. As an example, it would make sense to do "[P|p][O|o]" which would
    incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not
    easily troubleshot, found, or known.

    :param interface: The interface you are attempting to expand.
    :param addl_name_map (optional): A dict containing key/value pairs that updates
    the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs
    {"Po": "Port-Channel"}
    """

    name_map = {}
    name_map.update(base_interfaces)
    interface_type, interface_number = split_interface(interface)

    if isinstance(addl_name_map, dict):
        name_map.update(addl_name_map)
    # check in dict for mapping
    if name_map.get(interface_type):
        long_int = name_map.get(interface_type)
        return long_int + py23_compat.text_type(interface_number)
    # if nothing matched, return the original name
    else:
        return interface
Example #12
0
def ip(addr, version=None):
    """
    Converts a raw string to a valid IP address. Optional version argument will detect that \
    object matches specified version.

    Motivation: the groups of the IP addreses may contain leading zeros. IPv6 addresses can \
    contain sometimes uppercase characters. E.g.: 2001:0dB8:85a3:0000:0000:8A2e:0370:7334 has \
    the same logical value as 2001:db8:85a3::8a2e:370:7334. However, their values as strings are \
    not the same.

    :param raw: the raw string containing the value of the IP Address
    :param version: (optional) insist on a specific IP address version.
    :type version: int.
    :return: a string containing the IP Address in a standard format (no leading zeros, \
    zeros-grouping, lowercase)

    Example:

    .. code-block:: python

        >>> ip('2001:0dB8:85a3:0000:0000:8A2e:0370:7334')
        u'2001:db8:85a3::8a2e:370:7334'
    """
    addr_obj = IPAddress(addr)
    if version and addr_obj.version != version:
        raise ValueError("{} is not an ipv{} address".format(addr, version))
    return py23_compat.text_type(addr_obj)
Example #13
0
def canonical_interface_name(interface, addl_name_map=None):
    """Function to return an interface's canonical name (fully expanded name).

    Use of explicit matches used to indicate a clear understanding on any potential
    match. Regex and other looser matching methods were not implmented to avoid false
    positive matches. As an example, it would make sense to do "[P|p][O|o]" which would
    incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not
    easily troubleshot, found, or known.

    :param interface: The interface you are attempting to expand.
    :param addl_name_map (optional): A dict containing key/value pairs that updates
    the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs
    {"Po": "Port-Channel"}
    """

    name_map = {}
    name_map.update(base_interfaces)
    interface_type, interface_number = split_interface(interface)

    if isinstance(addl_name_map, dict):
        name_map.update(addl_name_map)
    # check in dict for mapping
    if name_map.get(interface_type):
        long_int = name_map.get(interface_type)
        return long_int + py23_compat.text_type(interface_number)
    # if nothing matched, return the original name
    else:
        return interface
Example #14
0
    def get_config(self, retrieve='all'):
        config = {
            'startup': '',
            'running': '',
            'candidate': ''
        }  # default values

        if retrieve.lower() in ('running', 'all'):
            _cmd = 'show running-config'
            config['running'] = py23_compat.text_type(
                self.cli([_cmd]).get(_cmd))
        if retrieve.lower() in ('startup', 'all'):
            _cmd = 'show startup-config'
            config['startup'] = py23_compat.text_type(
                self.cli([_cmd]).get(_cmd))
        return config
Example #15
0
    def get_interfaces(self):
        interfaces = {}
        iface_cmd = 'show interface'
        interfaces_out = self.device.show(iface_cmd)
        interfaces_body = interfaces_out['TABLE_interface']['ROW_interface']

        for interface_details in interfaces_body:
            interface_name = interface_details.get('interface')
            # Earlier version of Nexus returned a list for 'eth_bw' (observed on 7.1(0)N1(1a))
            interface_speed = interface_details.get('eth_bw', 0)
            if isinstance(interface_speed, list):
                interface_speed = interface_speed[0]
            interface_speed = int(interface_speed / 1000)
            if 'admin_state' in interface_details:
                is_up = interface_details.get('admin_state', '') == 'up'
            else:
                is_up = interface_details.get('state', '') == 'up'
            interfaces[interface_name] = {
                'is_up':
                is_up,
                'is_enabled': (interface_details.get('state') == 'up'),
                'description':
                py23_compat.text_type(
                    interface_details.get('desc', '').strip('"')),
                'last_flapped':
                self._compute_timestamp(
                    interface_details.get('eth_link_flapped', '')),
                'speed':
                interface_speed,
                'mac_address':
                napalm.base.helpers.convert(
                    napalm.base.helpers.mac,
                    interface_details.get('eth_hw_addr')),
            }
        return interfaces
Example #16
0
def mac(raw):
    """
    Converts a raw string to a standardised MAC Address EUI Format.

    :param raw: the raw string containing the value of the MAC Address
    :return: a string with the MAC Address in EUI format

    Example:

    .. code-block:: python

        >>> mac('0123.4567.89ab')
        u'01:23:45:67:89:AB'

    Some vendors like Cisco return MAC addresses like a9:c5:2e:7b:6: which is not entirely valid
    (with respect to EUI48 or EUI64 standards). Therefore we need to stuff with trailing zeros

    Example
    >>> mac('a9:c5:2e:7b:6:')
    u'A9:C5:2E:7B:60:00'

    If Cisco or other obscure vendors use their own standards, will throw an error and we can fix
    later, however, still works with weird formats like:

    >>> mac('123.4567.89ab')
    u'01:23:45:67:89:AB'
    >>> mac('23.4567.89ab')
    u'00:23:45:67:89:AB'
    """
    if raw.endswith(':'):
        flat_raw = raw.replace(':', '')
        raw = '{flat_raw}{zeros_stuffed}'.format(flat_raw=flat_raw,
                                                 zeros_stuffed='0' *
                                                 (12 - len(flat_raw)))
    return py23_compat.text_type(EUI(raw, dialect=_MACFormat))
Example #17
0
    def get_interfaces(self):
        interfaces = {}
        iface_cmd = 'show interface'
        interfaces_out = self.device.show(iface_cmd)
        interfaces_body = interfaces_out['TABLE_interface']['ROW_interface']

        for interface_details in interfaces_body:
            interface_name = interface_details.get('interface')
            # Earlier version of Nexus returned a list for 'eth_bw' (observed on 7.1(0)N1(1a))
            interface_speed = interface_details.get('eth_bw', 0)
            if isinstance(interface_speed, list):
                interface_speed = interface_speed[0]
            interface_speed = int(interface_speed / 1000)
            if 'admin_state' in interface_details:
                is_up = interface_details.get('admin_state', '') == 'up'
            else:
                is_up = interface_details.get('state', '') == 'up'
            interfaces[interface_name] = {
                'is_up': is_up,
                'is_enabled': (interface_details.get('state') == 'up'),
                'description': py23_compat.text_type(interface_details.get('desc', '').strip('"')),
                'last_flapped': self._compute_timestamp(
                    interface_details.get('eth_link_flapped', '')),
                'speed': interface_speed,
                'mac_address': napalm.base.helpers.convert(
                    napalm.base.helpers.mac, interface_details.get('eth_hw_addr')),
            }
        return interfaces
Example #18
0
File: ce.py Project: JurgenOS/PyNet
 def _create_tmp_file(config):
     tmp_dir = tempfile.gettempdir()
     rand_fname = py23_compat.text_type(uuid.uuid4())
     filename = os.path.join(tmp_dir, rand_fname)
     with open(filename, 'wt') as fobj:
         fobj.write(config)
     return filename
Example #19
0
    def get_ntp_servers(self):
        """Returns the NTP servers configuration as dictionary."""

        ntp_servers = {}
        command = 'show sntp'
        output = self._send_command(command)

        if 'Invalid input' in output:
            raise ValueError("Command not supported by network device")

        try:
            split_sntp = re.split(r'^  -----.*$', output,
                                  flags=re.M)[1].strip()

        except IndexError:
            return {}

        if 'Priority' in output:
            server_idx = 1
        else:
            server_idx = 0

        for line in split_sntp.splitlines():
            split_line = line.split()
            ntp_servers[py23_compat.text_type(split_line[server_idx])] = {}

        return ntp_servers
Example #20
0
 def _read_wrapper(data):
     """Ensure unicode always returned on read."""
     # Paramiko (strangely) in PY3 returns an int here.
     if isinstance(data, int):
         data = chr(data)
     # Ensure unicode
     return py23_compat.text_type(data)
Example #21
0
    def get_users(self):
        _CISCO_TO_CISCO_MAP = {
            'network-admin': 15,
            'network-operator': 5
        }

        _DEFAULT_USER_DICT = {
            'password': '',
            'level': 0,
            'sshkeys': []
        }

        users = {}
        command = 'show running-config'
        section_username_raw_output = self.cli([command]).get(command, '')
        section_username_tabled_output = napalm.base.helpers.textfsm_extractor(
            self, 'users', section_username_raw_output)

        for user in section_username_tabled_output:
            username = user.get('username', '')
            if not username:
                continue
            if username not in users:
                users[username] = _DEFAULT_USER_DICT.copy()

            password = user.get('password', '')
            if password:
                users[username]['password'] = py23_compat.text_type(password.strip())

            level = 0
            role = user.get('role', '')
            if role.startswith('priv'):
                level = int(role.split('-')[-1])
            else:
                level = _CISCO_TO_CISCO_MAP.get(role, 0)
            if level > users.get(username).get('level'):
                # unfortunately on Cisco you can set different priv levels for the same user
                # Good news though: the device will consider the highest level
                users[username]['level'] = level

            sshkeytype = user.get('sshkeytype', '')
            sshkeyvalue = user.get('sshkeyvalue', '')
            if sshkeytype and sshkeyvalue:
                if sshkeytype not in ['ssh-rsa', 'ssh-dsa']:
                    continue
                users[username]['sshkeys'].append(py23_compat.text_type(sshkeyvalue))
        return users
Example #22
0
    def get_snmp_information(self):
        snmp_information = {}
        snmp_command = 'show running-config'
        snmp_raw_output = self.cli([snmp_command]).get(snmp_command, '')
        snmp_config = napalm.base.helpers.textfsm_extractor(
            self, 'snmp_config', snmp_raw_output)

        if not snmp_config:
            return snmp_information

        snmp_information = {
            'contact': py23_compat.text_type(''),
            'location': py23_compat.text_type(''),
            'community': {},
            'chassis_id': py23_compat.text_type('')
        }

        for snmp_entry in snmp_config:
            contact = py23_compat.text_type(snmp_entry.get('contact', ''))
            if contact:
                snmp_information['contact'] = contact
            location = py23_compat.text_type(snmp_entry.get('location', ''))
            if location:
                snmp_information['location'] = location

            community_name = py23_compat.text_type(
                snmp_entry.get('community', ''))
            if not community_name:
                continue

            if community_name not in snmp_information['community'].keys():
                snmp_information['community'][community_name] = {
                    'acl':
                    py23_compat.text_type(snmp_entry.get('acl', '')),
                    'mode':
                    py23_compat.text_type(snmp_entry.get('mode', '').lower())
                }
            else:
                acl = py23_compat.text_type(snmp_entry.get('acl', ''))
                if acl:
                    snmp_information['community'][community_name]['acl'] = acl
                mode = py23_compat.text_type(
                    snmp_entry.get('mode', '').lower())
                if mode:
                    snmp_information['community'][community_name][
                        'mode'] = mode
        return snmp_information
Example #23
0
    def get_users(self):
        _CISCO_TO_CISCO_MAP = {
            'network-admin': 15,
            'network-operator': 5
        }

        _DEFAULT_USER_DICT = {
            'password': '',
            'level': 0,
            'sshkeys': []
        }

        users = {}
        command = 'show running-config'
        section_username_raw_output = self.cli([command]).get(command, '')
        section_username_tabled_output = napalm.base.helpers.textfsm_extractor(
            self, 'users', section_username_raw_output)

        for user in section_username_tabled_output:
            username = user.get('username', '')
            if not username:
                continue
            if username not in users:
                users[username] = _DEFAULT_USER_DICT.copy()

            password = user.get('password', '')
            if password:
                users[username]['password'] = py23_compat.text_type(password.strip())

            level = 0
            role = user.get('role', '')
            if role.startswith('priv'):
                level = int(role.split('-')[-1])
            else:
                level = _CISCO_TO_CISCO_MAP.get(role, 0)
            if level > users.get(username).get('level'):
                # unfortunately on Cisco you can set different priv levels for the same user
                # Good news though: the device will consider the highest level
                users[username]['level'] = level

            sshkeytype = user.get('sshkeytype', '')
            sshkeyvalue = user.get('sshkeyvalue', '')
            if sshkeytype and sshkeyvalue:
                if sshkeytype not in ['ssh-rsa', 'ssh-dsa']:
                    continue
                users[username]['sshkeys'].append(py23_compat.text_type(sshkeyvalue))
        return users
Example #24
0
    def get_bgp_neighbors_detail(self, neighbor_address=u''):
        """FTOS implementation of get_bgp_neighbors_detail."""
        cmd = ["show ip bgp neighbors"]
        if len(neighbor_address.strip()) > 0:
            cmd.append(neighbor_address)

        command = ' '.join(cmd)
        neighbors = self._send_command(command)
        neighbors = textfsm_extractor(self, 'show_ip_bgp_neighbors', neighbors)

        table = {u'global': {}}
        for idx, entry in enumerate(neighbors):
            # TODO: couldn't detect VRF from output
            vrf = u'global'

            neighbor = {
                "up": (entry['connection_state'] == 'ESTABLISHED'),
                "local_as": -1,  # unimplemented
                "router_id": ip(entry['router_id']),
                "local_address": py23_compat.text_type(entry['local_address']),
                "routing_table": u'',  # unimplemented
                "local_address_configured": False,  # unimplemented
                "local_port": entry['local_port'],
                "remote_address": ip(entry['remote_address']),
                "multihop": False,  # unimplemented
                "multipath": False,  # unimplemented
                "remove_private_as": False,  # unimplemented
                "import_policy": u'',  # unimplemented
                "export_policy": u'',  # unimplemented
                "connection_state": entry['connection_state'],
                "previous_connection_state": u'',  # unimplemented
                "last_event": u'',  # unimplemented
                "suppress_4byte_as": False,  # unimplemented
                "local_as_prepend": False,  # unimplemented
                "configured_holdtime": -1,  # unimplemented
                "configured_keepalive": -1,  # unimplemented
                "active_prefix_count": -1,  # unimplemented
                "received_prefix_count": -1,  # unimplemented
                "suppressed_prefix_count": -1,  # unimplemented
            }

            # cast some integers
            for k in [
                    'remote_as', 'local_port', 'remote_port', 'input_messages',
                    'output_messages', 'input_updates', 'output_updates',
                    'messages_queued_out', 'holdtime', 'keepalive',
                    'accepted_prefix_count', 'advertised_prefix_count',
                    'flap_count'
            ]:
                try:
                    neighbor[k] = int(entry[k])
                except ValueError:
                    neighbor[k] = -1

            if entry['remote_as'] not in table[vrf]:
                table[vrf][int(entry['remote_as'])] = []
            table[vrf][int(entry['remote_as'])].append(neighbor)

        return table
Example #25
0
    def get_lldp_neighbors(self):
        """
        Return LLDP neighbors brief info.

        Sample input:
            <device-vrp>dis lldp neighbor brief
            Local Intf    Neighbor Dev          Neighbor Intf             Exptime(s)
            XGE0/0/1      huawei-S5720-01       XGE0/0/1                  96
            XGE0/0/3      huawei-S5720-POE      XGE0/0/1                  119
            XGE0/0/46     Aruba-7210-M          GE0/0/2                   95

        Sample output:
        {
            'XGE0/0/1': [
                {
                    'hostname': 'huawei-S5720-01',
                    'port': 'XGE0/0/1'
                },
            'XGE0/0/3': [
                {
                    'hostname': 'huawei-S5720-POE',
                    'port': 'XGE0/0/1'
                },
            'XGE0/0/46': [
                {
                    'hostname': 'Aruba-7210-M',
                    'port': 'GE0/0/2'
                },
            ]
        }
        """
        results = {}
        command = 'display lldp neighbor brief'
        output = self.device.send_command(command)
        re_lldp = r"(?P<local>\S+)\s+(?P<hostname>\S+)\s+(?P<port>\S+)\s+\d+\s+"
        match = re.findall(re_lldp, output, re.M)
        for neighbor in match:
            local_intf = neighbor[0]
            if local_intf not in results:
                results[local_intf] = []

            neighbor_dict = dict()
            neighbor_dict['hostname'] = py23_compat.text_type(neighbor[1])
            neighbor_dict['port'] = py23_compat.text_type(neighbor[2])
            results[local_intf].append(neighbor_dict)
        return results
Example #26
0
    def traceroute(self, destination, source=u'', ttl=255, timeout=2, vrf=u''):
        """FTOS implementation of traceroute."""
        # source, ttl and timeout are not implemented and therefore ignored
        cmd = ["traceroute"]
        if len(vrf.strip()) > 0:
            cmd.append("vrf %s" % vrf)
        cmd.append(destination)

        command = ' '.join(cmd)
        result = self._send_command(command)

        # check if output holds an error
        m = re.search(r'% Error: (.+)', result)
        if m:
            return {
                'error': m.group(1)
            }

        # process results of succesful traceroute
        result = textfsm_extractor(self, 'traceroute', result)
        trace = {}
        ttl = None
        for idx, entry in enumerate(result):
            if len(entry['ttl'].strip()) > 0 and ttl != int(entry['ttl']):
                ttl = int(entry['ttl'])
                trace[ttl] = {'probes': {}}
                ctr = 1

            # rewrite probes for easier splitting
            probes = re.sub(r'\s+', ' ', entry['probes'].replace('ms', '').strip())
            if len(probes) == 0:
                probes = []
            else:
                probes = probes.split(' ')

            for probe in probes:
                trace[ttl]['probes'][ctr] = {
                    'rtt': float(probe),
                    'ip_address': ip(py23_compat.text_type(entry['hop'])),
                    'host_name': py23_compat.text_type(entry['hop']),
                }
                ctr += 1

        return {
            'success': trace,
        }
Example #27
0
def as_number(as_number_val):
    """Convert AS Number to standardized asplain notation as an integer."""
    as_number_str = py23_compat.text_type(as_number_val)
    if '.' in as_number_str:
        big, little = as_number_str.split('.')
        return (int(big) << 16) + int(little)
    else:
        return int(as_number_str)
Example #28
0
def as_number(as_number_val):
    """Convert AS Number to standardized asplain notation as an integer."""
    as_number_str = py23_compat.text_type(as_number_val)
    if '.' in as_number_str:
        big, little = as_number_str.split('.')
        return (int(big) << 16) + int(little)
    else:
        return int(as_number_str)
 def send_command_expect(self, command, **kwargs):
     """Fake execute a command in the device by just returning the
     content of a file."""
     # cmd = re.sub(r'[\[\]\*\^\+\s\|/]', '_', command)
     cmd = '{}'.format(BaseTestDouble.sanitize_text(command))
     file_path = 'dellos10/mock_data/{}.txt'.format(cmd)
     print("file_path :: " + file_path)
     output = self.read_txt_file(file_path)
     return py23_compat.text_type(output)
Example #30
0
    def test_mock_error(self):
        d = driver("blah", "bleh", "blih", optional_args=optional_args)
        d.open()

        with pytest.raises(KeyError) as excinfo:
            d.get_bgp_neighbors()
        assert "Something" in py23_compat.text_type(excinfo.value)

        with pytest.raises(napalm.base.exceptions.ConnectionClosedException) as excinfo:
            d.get_bgp_neighbors()
        assert "Something" in py23_compat.text_type(excinfo.value)

        with pytest.raises(TypeError) as excinfo:
            d.get_bgp_neighbors()
            assert "Couldn't resolve exception NoIdeaException" in py23_compat.text_type(
                    excinfo.value)

        d.close()
Example #31
0
    def cli(self, commands):
        cli_output = {}
        if type(commands) is not list:
            raise TypeError('Please enter a valid list of commands!')

        for command in commands:
            command_output = self._send_command(command, raw_text=True)
            cli_output[py23_compat.text_type(command)] = command_output
        return cli_output
Example #32
0
    def cli(self, commands):
        cli_output = {}
        if type(commands) is not list:
            raise TypeError('Please enter a valid list of commands!')

        for command in commands:
            output = self.device.send_command(command)
            cli_output[py23_compat.text_type(command)] = output
        return cli_output
Example #33
0
    def cli(self, commands):
        cli_output = {}
        if type(commands) is not list:
            raise TypeError('Please enter a valid list of commands!')

        for command in commands:
            command_output = self.device.show(command, raw_text=True)
            cli_output[py23_compat.text_type(command)] = command_output
        return cli_output
Example #34
0
    def ping(self, destination, source=c.PING_SOURCE, ttl=c.PING_TTL, timeout=c.PING_TIMEOUT, size=c.PING_SIZE,
             count=c.PING_COUNT, vrf=c.PING_VRF):
        """Execute ping on the device."""
        ping_dict = {}
        command = 'ping'
        # Timeout in milliseconds to wait for each reply, the default is 2000
        command += ' -t {}'.format(timeout*1000)
        # Specify the number of data bytes to be sent
        command += ' -s {}'.format(size)
        # Specify the number of echo requests to be sent
        command += ' -c {}'.format(count)
        if source != '':
            command += ' -a {}'.format(source)
        command += ' {}'.format(destination)
        output = self.device.send_command(command)

        if 'Error' in output:
            ping_dict['error'] = output
        elif 'PING' in output:
            ping_dict['success'] = {
                                'probes_sent': 0,
                                'packet_loss': 0,
                                'rtt_min': 0.0,
                                'rtt_max': 0.0,
                                'rtt_avg': 0.0,
                                'rtt_stddev': 0.0,
                                'results': []
            }

            match_sent = re.search(r"(\d+).+transmitted", output, re.M)
            match_received = re.search(r"(\d+).+received", output, re.M)

            try:
                probes_sent = int(match_sent.group(1))
                probes_received = int(match_received.group(1))
                ping_dict['success']['probes_sent'] = probes_sent
                ping_dict['success']['packet_loss'] = probes_sent - probes_received
            except Exception:
                msg = "Unexpected output data:\n{}".format(output)
                raise ValueError(msg)

            match = re.search(r"min/avg/max = (\d+)/(\d+)/(\d+)", output, re.M)
            if match:
                ping_dict['success'].update({
                    'rtt_min': float(match.group(1)),
                    'rtt_avg': float(match.group(2)),
                    'rtt_max': float(match.group(3)),
                })

                results_array = []
                match = re.findall(r"Reply from.+time=(\d+)", output, re.M)
                for i in match:
                    results_array.append({'ip_address': py23_compat.text_type(destination),
                                          'rtt': float(i)})
                ping_dict['success'].update({'results': results_array})
        return ping_dict
Example #35
0
    def get_config(self, retrieve='all'):
        """ Get config from device. """
        config = {
            'startup': '',
            'running': '',
            'candidate': ''
        }
        if retrieve.lower() in ('running', 'all'):
            command = 'show config current_config'
            config['running'] = py23_compat.text_type(self.device.send_command(command))
            # Some D-link switch need run other command
            if "Configuration" not in config['running']:
                command = 'show config active'
                config['running'] = py23_compat.text_type(self.device.send_command(command))
        if retrieve.lower() in ('candidate', 'all'):
            command = 'show config config_in_nvram'
            config['candidate'] = py23_compat.text_type(self.device.send_command(command))

        return config
Example #36
0
    def get_arp_table(self, vrf=""):
        # 'age' is not implemented yet
        """
        'show arp' output example:
        Address                  HWtype  HWaddress           Flags Mask            Iface
        10.129.2.254             ether   00:50:56:97:af:b1   C                     eth0
        192.168.1.134                    (incomplete)                              eth1
        192.168.1.1              ether   00:50:56:ba:26:7f   C                     eth1
        10.129.2.97              ether   00:50:56:9f:64:09   C                     eth0
        192.168.1.3              ether   00:50:56:86:7b:06   C                     eth1
        """

        if vrf:
            raise NotImplementedError(
                "VRF support has not been added for this getter on this platform."
            )

        output = self.device.send_command("show arp")
        output = output.split("\n")

        # Skip the header line
        output = output[1:-1]

        arp_table = list()
        for line in output:

            line = line.split()
            # 'line' example:
            # ["10.129.2.254", "ether", "00:50:56:97:af:b1", "C", "eth0"]
            # [u'10.0.12.33', u'(incomplete)', u'eth1']
            if "incomplete" in line[1]:
                macaddr = py23_compat.text_type("00:00:00:00:00:00")
            else:
                macaddr = py23_compat.text_type(line[2])

            arp_table.append({
                'interface': py23_compat.text_type(line[-1]),
                'mac': macaddr,
                'ip': py23_compat.text_type(line[0]),
                'age': 0.0
            })

        return arp_table
Example #37
0
    def get_lldp_neighbors(self):
        """
        Return LLDP neighbors brief info.

        Sample input:
            <XG.DC06.F058-AS-S5560-101>display lldp neighbor-information list
            Chassis ID : * -- -- Nearest nontpmr bridge neighbor
                         # -- -- Nearest customer bridge neighbor
                         Default -- -- Nearest bridge neighbor
            System Name               Local Interface Chassis ID      Port ID
            XG.DC06.F060-CS-S6800-100 XGE1/0/51       d461-feab-b3ab  Ten-GigabitEthernet1/2/1
            XG.DC06.F060-CS-S6800-100 XGE1/0/52       d461-feab-b3ab  Ten-GigabitEthernet2/2/1

        Sample output:
        {
            'XGE1/0/51': [
                {
                    'hostname': 'XG.DC06.F060-CS-S6800-100',
                    'port': 'Ten-GigabitEthernet1/2/1'
                },
            'XGE1/0/52': [
                {
                    'hostname': 'XG.DC06.F060-CS-S6800-100',
                    'port': 'Ten-GigabitEthernet2/2/1'
                },
            ]
        }
        """
        results = {}
        command = 'display lldp neighbor-information list'
        output = self.device.send_command(command)
        re_lldp = r"(?P<hostname>\S+)\s+(?P<local>\S+)\s+\S+\s+(?P<port>[G,T]\S+)\s+"
        match = re.findall(re_lldp, output, re.M)
        for neighbor in match:
            local_intf = neighbor[1]
            if local_intf not in results:
                results[local_intf] = []

            neighbor_dict = dict()
            neighbor_dict['hostname'] = py23_compat.text_type(neighbor[0])
            neighbor_dict['port'] = py23_compat.text_type(neighbor[2])
            results[local_intf].append(neighbor_dict)
        return results
Example #38
0
    def get_ntp_stats(self):
        """
        'ntpq -np' output example
             remote           refid      st t when poll reach   delay   offset  jitter
        ==============================================================================
         116.91.118.97   133.243.238.244  2 u   51   64  377    5.436  987971. 1694.82
         219.117.210.137 .GPS.            1 u   17   64  377   17.586  988068. 1652.00
         133.130.120.204 133.243.238.164  2 u   46   64  377    7.717  987996. 1669.77
        """

        output = self.device.send_command("ntpq -np")
        output = output.split("\n")[2:]
        ntp_stats = list()

        for ntp_info in output:
            if len(ntp_info) > 0:
                remote, refid, st, t, when, hostpoll, reachability, delay, offset, \
                    jitter = ntp_info.split()

                # 'remote' contains '*' if the machine synchronized with NTP server
                synchronized = "*" in remote

                match = re.search("(\d+\.\d+\.\d+\.\d+)", remote)
                ip = match.group(1)

                when = when if when != '-' else 0

                ntp_stats.append({
                    "remote": py23_compat.text_type(ip),
                    "referenceid": py23_compat.text_type(refid),
                    "synchronized": bool(synchronized),
                    "stratum": int(st),
                    "type": py23_compat.text_type(t),
                    "when": py23_compat.text_type(when),
                    "hostpoll": int(hostpoll),
                    "reachability": int(reachability),
                    "delay": float(delay),
                    "offset": float(offset),
                    "jitter": float(jitter)
                })

        return ntp_stats
Example #39
0
    def test_arguments(self):
        d = driver("blah", "bleh", "blih", optional_args=optional_args)
        d.open()

        with pytest.raises(TypeError) as excinfo:
            d.get_route_to(1, 2, 3)
        assert ("get_route_to: expected at most 3 arguments, got 4"
                in py23_compat.text_type(excinfo.value))

        with pytest.raises(TypeError) as excinfo:
            d.get_route_to(1, 1, protocol=2)
        assert ("get_route_to: expected at most 3 arguments, got 3"
                in py23_compat.text_type(excinfo.value))

        with pytest.raises(TypeError) as excinfo:
            d.get_route_to(proto=2)
        assert ("get_route_to got an unexpected keyword argument 'proto'"
                in py23_compat.text_type(excinfo.value))

        d.close()
Example #40
0
    def test_basic(self):
        d = driver("blah", "bleh", "blih", optional_args=optional_args)
        assert d.is_alive() == {u'is_alive': False}
        d.open()
        assert d.is_alive() == {u'is_alive': True}
        d.close()
        assert d.is_alive() == {u'is_alive': False}

        with pytest.raises(napalm.base.exceptions.ConnectionClosedException) as excinfo:
            d.get_facts()
        assert "connection closed" in py23_compat.text_type(excinfo.value)
Example #41
0
    def get_ntp_peers(self):
        output = self.device.send_command("ntpq -np")
        output_peers = output.split("\n")[2:]
        ntp_peers = dict()

        for line in output_peers:
            if len(line) > 0:
                match = re.search("(\d+\.\d+\.\d+\.\d+)\s+", line)
                ntp_peers.update({py23_compat.text_type(match.group(1)): {}})

        return ntp_peers
Example #42
0
    def test_arguments(self):
        d = driver("blah", "bleh", "blih", optional_args=optional_args)
        d.open()

        with pytest.raises(TypeError) as excinfo:
            d.get_route_to(1, 2, 3)
        assert "get_route_to: expected at most 3 arguments, got 4" in py23_compat.text_type(
                excinfo.value)

        with pytest.raises(TypeError) as excinfo:
            d.get_route_to(1, 1, protocol=2)
        assert "get_route_to: expected at most 3 arguments, got 3" in py23_compat.text_type(
                excinfo.value)

        with pytest.raises(TypeError) as excinfo:
            d.get_route_to(proto=2)
        assert "get_route_to got an unexpected keyword argument 'proto'" in py23_compat.text_type(
                excinfo.value)

        d.close()
Example #43
0
    def get_snmp_information(self):
        snmp_information = {}
        snmp_command = 'show running-config'
        snmp_raw_output = self.cli([snmp_command]).get(snmp_command, '')
        snmp_config = napalm.base.helpers.textfsm_extractor(self, 'snmp_config', snmp_raw_output)

        if not snmp_config:
            return snmp_information

        snmp_information = {
            'contact': py23_compat.text_type(''),
            'location': py23_compat.text_type(''),
            'community': {},
            'chassis_id': py23_compat.text_type('')
        }

        for snmp_entry in snmp_config:
            contact = py23_compat.text_type(snmp_entry.get('contact', ''))
            if contact:
                snmp_information['contact'] = contact
            location = py23_compat.text_type(snmp_entry.get('location', ''))
            if location:
                snmp_information['location'] = location

            community_name = py23_compat.text_type(snmp_entry.get('community', ''))
            if not community_name:
                continue

            if community_name not in snmp_information['community'].keys():
                snmp_information['community'][community_name] = {
                    'acl': py23_compat.text_type(snmp_entry.get('acl', '')),
                    'mode': py23_compat.text_type(snmp_entry.get('mode', '').lower())
                }
            else:
                acl = py23_compat.text_type(snmp_entry.get('acl', ''))
                if acl:
                    snmp_information['community'][community_name]['acl'] = acl
                mode = py23_compat.text_type(snmp_entry.get('mode', '').lower())
                if mode:
                    snmp_information['community'][community_name]['mode'] = mode
        return snmp_information
Example #44
0
    def get_lldp_neighbors(self):
        results = {}
        try:
            command = 'show lldp neighbors'
            lldp_raw_output = self.cli([command]).get(command, '')
            lldp_neighbors = napalm.base.helpers.textfsm_extractor(
                                self, 'lldp_neighbors', lldp_raw_output)
        except CLIError:
            lldp_neighbors = []

        for neighbor in lldp_neighbors:
            local_iface = neighbor.get('local_interface')
            if neighbor.get(local_iface) is None:
                if local_iface not in results:
                    results[local_iface] = []

            neighbor_dict = {}
            neighbor_dict['hostname'] = py23_compat.text_type(neighbor.get('neighbor'))
            neighbor_dict['port'] = py23_compat.text_type(neighbor.get('neighbor_interface'))

            results[local_iface].append(neighbor_dict)
        return results
Example #45
0
    def get_interfaces(self):
        LOOPBACK_SUBIF_DEFAULTS = {
            'is_up': True,
            'is_enabled': True,
            'speed': 0,
            'last_flapped': -1.0,
            'mac_address': '',
            'description': 'N/A'
        }
        interface_dict = {}
        interface_list = self._extract_interface_list()

        for intf in interface_list:
            interface = {}
            cmd = "<show><interface>{0}</interface></show>".format(intf)

            try:
                self.device.op(cmd=cmd)
                interface_info_xml = xmltodict.parse(self.device.xml_root())
                interface_info_json = json.dumps(interface_info_xml['response']['result']['hw'])
                interface_info = json.loads(interface_info_json)
            except KeyError as err:
                if 'loopback.' in intf and 'hw' in str(err):
                    # loopback sub-ifs don't return a 'hw' key
                    interface_dict[intf] = LOOPBACK_SUBIF_DEFAULTS
                    continue
                raise

            interface['is_up'] = interface_info.get('state') == 'up'

            conf_state = interface_info.get('state_c')
            if conf_state == 'down':
                interface['is_enabled'] = False
            elif conf_state in ('up', 'auto'):
                interface['is_enabled'] = True
            else:
                msg = 'Unknown configured state {} for interface {}'.format(conf_state, intf)
                raise RuntimeError(msg)

            interface['last_flapped'] = -1.0
            interface['speed'] = interface_info.get('speed')
            # Loopback and down interfaces
            if interface['speed'] in ('[n/a]', 'unknown'):
                interface['speed'] = 0
            else:
                interface['speed'] = int(interface['speed'])
            interface['mac_address'] = standardize_mac(interface_info.get('mac'))
            interface['description'] = py23_compat.text_type('N/A')
            interface_dict[intf] = interface

        return interface_dict
Example #46
0
def textfsm_extractor(cls, template_name, raw_text):
    """
    Applies a TextFSM template over a raw text and return the matching table.

    Main usage of this method will be to extract data form a non-structured output
    from a network device and return the values in a table format.

    :param cls: Instance of the driver class
    :param template_name: Specifies the name of the template to be used
    :param raw_text: Text output as the devices prompts on the CLI
    :return: table-like list of entries
    """
    textfsm_data = list()
    cls.__class__.__name__.replace('Driver', '')
    current_dir = os.path.dirname(os.path.abspath(sys.modules[cls.__module__].__file__))
    template_dir_path = '{current_dir}/utils/textfsm_templates'.format(
        current_dir=current_dir
    )
    template_path = '{template_dir_path}/{template_name}.tpl'.format(
        template_dir_path=template_dir_path,
        template_name=template_name
    )

    try:
        fsm_handler = textfsm.TextFSM(open(template_path))
    except IOError:
        raise napalm.base.exceptions.TemplateNotImplemented(
            "TextFSM template {template_name}.tpl is not defined under {path}".format(
                template_name=template_name,
                path=template_dir_path
            )
        )
    except textfsm.TextFSMTemplateError as tfte:
        raise napalm.base.exceptions.TemplateRenderException(
            "Wrong format of TextFSM template {template_name}: {error}".format(
                template_name=template_name,
                error=py23_compat.text_type(tfte)
            )
        )

    objects = fsm_handler.ParseText(raw_text)

    for obj in objects:
        index = 0
        entry = {}
        for entry_value in obj:
            entry[fsm_handler.header[index].lower()] = entry_value
            index += 1
        textfsm_data.append(entry)

    return textfsm_data
Example #47
0
    def get_facts(self):
        facts = {}

        try:
            self.device.op(cmd='<show><system><info></info></system></show>')
            system_info_xml = xmltodict.parse(self.device.xml_root())
            system_info_json = json.dumps(system_info_xml['response']['result']['system'])
            system_info = json.loads(system_info_json)
        except AttributeError:
            system_info = {}

        if system_info:
            facts['hostname'] = system_info['hostname']
            facts['vendor'] = py23_compat.text_type('Palo Alto Networks')
            facts['uptime'] = int(convert_uptime_string_seconds(system_info['uptime']))
            facts['os_version'] = system_info['sw-version']
            facts['serial_number'] = system_info['serial']
            facts['model'] = system_info['model']
            facts['fqdn'] = py23_compat.text_type('N/A')
            facts['interface_list'] = self._extract_interface_list()

            facts['interface_list'].sort()

        return facts
Example #48
0
    def get_config(self, retrieve='all'):
        configs = {}
        running = py23_compat.text_type('')
        candidate = py23_compat.text_type('')
        startup = py23_compat.text_type('')

        if retrieve == 'all':
            running = py23_compat.text_type(self._get_running())
            candidate = py23_compat.text_type(self._get_candidate())
        elif retrieve == 'running':
            running = py23_compat.text_type(self._get_running())
        elif retrieve == 'candidate':
            candidate = py23_compat.text_type(self._get_candidate())

        configs['running'] = running
        configs['candidate'] = candidate
        configs['startup'] = startup

        return configs
Example #49
0
def find_txt(xml_tree, path, default=''):
    """
    Extracts the text value from an XML tree, using XPath.
    In case of error, will return a default value.

    :param xml_tree: the XML Tree object. Assumed is <type 'lxml.etree._Element'>.
    :param path:     XPath to be applied, in order to extract the desired data.
    :param default:  Value to be returned in case of error.
    :return: a str value.
    """
    value = ''
    try:
        xpath_applied = xml_tree.xpath(path)  # will consider the first match only
        if len(xpath_applied) and xpath_applied[0] is not None:
            xpath_result = xpath_applied[0]
            if isinstance(xpath_result, type(xml_tree)):
                value = xpath_result.text.strip()
            else:
                value = xpath_result
    except Exception:  # in case of any exception, returns default
        value = default
    return py23_compat.text_type(value)
Example #50
0
def abbreviated_interface_name(interface, addl_name_map=None, addl_reverse_map=None):
    """Function to return an abbreviated representation of the interface name.

    :param interface: The interface you are attempting to abbreviate.
    :param addl_name_map (optional): A dict containing key/value pairs that updates
    the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs
    {"Po": "Port-Channel"}
    :param addl_reverse_map (optional): A dict containing key/value pairs that updates
    the reverse mapping. Used if an OS has specific differences. e.g. {"PortChannel": "Po"} vs
    {"PortChannel": "po"}
    """

    name_map = {}
    name_map.update(base_interfaces)
    interface_type, interface_number = split_interface(interface)

    if isinstance(addl_name_map, dict):
        name_map.update(addl_name_map)

    rev_name_map = {}
    rev_name_map.update(reverse_mapping)

    if isinstance(addl_reverse_map, dict):
        rev_name_map.update(addl_reverse_map)

    # Try to ensure canonical type.
    if name_map.get(interface_type):
        canonical_type = name_map.get(interface_type)
    else:
        canonical_type = interface_type

    try:
        abbreviated_name = rev_name_map[canonical_type] + py23_compat.text_type(interface_number)
        return abbreviated_name
    except KeyError:
        pass

    # If abbreviated name lookup fails, return original name
    return interface
Example #51
0
    def get_arp_table(self):
        arp_table = []
        command = 'show ip arp'
        arp_table_vrf = self._get_command_table(command, 'TABLE_vrf', 'ROW_vrf')
        arp_table_raw = self._get_table_rows(arp_table_vrf[0], 'TABLE_adj', 'ROW_adj')

        for arp_table_entry in arp_table_raw:
            raw_ip = arp_table_entry.get('ip-addr-out')
            raw_mac = arp_table_entry.get('mac')
            age = arp_table_entry.get('time-stamp')
            if age == '-':
                age_sec = -1.0
            elif ':' not in age:
                # Cisco sometimes returns a sub second arp time 0.411797
                try:
                    age_sec = float(age)
                except ValueError:
                    age_sec = -1.0
            else:
                fields = age.split(':')
                if len(fields) == 3:
                    try:
                        fields = [float(x) for x in fields]
                        hours, minutes, seconds = fields
                        age_sec = 3600 * hours + 60 * minutes + seconds
                    except ValueError:
                        age_sec = -1.0
            age_sec = round(age_sec, 1)

            interface = py23_compat.text_type(arp_table_entry.get('intf-out'))
            arp_table.append({
                'interface': interface,
                'mac': napalm.base.helpers.convert(
                    napalm.base.helpers.mac, raw_mac, raw_mac),
                'ip': napalm.base.helpers.ip(raw_ip),
                'age': age_sec
            })
        return arp_table
Example #52
0
    def get_mac_address_table(self):
        mac_table = []
        command = 'show mac address-table'
        mac_table_raw = self._get_command_table(command, 'TABLE_mac_address', 'ROW_mac_address')

        for mac_entry in mac_table_raw:
            raw_mac = mac_entry.get('disp_mac_addr')
            interface = py23_compat.text_type(mac_entry.get('disp_port'))
            vlan = int(mac_entry.get('disp_vlan'))
            active = True
            static = (mac_entry.get('disp_is_static') != '0')
            moves = 0
            last_move = 0.0
            mac_table.append({
                'mac': napalm.base.helpers.mac(raw_mac),
                'interface': interface,
                'vlan': vlan,
                'active': active,
                'static': static,
                'moves': moves,
                'last_move': last_move
            })
        return mac_table
Example #53
0
def mac(raw):
    """
    Converts a raw string to a standardised MAC Address EUI Format.

    :param raw: the raw string containing the value of the MAC Address
    :return: a string with the MAC Address in EUI format

    Example:

    .. code-block:: python

        >>> mac('0123.4567.89ab')
        u'01:23:45:67:89:AB'

    Some vendors like Cisco return MAC addresses like a9:c5:2e:7b:6: which is not entirely valid
    (with respect to EUI48 or EUI64 standards). Therefore we need to stuff with trailing zeros

    Example
    >>> mac('a9:c5:2e:7b:6:')
    u'A9:C5:2E:7B:60:00'

    If Cisco or other obscure vendors use their own standards, will throw an error and we can fix
    later, however, still works with weird formats like:

    >>> mac('123.4567.89ab')
    u'01:23:45:67:89:AB'
    >>> mac('23.4567.89ab')
    u'00:23:45:67:89:AB'
    """
    if raw.endswith(':'):
        flat_raw = raw.replace(':', '')
        raw = '{flat_raw}{zeros_stuffed}'.format(
            flat_raw=flat_raw,
            zeros_stuffed='0'*(12-len(flat_raw))
        )
    return py23_compat.text_type(EUI(raw, dialect=_MACFormat))
Example #54
0
    def get_lldp_neighbors_detail(self, interface=''):
        lldp_neighbors = {}
        filter = ''
        if interface:
            filter = 'interface {name} '.format(name=interface)

        command = 'show lldp neighbors {filter}detail'.format(filter=filter)
        # seems that some old devices may not return JSON output...

        try:
            lldp_neighbors_table_str = self.cli([command]).get(command)
            # thus we need to take the raw text output
            lldp_neighbors_list = lldp_neighbors_table_str.splitlines()
        except CLIError:
            lldp_neighbors_list = []

        if not lldp_neighbors_list:
            return lldp_neighbors  # empty dict

        CHASSIS_REGEX = r'^(Chassis id:)\s+([a-z0-9\.]+)$'
        PORT_REGEX = r'^(Port id:)\s+([0-9]+)$'
        LOCAL_PORT_ID_REGEX = r'^(Local Port id:)\s+(.*)$'
        PORT_DESCR_REGEX = r'^(Port Description:)\s+(.*)$'
        SYSTEM_NAME_REGEX = r'^(System Name:)\s+(.*)$'
        SYSTEM_DESCR_REGEX = r'^(System Description:)\s+(.*)$'
        SYST_CAPAB_REEGX = r'^(System Capabilities:)\s+(.*)$'
        ENABL_CAPAB_REGEX = r'^(Enabled Capabilities:)\s+(.*)$'
        VLAN_ID_REGEX = r'^(Vlan ID:)\s+(.*)$'

        lldp_neighbor = {}
        interface_name = None

        for line in lldp_neighbors_list:
            chassis_rgx = re.search(CHASSIS_REGEX, line, re.I)
            if chassis_rgx:
                lldp_neighbor = {
                    'remote_chassis_id': napalm.base.helpers.mac(chassis_rgx.groups()[1])
                }
                continue
            lldp_neighbor['parent_interface'] = ''
            port_rgx = re.search(PORT_REGEX, line, re.I)
            if port_rgx:
                lldp_neighbor['parent_interface'] = py23_compat.text_type(port_rgx.groups()[1])
                continue
            local_port_rgx = re.search(LOCAL_PORT_ID_REGEX, line, re.I)
            if local_port_rgx:
                interface_name = local_port_rgx.groups()[1]
                continue
            port_descr_rgx = re.search(PORT_DESCR_REGEX, line, re.I)
            if port_descr_rgx:
                lldp_neighbor['remote_port'] = py23_compat.text_type(port_descr_rgx.groups()[1])
                lldp_neighbor['remote_port_description'] = py23_compat.text_type(
                                                            port_descr_rgx.groups()[1])
                continue
            syst_name_rgx = re.search(SYSTEM_NAME_REGEX, line, re.I)
            if syst_name_rgx:
                lldp_neighbor['remote_system_name'] = py23_compat.text_type(
                                                        syst_name_rgx.groups()[1])
                continue
            syst_descr_rgx = re.search(SYSTEM_DESCR_REGEX, line, re.I)
            if syst_descr_rgx:
                lldp_neighbor['remote_system_description'] = py23_compat.text_type(
                                                                syst_descr_rgx.groups()[1])
                continue
            syst_capab_rgx = re.search(SYST_CAPAB_REEGX, line, re.I)
            if syst_capab_rgx:
                lldp_neighbor['remote_system_capab'] = py23_compat.text_type(
                                                        syst_capab_rgx.groups()[1])
                continue
            syst_enabled_rgx = re.search(ENABL_CAPAB_REGEX, line, re.I)
            if syst_enabled_rgx:
                lldp_neighbor['remote_system_enable_capab'] = py23_compat.text_type(
                                                                syst_enabled_rgx.groups()[1])
                continue
            vlan_rgx = re.search(VLAN_ID_REGEX, line, re.I)
            if vlan_rgx:
                # at the end of the loop
                if interface_name not in lldp_neighbors.keys():
                    lldp_neighbors[interface_name] = []
                lldp_neighbors[interface_name].append(lldp_neighbor)
        return lldp_neighbors
Example #55
0
    def get_interfaces_ip(self):
        interfaces_ip = {}
        ipv4_command = 'show ip interface'
        ipv4_interf_table_vrf = self._get_command_table(ipv4_command, 'TABLE_intf', 'ROW_intf')

        for interface in ipv4_interf_table_vrf:
            interface_name = py23_compat.text_type(interface.get('intf-name', ''))
            address = napalm.base.helpers.ip(interface.get('prefix'))
            prefix = int(interface.get('masklen', ''))
            if interface_name not in interfaces_ip.keys():
                interfaces_ip[interface_name] = {}
            if 'ipv4' not in interfaces_ip[interface_name].keys():
                interfaces_ip[interface_name]['ipv4'] = {}
            if address not in interfaces_ip[interface_name].get('ipv4'):
                interfaces_ip[interface_name]['ipv4'][address] = {}
            interfaces_ip[interface_name]['ipv4'][address].update({
                'prefix_length': prefix
            })
            secondary_addresses = interface.get('TABLE_secondary_address', {})\
                                           .get('ROW_secondary_address', [])
            if type(secondary_addresses) is dict:
                secondary_addresses = [secondary_addresses]
            for secondary_address in secondary_addresses:
                secondary_address_ip = napalm.base.helpers.ip(secondary_address.get('prefix1'))
                secondary_address_prefix = int(secondary_address.get('masklen1', ''))
                if 'ipv4' not in interfaces_ip[interface_name].keys():
                    interfaces_ip[interface_name]['ipv4'] = {}
                if secondary_address_ip not in interfaces_ip[interface_name].get('ipv4'):
                    interfaces_ip[interface_name]['ipv4'][secondary_address_ip] = {}
                interfaces_ip[interface_name]['ipv4'][secondary_address_ip].update({
                    'prefix_length': secondary_address_prefix
                })

        ipv6_command = 'show ipv6 interface'
        ipv6_interf_table_vrf = self._get_command_table(ipv6_command, 'TABLE_intf', 'ROW_intf')

        for interface in ipv6_interf_table_vrf:
            interface_name = py23_compat.text_type(interface.get('intf-name', ''))
            address = napalm.base.helpers.ip(interface.get('addr', '').split('/')[0])
            prefix = interface.get('prefix', '').split('/')[-1]
            if prefix:
                prefix = int(interface.get('prefix', '').split('/')[-1])
            else:
                prefix = 128
            if interface_name not in interfaces_ip.keys():
                interfaces_ip[interface_name] = {}
            if 'ipv6' not in interfaces_ip[interface_name].keys():
                interfaces_ip[interface_name]['ipv6'] = {}
            if address not in interfaces_ip[interface_name].get('ipv6'):
                interfaces_ip[interface_name]['ipv6'][address] = {}
            interfaces_ip[interface_name]['ipv6'][address].update({
                'prefix_length': prefix
            })
            secondary_addresses = interface.get('TABLE_sec_addr', {}).get('ROW_sec_addr', [])
            if type(secondary_addresses) is dict:
                secondary_addresses = [secondary_addresses]
            for secondary_address in secondary_addresses:
                sec_prefix = secondary_address.get('sec-prefix', '').split('/')
                secondary_address_ip = napalm.base.helpers.ip(sec_prefix[0])
                secondary_address_prefix = int(sec_prefix[-1])
                if 'ipv6' not in interfaces_ip[interface_name].keys():
                    interfaces_ip[interface_name]['ipv6'] = {}
                if secondary_address_ip not in interfaces_ip[interface_name].get('ipv6'):
                    interfaces_ip[interface_name]['ipv6'][secondary_address_ip] = {}
                interfaces_ip[interface_name]['ipv6'][secondary_address_ip].update({
                    'prefix_length': secondary_address_prefix
                })
        return interfaces_ip
Example #56
0
 def send_command_expect(self, command, **kwargs):
     """Fake execute a command in the device by just returning the content of a file."""
     cmd = re.sub(r'[\[\]\*\^\+\s\|]', '_', command)
     output = self.read_txt_file('ios/mock_data/{}.txt'.format(cmd))
     return py23_compat.text_type(output)
Example #57
0
 def send_command(self, command, **kwargs):
     filename = '{}.txt'.format(self.sanitize_text(command))
     full_path = self.find_file(filename)
     result = self.read_txt_file(full_path)
     return py23_compat.text_type(result)
Example #58
0
    def traceroute(self,
                   destination,
                   source=c.TRACEROUTE_SOURCE,
                   ttl=c.TRACEROUTE_TTL,
                   timeout=c.TRACEROUTE_TIMEOUT,
                   vrf=c.TRACEROUTE_VRF):
        _HOP_ENTRY_PROBE = [
            r'\s+',
            r'(',  # beginning of host_name (ip_address) RTT group
            r'(',  # beginning of host_name (ip_address) group only
            r'([a-zA-Z0-9\.:-]*)',  # hostname
            r'\s+',
            r'\(?([a-fA-F0-9\.:][^\)]*)\)?'  # IP Address between brackets
            r')?',  # end of host_name (ip_address) group only
            # also hostname/ip are optional -- they can or cannot be specified
            # if not specified, means the current probe followed the same path as the previous
            r'\s+',
            r'(\d+\.\d+)\s+ms',  # RTT
            r'|\*',  # OR *, when non responsive hop
            r')'  # end of host_name (ip_address) RTT group
        ]

        _HOP_ENTRY = [
            r'\s?',  # space before hop index?
            r'(\d+)',  # hop index
        ]

        traceroute_result = {}
        timeout = 5  # seconds
        probes = 3  # 3 probes/jop and this cannot be changed on NXOS!

        version = ''
        try:
            version = '6' if IPAddress(destination).version == 6 else ''
        except AddrFormatError:
            return {'error': 'Destination doest not look like a valid IP Address: {}'.format(
                destination)}

        source_opt = ''
        if source:
            source_opt = 'source {source}'.format(source=source)

        command = 'traceroute{version} {destination} {source_opt}'.format(
            version=version,
            destination=destination,
            source_opt=source_opt
        )

        try:
            traceroute_raw_output = self.cli([command]).get(command)
        except CommandErrorException:
            return {'error': 'Cannot execute traceroute on the device: {}'.format(command)}

        hop_regex = ''.join(_HOP_ENTRY + _HOP_ENTRY_PROBE * probes)
        traceroute_result['success'] = {}
        if traceroute_raw_output:
            for line in traceroute_raw_output.splitlines():
                hop_search = re.search(hop_regex, line)
                if not hop_search:
                    continue
                hop_details = hop_search.groups()
                hop_index = int(hop_details[0])
                previous_probe_host_name = '*'
                previous_probe_ip_address = '*'
                traceroute_result['success'][hop_index] = {'probes': {}}
                for probe_index in range(probes):
                    host_name = hop_details[3+probe_index*5]
                    ip_address_raw = hop_details[4+probe_index*5]
                    ip_address = napalm.base.helpers.convert(
                        napalm.base.helpers.ip, ip_address_raw, ip_address_raw)
                    rtt = hop_details[5+probe_index*5]
                    if rtt:
                        rtt = float(rtt)
                    else:
                        rtt = timeout * 1000.0
                    if not host_name:
                        host_name = previous_probe_host_name
                    if not ip_address:
                        ip_address = previous_probe_ip_address
                    if hop_details[1+probe_index*5] == '*':
                        host_name = '*'
                        ip_address = '*'
                    traceroute_result['success'][hop_index]['probes'][probe_index+1] = {
                        'host_name': py23_compat.text_type(host_name),
                        'ip_address': py23_compat.text_type(ip_address),
                        'rtt': rtt
                    }
                    previous_probe_host_name = host_name
                    previous_probe_ip_address = ip_address
        return traceroute_result