Skip to content

Commit

Permalink
Merge pull request #541 from itdependsnetworks/int_map_tests
Browse files Browse the repository at this point in the history
Int map tests
  • Loading branch information
ktbyers committed Nov 19, 2017
2 parents d5768ad + 6395912 commit 8de8599
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 42 deletions.
2 changes: 1 addition & 1 deletion napalm/base/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,6 @@ def compliance_report(self, validation_file=None, validation_source=None):
def _canonical_int(self, interface):
"""Expose the helper function within this class."""
if self.use_canonical_interface is True:
return napalm.base.helpers.canonical_interface_name(interface, update_os_mapping=None)
return napalm.base.helpers.canonical_interface_name(interface, addl_name_map=None)
else:
return interface
1 change: 1 addition & 0 deletions napalm/base/canonical_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"Hu": "HundredGigabitEthernet",
"Loopback": "Loopback",
"Lo": "Loopback",
"lo": "Loopback",
"Management": "Management",
"Mgmt": "Management",
"Ma": "Management",
Expand Down
109 changes: 68 additions & 41 deletions napalm/base/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,52 +258,79 @@ def as_number(as_number_val):
return int(as_number_str)


def int_split_on_match(split_interface):
'''
simple fuction to split on first digit, slash, or space match
'''
head = split_interface.rstrip(r'/\0123456789 ')
tail = split_interface[len(head):].lstrip()
return head, tail


def canonical_interface_name(interface, update_os_mapping=None):
'''
Function to retun interface canonical name
This puposely does not use regex, or first X characters, to ensure
there is no chance for false positives. As an example, Po = PortChannel, and
PO = POS. With either character or regex, that would produce a false positive.
'''

interface_type, interface_number = int_split_on_match(interface)

if isinstance(update_os_mapping, dict):
base_interfaces.update(update_os_mapping)
def split_interface(intf_name):
"""Split an interface name based on first digit, slash, or space match."""
head = intf_name.rstrip(r'/\0123456789. ')
tail = intf_name[len(head):].lstrip()
return (head, tail)


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 base_interfaces.get(interface_type):
long_int = base_interfaces.get(interface_type)
return long_int + str(interface_number)
# if nothing matched, at least return the original
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


def abbreviated_interface_name(interface, update_os_mapping=None):
'''
Function to retun interface canonical name
This puposely does not use regex, or first X characters, to ensure
there is no chance for false positives. As an example, Po = PortChannel, and
PO = POS. With either character or regex, that would produce a false positive.
'''
def abbreviated_interface_name(interface, addl_name_map=None, addl_reverse_map=None):
"""Function to return an abbreviated representation of the interface name.
interface_type, interface_number = int_split_on_match(interface)
: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"}
"""

if isinstance(update_os_mapping, dict):
base_interfaces.update(update_os_mapping)
# check in dict for mapping
if base_interfaces.get(interface_type):
long_int = base_interfaces.get(interface_type)
return reverse_mapping[long_int] + str(interface_number)
# if nothing matched, at least return the original
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:
return interface
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
40 changes: 40 additions & 0 deletions test/base/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,46 @@ def test_convert_uptime_string_seconds(self):
self.assertEqual(convert_uptime_string_seconds('95w2d10h58m'), 57668280)
self.assertEqual(convert_uptime_string_seconds('1h5m'), 3900)

def test_canonical_interface_name(self):
"""Test the canonical_interface_name helper function."""
self.assertEqual(napalm.base.helpers.canonical_interface_name('Fa0/1'), "FastEthernet0/1")
self.assertEqual(napalm.base.helpers.canonical_interface_name('FastEthernet0/1'),
'FastEthernet0/1')
self.assertEqual(napalm.base.helpers.canonical_interface_name('TenGig1/1/1.5'),
"TenGigabitEthernet1/1/1.5")
self.assertEqual(napalm.base.helpers.canonical_interface_name('Gi1/2'),
"GigabitEthernet1/2")
self.assertEqual(napalm.base.helpers.canonical_interface_name('HundredGigE105/1/1'),
"HundredGigabitEthernet105/1/1")
self.assertEqual(napalm.base.helpers.canonical_interface_name('Lo0'), "Loopback0")
self.assertEqual(napalm.base.helpers.canonical_interface_name('lo0'), "Loopback0")
self.assertEqual(napalm.base.helpers.canonical_interface_name('no_match0/1'),
"no_match0/1")
self.assertEqual(napalm.base.helpers.canonical_interface_name('lo10',
addl_name_map={"lo": "something_custom"}), "something_custom10")
self.assertEqual(napalm.base.helpers.canonical_interface_name('uniq0/1/1',
addl_name_map={"uniq": "something_custom"}), "something_custom0/1/1")

def test_abbreviated_interface_name(self):
"""Test the abbreviated_interface_name helper function."""
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('Fa0/1'), "Fa0/1")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('FastEthernet0/1'),
"Fa0/1")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('TenGig1/1/1.5'),
"Te1/1/1.5")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('Gi1/2'), "Gi1/2")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('HundredGigE105/1/1'),
"Hu105/1/1")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('Lo0'), "Lo0")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('lo0'), "Lo0")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('something_custom0/1'),
"something_custom0/1")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('loop10',
addl_name_map={"loop": "Loopback"}), "Lo10")
self.assertEqual(napalm.base.helpers.abbreviated_interface_name('loop10',
addl_name_map={"loop": "Loopback"},
addl_reverse_map={"Loopback": "lo"}), "lo10")


class FakeNetworkDriver(NetworkDriver):

Expand Down

0 comments on commit 8de8599

Please sign in to comment.