From 38a3a029e1d1ef0e3d542cd94091f740ca41766f Mon Sep 17 00:00:00 2001 From: Alexey Kolobynin Date: Wed, 29 Apr 2020 17:46:37 -0500 Subject: [PATCH] Add pyeapi.Node shim to handle CLI translation Create a new Node class that checks EOS versions for forward and backward compatible command translation for FN-0039, along with unit tests for version detection and translation --- napalm/eos/eos.py | 31 ++- napalm/eos/pyeapi_syntax_wrapper.py | 40 +++ napalm/eos/utils/cli_syntax.py | 357 +++++++++++++++++++++++++ napalm/eos/utils/versions.py | 70 +++++ test/eos/conftest.py | 8 + test/eos/mocked_data/show_clock.text | 3 - test/eos/mocked_data/show_version.text | 13 + test/eos/test_cli_syntax.py | 51 ++++ test/eos/test_versions.py | 28 ++ 9 files changed, 595 insertions(+), 6 deletions(-) create mode 100644 napalm/eos/pyeapi_syntax_wrapper.py create mode 100644 napalm/eos/utils/cli_syntax.py create mode 100644 napalm/eos/utils/versions.py delete mode 100644 test/eos/mocked_data/show_clock.text create mode 100644 test/eos/mocked_data/show_version.text create mode 100644 test/eos/test_cli_syntax.py create mode 100644 test/eos/test_versions.py diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index fa3745433..32cd33418 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -46,6 +46,8 @@ CommandErrorException, ) from napalm.eos.constants import LLDP_CAPAB_TRANFORM_TABLE +from napalm.eos.pyeapi_syntax_wrapper import Node +from napalm.eos.utils.versions import EOSVersion import napalm.base.constants as c # local modules @@ -83,6 +85,25 @@ class EOSDriver(NetworkDriver): re.VERBOSE, ) + def _determine_syntax_version(self, ver_output): + """ + Determine cli syntax version from "sh ver" output + Syntax versions: + 1: all EOS versions before 4.23.0 + 2: all EOS version 4.23.0 and higher + :param ver_output: list of lines for "sh ver" command output + :return: int: cli version + """ + regexp = re.compile(r"^Software image version:\s+(?P\d+\.\d+\.\d+)") + + for line in ver_output.split("\n"): + m = regexp.match(line) + + if m and EOSVersion(m.group("version")) >= EOSVersion("4.23.0"): + return 2 + + return 1 + def __init__(self, hostname, username, password, timeout=60, optional_args=None): """ Initialize EOS Driver. @@ -156,11 +177,15 @@ def open(self): ) if self.device is None: - self.device = pyeapi.client.Node(connection, enablepwd=self.enablepwd) + self.device = Node(connection, enablepwd=self.enablepwd) # does not raise an Exception if unusable - # let's try to run a very simple command - self.device.run_commands(["show clock"], encoding="text") + # let's try to determine if we need to use new EOS cli syntax + cli_version = self._determine_syntax_version( + self.device.run_commands(["show version"], encoding="text")[0]["output"] + ) + + self.device.update_cli_version(cli_version) except ConnectionError as ce: # and this is raised either if device not avaiable # either if HTTP(S) agent is not enabled diff --git a/napalm/eos/pyeapi_syntax_wrapper.py b/napalm/eos/pyeapi_syntax_wrapper.py new file mode 100644 index 000000000..695282860 --- /dev/null +++ b/napalm/eos/pyeapi_syntax_wrapper.py @@ -0,0 +1,40 @@ +"""pyeapi wrapper to fix cli syntax change""" +import pyeapi +from napalm.eos.utils.cli_syntax import cli_convert + + +class Node(pyeapi.client.Node): + """ + pyeapi node wrapper to fix cli syntax change + """ + + def __init__(self, *args, **kwargs): + if "cli_version" in kwargs: + self.cli_version = kwargs["cli_version"] + del kwargs["cli_version"] + else: + self.cli_version = 1 + + super(Node, self).__init__(*args, **kwargs) + + def update_cli_version(self, version): + """ + Update CLI version number for this device + :param version: int: version number + :return: None + """ + self.cli_version = version + + def run_commands(self, commands, **kwargs): + """ + Run commands wrapper + :param commands: list of commands + :param kwargs: other args + :return: list of outputs + """ + if isinstance(commands, str): + new_commands = [cli_convert(commands, self.cli_version)] + else: + new_commands = [cli_convert(cmd, self.cli_version) for cmd in commands] + + return super(Node, self).run_commands(new_commands, **kwargs) diff --git a/napalm/eos/utils/cli_syntax.py b/napalm/eos/utils/cli_syntax.py new file mode 100644 index 000000000..1dcda1bf2 --- /dev/null +++ b/napalm/eos/utils/cli_syntax.py @@ -0,0 +1,357 @@ +""" +EOS CLI syntax changes +""" +CLI_SYNTAX = { + # Default CLI syntax version + # We do trandlation from 4.23.0 syntax to pre-4.23.0 syntax + 1: { + "aaa authorization serial-console": "aaa authorization console", + "area not-so-stubby lsa type-7 convert type-5": "area nssa translate type7 always", + "arp aging timeout": "arp timeout", + "bfd default": "bfd all-interfaces", + "dynamic peer max": "bgp listen limit", + "class-map type copp": "class-map type control-plane", + "clear arp": "clear ip arp", + "clear ip nat flow translation": "clear ip nat translation", + "clear ospfv3 ipv6 force-spf": "clear ipv6 ospf force-spf", + "system control-plane": "control-plane", + "metric default": "default-metric", + "dot1x reauthorization request limit ": "dot1x max-reauth-req", + "enable password": "enable secret", + "delete startup-config": "erase startup-config", + "errdisable detect cause link-change": "errdisable detect cause link-flap", + "ip community-list regexp": "ip community-list expanded", + "ip dhcp relay all-subnets": "ip dhcp smart-relay", + "ip dhcp relay all-subnets default": "ip dhcp smart-relay global", + "dns domain": "ip domain-name", + "ip extcommunity-list regexp": "ip extcommunity-list expanded", + "ip extcommunity-list": "ip extcommunity-list standard", + "ip http client local-interface": "ip http client source-interface", + "query-max-response-time": "ip igmp query-max-response-time", + "ip igmp snooping vlan fast-leave": "ip igmp snooping vlan immediate-leave", + "ip igmp snooping vlan multicast-router": "ip igmp snooping vlan mrouter", + "ip igmp snooping vlan member": "ip igmp snooping vlan static", + # disabled next command because of ambiguity + # 'default-peer': 'ip msdp default-peer', + # disabled next command because of ambiguity + # 'description': 'ip msdp description', + "sa-limit": "ip msdp group-limit", + # disabled next command because of ambiguity + # 'keepalive': 'ip msdp keepalive', + "mesh-group": "ip msdp mesh-group", + "originator-id local-interface": "ip msdp originator-id", + # disabled next command because of ambiguity + # 'peer': 'ip msdp peer', + "sa filter in": "ip msdp sa-filter in", + "sa filter out": "ip msdp sa-filter out", + "sa limit": "ip msdp sa-limit", + # disabled next command because of ambiguity + # 'disabled': 'ip msdp shutdown', + "connection retry interval": "ip msdp timer", + "ip ospf neighbor bfd": "ip ospf bfd", + "router-id output-format hostnames": "ip ospf name-lookup", + "ip ospf disabled": "ip ospf shutdown", + "anycast-rp": "ip pim anycast-rp", + # disabled next command because of ambiguity + # 'bfd': 'ip pim bfd', + "pim bfd": "ip pim bfd-instance", + "pim bsr border": "ip pim bsr-border", + "log neighbors": "ip pim log-neighbor-changes", + "pim neighbor filter": "ip pim neighbor-filter", + "pim hello interval": "ip pim query-interval", + "register local-interface": "ip pim register-source", + "spt threshold match list": "ip pim spt-threshold group-list", + "ssm address range": "ip pim ssm range", + "rip v2 multicast disable": "ip rip v2-broadcast", + "ipv6 nd ra disabled": "ipv6 nd ra suppress", + "ospfv3 ipv6 retransmit-interval": "ipv6 ospf retransmit-interval", + "isis lsp tx interval": "isis lsp-interval", + # disabled next command because of ambiguity + # 'passive': 'passive-interface', + "lacp timer": "lacp rate", + "link tracking group ": "link state track", + "lldp hold-time": "lldp holdtime", + "lldp timer reinitialization": "lldp reinit", + "lldp tlv transmit": "lldp tlv-select", + "neighbor bfd": "neighbor fall-over bfd", + "neighbor peer group": "neighbor peer-group", + "neighbor rib-in pre-policy retain": "neighbor soft-reconfiguration", + "neighbor passive": "neighbor transport connection-mode", + "ntp local-interface": "ntp source", + "policy-map type copp": "policy-map type control-plane", + "policy-map type quality-of-service": "policy-map type qos", + "priority-flow-control": "priority-flow-control mode", + "pvlan mapping": "private-vlan mapping", + "ptp sync-message interval": "ptp sync interval", + "redundancy manual switchover": "redundancy force-switchover", + "cli vrf ": "routing-context vrf", + "logging format sequence-numbers": "service sequence-numbers", + "show aaa methods": "show aaa method-lists", + "show users detail": "show aaa sessions", + "show bfd peers": "show bfd neighbors", + "show dot1x all brief": "show dot1x all summary", + "show system environment all": "show environment all", + "show system environment cooling": "show environment cooling", + "show interfaces hardware": "show interfaces capabilities", + "show interfaces flow-control": "show interfaces flowcontrol", + "show pvlan mapping interfaces": "show interfaces private-vlan mapping", + "show interfaces switchport backup-link": "show interfaces switchport backup", + "show igmp snooping querier": "show ip igmp snooping querier", + "show multicast fib ipv4": "show ip mfib", + "show msdp mesh-group": "show ip msdp mesh-group", + "show msdp rpf-peer": "show ip msdp rpf-peer", + "show ip ospf request queue": "show ip ospf request-list", + "show ip ospf retransmission queue": "show ip ospf retransmission-list", + "show ip route match tag": "show ip route tag", + "show ipv6 bgp match community": "show ipv6 bgp community", + "show ipv6 bgp peers": "show ipv6 bgp neighbors", + "show ipv6 route match tag": "show ipv6 route tag", + "show isis network topology": "show isis topology", + "show lacp peer": "show lacp neighbor", + "show link tracking group": "show link state group", + "show lldp counters": "show lldp traffic", + "show bridge mac-address-table aging timeout": "show mac-address-table aging-time", + "show policy-map type copp": "show policy-map control-plane", + "show policy-map copp": "show policy-map interface control-plane", + "show port-channel dense": "show port-channel summary", + "show port-channel load-balance": "show port-channel traffic", + "show port-security mac-address": "show port-security address", + "show ptp local-clock": "show ptp clock", + "show ptp masters": "show ptp parent", + "show ptp local-clock time properties": "show ptp time-property", + "show redundancy status": "show redundancy states", + "show users roles": "show role", + "show snmp v2-mib chassis": "show snmp chassis", + "show snmp v2-mib contact": "show snmp contact", + "show snmp notification host": "show snmp host", + "show snmp v2-mib location": "show snmp location", + "show snmp local-interface": "show snmp source-interface", + "show snmp notification": "show snmp trap", + "show spanning-tree instance": "show spanning-tree bridge", + "show users accounts": "show user-account", + "show vlan brief count": "show vlan summary", + "snmp trap link-change": "snmp trap link-status", + "snmp-server local-interface": "snmp-server source-interface", + "spanning-tree transmit active": "spanning-tree bridge assurance", + "spanning-tree guard loop default": "spanning-tree loopguard default", + "spanning-tree edge-port bpdufilter default": "spanning-tree portfast bpdufilter default", + "spanning-tree edge-port bpduguard default": "spanning-tree portfast bpduguard default", + "spanning-tree bpdu tx hold-count": "spanning-tree transmit hold-count", + "spanning-tree vlan-id": "spanning-tree vlan", + "counters per-entry": "statistics per-entry", + "switchport backup-link": "switchport backup interface", + "switchport port-security mac-address maximum": "switchport port-security maximum", + "switchport vlan translation": "switchport vlan mapping", + # disabled next command because of ambiguity + # 'timers': 'timers basic', + "timers lsa rx min interval": "timers lsa arrival", + "timers lsa tx delay initial": "timers throttle lsa all", + "timers spf delay initial": "timers throttle spf", + "username ssh-key": "username sshkey", + "vlan internal order": "vlan internal allocation policy", + "vrf instance": "vrf definition", + # disabled next command because of ambiguity + # 'vrf': 'vrf forwarding', + "vrrp peer authentication": "vrrp authentication", + "vrrp timers delay reload": "vrrp delay reload", + "vrrp session description": "vrrp description", + "vrrp ipv4": "vrrp ip", + "vrrp ipv4 secondary": "vrrp ip secondary", + "vrrp priority-level": "vrrp priority", + "vrrp disabled": "vrrp shutdown", + "vrrp advertisement interval": "vrrp timers advertise", + "vrrp tracked-object": "vrrp track", + }, + # CLI syntax version after EOS 4.23.0 + 2: { + "aaa authorization console": "aaa authorization serial-console", + "area nssa translate type7 always": "area not-so-stubby lsa type-7 convert type-5", + "arp timeout": "arp aging timeout", + "bfd all-interfaces": "bfd default", + "bgp listen limit": "dynamic peer max", + "class-map type control-plane": "class-map type copp", + "clear ip arp": "clear arp", + "clear ip nat translation": "clear ip nat flow translation", + "clear ipv6 ospf force-spf": "clear ospfv3 ipv6 force-spf", + "control-plane": "system control-plane", + "default-metric": "metric default", + "dot1x max-reauth-req": "dot1x reauthorization request limit ", + "enable secret": "enable password", + "erase startup-config": "delete startup-config", + "errdisable detect cause link-flap": "errdisable detect cause link-change", + "ip community-list expanded": "ip community-list regexp", + "ip dhcp smart-relay": "ip dhcp relay all-subnets", + "ip dhcp smart-relay global": "ip dhcp relay all-subnets default", + "ip domain-name": "dns domain", + "ip extcommunity-list expanded": "ip extcommunity-list regexp", + "ip extcommunity-list standard": "ip extcommunity-list", + "ip http client source-interface": "ip http client local-interface", + "ip igmp query-max-response-time": "query-max-response-time", + "ip igmp snooping vlan immediate-leave": "ip igmp snooping vlan fast-leave", + "ip igmp snooping vlan mrouter": "ip igmp snooping vlan multicast-router", + "ip igmp snooping vlan static": "ip igmp snooping vlan member", + "ip msdp default-peer": "default-peer", + "ip msdp description": "description", + "ip msdp group-limit": "sa-limit", + "ip msdp keepalive": "keepalive", + "ip msdp mesh-group": "mesh-group", + "ip msdp originator-id": "originator-id local-interface", + "ip msdp peer": "peer", + "ip msdp sa-filter in": "sa filter in", + "ip msdp sa-filter out": "sa filter out", + "ip msdp sa-limit": "sa limit", + "ip msdp shutdown": "disabled", + "ip msdp timer": "connection retry interval", + "ip ospf bfd": "ip ospf neighbor bfd", + "ip ospf name-lookup": "router-id output-format hostnames", + "ip ospf shutdown": "ip ospf disabled", + "ip pim anycast-rp": "anycast-rp", + "ip pim bfd": "bfd", + "ip pim bfd-instance": "pim bfd", + "ip pim bsr-border": "pim bsr border", + "ip pim log-neighbor-changes": "log neighbors", + "ip pim neighbor-filter": "pim neighbor filter", + "ip pim query-interval": "pim hello interval", + "ip pim register-source": "register local-interface", + "ip pim spt-threshold group-list": "spt threshold match list", + "ip pim ssm range": "ssm address range", + "ip rip v2-broadcast": "rip v2 multicast disable", + "ipv6 nd ra suppress": "ipv6 nd ra disabled", + "ipv6 ospf retransmit-interval": "ospfv3 ipv6 retransmit-interval", + "isis lsp-interval": "isis lsp tx interval", + "passive-interface": "passive", + "lacp rate": "lacp timer", + "link state track": "link tracking group ", + "lldp holdtime": "lldp hold-time", + "lldp reinit": "lldp timer reinitialization", + "lldp tlv-select": "lldp tlv transmit", + "neighbor fall-over bfd": "neighbor bfd", + "neighbor peer-group": "neighbor peer group", + "neighbor soft-reconfiguration": "neighbor rib-in pre-policy retain", + "neighbor transport connection-mode": "neighbor passive", + "ntp source": "ntp local-interface", + "policy-map type control-plane": "policy-map type copp", + "policy-map type qos": "policy-map type quality-of-service", + "priority-flow-control mode": "priority-flow-control", + "private-vlan mapping": "pvlan mapping", + "ptp sync interval": "ptp sync-message interval", + "redundancy force-switchover": "redundancy manual switchover", + "routing-context vrf": "cli vrf ", + "service sequence-numbers": "logging format sequence-numbers", + "show aaa method-lists": "show aaa methods", + "show aaa sessions": "show users detail", + "show bfd neighbors": "show bfd peers", + "show dot1x all summary": "show dot1x all brief", + "show environment all": "show system environment all", + "show environment cooling": "show system environment cooling", + "show interfaces capabilities": "show interfaces hardware", + "show interfaces flowcontrol": "show interfaces flow-control", + "show interfaces private-vlan mapping": "show pvlan mapping interfaces", + "show interfaces switchport backup": "show interfaces switchport backup-link", + "show ip igmp snooping querier": "show igmp snooping querier", + "show ip mfib": "show multicast fib ipv4", + "show ip msdp mesh-group": "show msdp mesh-group", + "show ip msdp rpf-peer": "show msdp rpf-peer", + "show ip ospf request-list": "show ip ospf request queue", + "show ip ospf retransmission-list": "show ip ospf retransmission queue", + "show ip route tag": "show ip route match tag", + "show ipv6 bgp community": "show ipv6 bgp match community", + "show ipv6 bgp neighbors": "show ipv6 bgp peers", + "show ipv6 route tag": "show ipv6 route match tag", + "show isis topology": "show isis network topology", + "show lacp neighbor": "show lacp peer", + "show link state group": "show link tracking group", + "show lldp traffic": "show lldp counters", + "show mac-address-table aging-time": "show bridge mac-address-table aging timeout", + "show policy-map control-plane": "show policy-map type copp", + "show policy-map interface control-plane": "show policy-map copp", + "show port-channel summary": "show port-channel dense", + "show port-channel traffic": "show port-channel load-balance", + "show port-security address": "show port-security mac-address", + "show ptp clock": "show ptp local-clock", + "show ptp parent": "show ptp masters", + "show ptp time-property": "show ptp local-clock time properties", + "show redundancy states": "show redundancy status", + "show role": "show users roles", + "show snmp chassis": "show snmp v2-mib chassis", + "show snmp contact": "show snmp v2-mib contact", + "show snmp host": "show snmp notification host", + "show snmp location": "show snmp v2-mib location", + "show snmp source-interface": "show snmp local-interface", + "show snmp trap": "show snmp notification", + "show spanning-tree bridge": "show spanning-tree instance", + "show user-account": "show users accounts", + "show vlan summary": "show vlan brief count", + "snmp trap link-status": "snmp trap link-change", + "snmp-server source-interface": "snmp-server local-interface", + "spanning-tree bridge assurance": "spanning-tree transmit active", + "spanning-tree loopguard default": "spanning-tree guard loop default", + "spanning-tree portfast bpdufilter default": "spanning-tree edge-port bpdufilter default", + "spanning-tree portfast bpduguard default": "spanning-tree edge-port bpduguard default", + "spanning-tree transmit hold-count": "spanning-tree bpdu tx hold-count", + "spanning-tree vlan": "spanning-tree vlan-id", + "statistics per-entry": "counters per-entry", + "switchport backup interface": "switchport backup-link", + "switchport port-security maximum": "switchport port-security mac-address maximum", + "switchport vlan mapping": "switchport vlan translation", + "timers basic": "timers", + "timers lsa arrival": "timers lsa rx min interval", + "timers throttle lsa all": "timers lsa tx delay initial", + "timers throttle spf": "timers spf delay initial", + "username sshkey": "username ssh-key", + "vlan internal allocation policy": "vlan internal order", + "vrf definition": "vrf instance", + "vrf forwarding": "vrf", + "vrrp authentication": "vrrp peer authentication", + "vrrp delay reload": "vrrp timers delay reload", + "vrrp description": "vrrp session description", + "vrrp ip": "vrrp ipv4", + "vrrp ip secondary": "vrrp ipv4 secondary", + "vrrp priority": "vrrp priority-level", + "vrrp shutdown": "vrrp disabled", + "vrrp timers advertise": "vrrp advertisement interval", + "vrrp track": "vrrp tracked-object", + }, +} + + +class CliConverter: + """ + ClI converter class + """ + + def __init__(self, syntax): + """ + Object creation + :param syntax: syntax dict + """ + self.syntax = syntax + + def convert(self, command, version): + """ + Convert command from version 1 to specified version + :param command: str: command + :param version: int: version number + :return: str: command + """ + if version not in self.syntax: + return command + + for c in self.syntax[version]: + if command.startswith(c): + return self.syntax[version][c] + command[len(c) :] + + return command + + +CONVERTER = CliConverter(CLI_SYNTAX) + + +def cli_convert(command, version): + """ + Convert command from CLI version 1 to one from CLI of specified version + :param command: str: CLI command + :param version: int: EOS CLI version number + :return: str: command + """ + return CONVERTER.convert(command, version) diff --git a/napalm/eos/utils/versions.py b/napalm/eos/utils/versions.py new file mode 100644 index 000000000..7e63cc0bc --- /dev/null +++ b/napalm/eos/utils/versions.py @@ -0,0 +1,70 @@ +"""Some functions to work with EOS version numbers""" +import re + + +class EOSVersion: + """ + Class to represent EOS version + """ + + def __init__(self, version): + """ + Create object + :param version: str: version string + """ + self.version = version + self.numbers = [] + self.type = "" + + self._parse(version) + + def _parse(self, version): + """ + Parse version string + :param version: str: version + :return: None + """ + m = re.match(r"^(?P\d[\d.]+\d)", version) + + if m: + self.numbers = m.group("numbers").split(".") + + def __lt__(self, other): + if not len(self.numbers): + return True + + for x, y in zip(self.numbers, other.numbers): + if x < y: + return True + elif x > y: + return False + + return False + + def __gt__(self, other): + if not len(self.numbers): + return False + + for x, y in zip(self.numbers, other.numbers): + if x > y: + return True + elif x < y: + return False + + return False + + def __eq__(self, other): + if len(self.numbers) != len(other.numbers): + return False + + for x, y in zip(self.numbers, other.numbers): + if x != y: + return False + + return True + + def __le__(self, other): + return self < other or self == other + + def __ge__(self, other): + return self > other or self == other diff --git a/test/eos/conftest.py b/test/eos/conftest.py index c885f5849..c7cd31262 100644 --- a/test/eos/conftest.py +++ b/test/eos/conftest.py @@ -56,3 +56,11 @@ def run_commands(self, command_list, encoding="json"): result.append({"output": self.read_txt_file(full_path)}) return result + + def update_cli_version(self, version): + """ + Update CLI version number for this device + :param version: int: version number + :return: None + """ + self.cli_version = version diff --git a/test/eos/mocked_data/show_clock.text b/test/eos/mocked_data/show_clock.text deleted file mode 100644 index 4f0b938b4..000000000 --- a/test/eos/mocked_data/show_clock.text +++ /dev/null @@ -1,3 +0,0 @@ -Wed Jun 22 09:14:42 2016 -Timezone: UTC -Clock source: local diff --git a/test/eos/mocked_data/show_version.text b/test/eos/mocked_data/show_version.text new file mode 100644 index 000000000..9e8d32728 --- /dev/null +++ b/test/eos/mocked_data/show_version.text @@ -0,0 +1,13 @@ +Arista DCS-7150S-64-CL-R +Hardware version: 01.01 +Serial number: JPE00000000 +System MAC address: 001c.7327.07e0 + +Software image version: 4.22.4M-2GB +Architecture: i686 +Internal build version: 4.22.4M-2GB-15583082.4224M +Internal build ID: 523a3357-484c-4110-9019-39750ffa8af5 + +Uptime: 3 weeks, 1 days, 2 hours and 1 minutes +Total memory: 4009188 kB +Free memory: 2515256 kB diff --git a/test/eos/test_cli_syntax.py b/test/eos/test_cli_syntax.py new file mode 100644 index 000000000..791dca095 --- /dev/null +++ b/test/eos/test_cli_syntax.py @@ -0,0 +1,51 @@ +""" +Tests for EOS cli_syntax +""" +from napalm.eos.utils.cli_syntax import cli_convert + + +def test_cli_no_change_v2(): + """ + Test no change for basic commands in version 2 + :return: + """ + commands = ["show version", "show interfaces"] + + for c in commands: + assert c == cli_convert(c, 2) + assert c == cli_convert(c, 1) + + +def test_cli_no_change_non_exist_version(): + """ + Test no change for basic commands and non-existing versions + :return: + """ + commands = ["show version", "show interfaces"] + + for c in commands: + assert c == cli_convert(c, 100000) + + +def test_cli_change_exact(): + """ + Test cli change for exact commands + """ + commands = ["show ipv6 bgp neighbors", "show lldp traffic"] + expect = ["show ipv6 bgp peers", "show lldp counters"] + + for c, e in zip(commands, expect): + assert e == cli_convert(c, 2) + assert c == cli_convert(e, 1) + + +def test_cli_change_long_commands(): + """ + Test cli change for long commands + """ + commands = ["show ipv6 bgp neighbors vrf all", "show lldp traffic | include test"] + expect = ["show ipv6 bgp peers vrf all", "show lldp counters | include test"] + + for c, e in zip(commands, expect): + assert e == cli_convert(c, 2) + assert c == cli_convert(e, 1) diff --git a/test/eos/test_versions.py b/test/eos/test_versions.py new file mode 100644 index 000000000..8c284e7a1 --- /dev/null +++ b/test/eos/test_versions.py @@ -0,0 +1,28 @@ +"""Tests for versions utils""" +from napalm.eos.utils.versions import EOSVersion + + +def test_version_create(): + """ + Test we can create version object + """ + versions = ["4.21.7.1M", "4.20.24F-2GB", "blablabla"] + + for v in versions: + assert v == EOSVersion(v).version + + +def test_version_comparisons(): + """ + Test version comparison + """ + old_version = "4.21.7.1M" + new_verion = "4.23.0F" + + assert EOSVersion(old_version) < EOSVersion(new_verion) + assert EOSVersion(new_verion) > EOSVersion(old_version) + assert EOSVersion(old_version) <= EOSVersion(new_verion) + assert EOSVersion(new_verion) >= EOSVersion(old_version) + assert not EOSVersion(old_version) < EOSVersion(old_version) + assert EOSVersion(old_version) == EOSVersion(old_version) + assert EOSVersion(old_version) <= EOSVersion(old_version)