Skip to content

Commit 803f764

Browse files
bewingpraniqmirceaulinic
authored
EOS syntax change updates (#1093)
* 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 * Use json version instead of text Co-authored-by: Alexey Kolobynin <[email protected]> Co-authored-by: Mircea Ulinic <[email protected]>
1 parent 0770843 commit 803f764

File tree

9 files changed

+580
-6
lines changed

9 files changed

+580
-6
lines changed

napalm/eos/eos.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
CommandErrorException,
4747
)
4848
from napalm.eos.constants import LLDP_CAPAB_TRANFORM_TABLE
49+
from napalm.eos.pyeapi_syntax_wrapper import Node
50+
from napalm.eos.utils.versions import EOSVersion
4951
import napalm.base.constants as c
5052

5153
# local modules
@@ -156,11 +158,16 @@ def open(self):
156158
)
157159

158160
if self.device is None:
159-
self.device = pyeapi.client.Node(connection, enablepwd=self.enablepwd)
161+
self.device = Node(connection, enablepwd=self.enablepwd)
160162
# does not raise an Exception if unusable
161163

162-
# let's try to run a very simple command
163-
self.device.run_commands(["show clock"], encoding="text")
164+
# let's try to determine if we need to use new EOS cli syntax
165+
sh_ver = self.device.run_commands(["show version"])
166+
cli_version = (
167+
2 if EOSVersion(sh_ver[0]["version"]) >= EOSVersion("4.23.0") else 1
168+
)
169+
170+
self.device.update_cli_version(cli_version)
164171
except ConnectionError as ce:
165172
# and this is raised either if device not avaiable
166173
# either if HTTP(S) agent is not enabled
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""pyeapi wrapper to fix cli syntax change"""
2+
import pyeapi
3+
from napalm.eos.utils.cli_syntax import cli_convert
4+
5+
6+
class Node(pyeapi.client.Node):
7+
"""
8+
pyeapi node wrapper to fix cli syntax change
9+
"""
10+
11+
def __init__(self, *args, **kwargs):
12+
if "cli_version" in kwargs:
13+
self.cli_version = kwargs["cli_version"]
14+
del kwargs["cli_version"]
15+
else:
16+
self.cli_version = 1
17+
18+
super(Node, self).__init__(*args, **kwargs)
19+
20+
def update_cli_version(self, version):
21+
"""
22+
Update CLI version number for this device
23+
:param version: int: version number
24+
:return: None
25+
"""
26+
self.cli_version = version
27+
28+
def run_commands(self, commands, **kwargs):
29+
"""
30+
Run commands wrapper
31+
:param commands: list of commands
32+
:param kwargs: other args
33+
:return: list of outputs
34+
"""
35+
if isinstance(commands, str):
36+
new_commands = [cli_convert(commands, self.cli_version)]
37+
else:
38+
new_commands = [cli_convert(cmd, self.cli_version) for cmd in commands]
39+
40+
return super(Node, self).run_commands(new_commands, **kwargs)

napalm/eos/utils/cli_syntax.py

Lines changed: 357 additions & 0 deletions
Large diffs are not rendered by default.

napalm/eos/utils/versions.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Some functions to work with EOS version numbers"""
2+
import re
3+
4+
5+
class EOSVersion:
6+
"""
7+
Class to represent EOS version
8+
"""
9+
10+
def __init__(self, version):
11+
"""
12+
Create object
13+
:param version: str: version string
14+
"""
15+
self.version = version
16+
self.numbers = []
17+
self.type = ""
18+
19+
self._parse(version)
20+
21+
def _parse(self, version):
22+
"""
23+
Parse version string
24+
:param version: str: version
25+
:return: None
26+
"""
27+
m = re.match(r"^(?P<numbers>\d[\d.]+\d)", version)
28+
29+
if m:
30+
self.numbers = m.group("numbers").split(".")
31+
32+
def __lt__(self, other):
33+
if not len(self.numbers):
34+
return True
35+
36+
for x, y in zip(self.numbers, other.numbers):
37+
if x < y:
38+
return True
39+
elif x > y:
40+
return False
41+
42+
return False
43+
44+
def __gt__(self, other):
45+
if not len(self.numbers):
46+
return False
47+
48+
for x, y in zip(self.numbers, other.numbers):
49+
if x > y:
50+
return True
51+
elif x < y:
52+
return False
53+
54+
return False
55+
56+
def __eq__(self, other):
57+
if len(self.numbers) != len(other.numbers):
58+
return False
59+
60+
for x, y in zip(self.numbers, other.numbers):
61+
if x != y:
62+
return False
63+
64+
return True
65+
66+
def __le__(self, other):
67+
return self < other or self == other
68+
69+
def __ge__(self, other):
70+
return self > other or self == other

test/eos/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,11 @@ def run_commands(self, command_list, encoding="json"):
5656
result.append({"output": self.read_txt_file(full_path)})
5757

5858
return result
59+
60+
def update_cli_version(self, version):
61+
"""
62+
Update CLI version number for this device
63+
:param version: int: version number
64+
:return: None
65+
"""
66+
self.cli_version = version

test/eos/mocked_data/show_clock.text

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"memTotal": 3954980,
3+
"uptime": 200478.31,
4+
"modelName": "DCS-7150S-64-CL-R",
5+
"internalVersion": "4.21.8M-2GB-13902577.4218M",
6+
"mfgName": "Arista",
7+
"serialNumber": "JPE00000000",
8+
"systemMacAddress": "00:1c:73:00:00:00",
9+
"bootupTimestamp": 1588135848.0,
10+
"memFree": 2558364,
11+
"version": "4.21.8M-2GB",
12+
"architecture": "i386",
13+
"isIntlVersion": false,
14+
"internalBuildId": "5af75062-ded5-4c99-8f44-daa88aa4414d",
15+
"hardwareRevision": "01.03"
16+
}

test/eos/test_cli_syntax.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""
2+
Tests for EOS cli_syntax
3+
"""
4+
from napalm.eos.utils.cli_syntax import cli_convert
5+
6+
7+
def test_cli_no_change_v2():
8+
"""
9+
Test no change for basic commands in version 2
10+
:return:
11+
"""
12+
commands = ["show version", "show interfaces"]
13+
14+
for c in commands:
15+
assert c == cli_convert(c, 2)
16+
assert c == cli_convert(c, 1)
17+
18+
19+
def test_cli_no_change_non_exist_version():
20+
"""
21+
Test no change for basic commands and non-existing versions
22+
:return:
23+
"""
24+
commands = ["show version", "show interfaces"]
25+
26+
for c in commands:
27+
assert c == cli_convert(c, 100000)
28+
29+
30+
def test_cli_change_exact():
31+
"""
32+
Test cli change for exact commands
33+
"""
34+
commands = ["show ipv6 bgp neighbors", "show lldp traffic"]
35+
expect = ["show ipv6 bgp peers", "show lldp counters"]
36+
37+
for c, e in zip(commands, expect):
38+
assert e == cli_convert(c, 2)
39+
assert c == cli_convert(e, 1)
40+
41+
42+
def test_cli_change_long_commands():
43+
"""
44+
Test cli change for long commands
45+
"""
46+
commands = ["show ipv6 bgp neighbors vrf all", "show lldp traffic | include test"]
47+
expect = ["show ipv6 bgp peers vrf all", "show lldp counters | include test"]
48+
49+
for c, e in zip(commands, expect):
50+
assert e == cli_convert(c, 2)
51+
assert c == cli_convert(e, 1)

test/eos/test_versions.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Tests for versions utils"""
2+
from napalm.eos.utils.versions import EOSVersion
3+
4+
5+
def test_version_create():
6+
"""
7+
Test we can create version object
8+
"""
9+
versions = ["4.21.7.1M", "4.20.24F-2GB", "blablabla"]
10+
11+
for v in versions:
12+
assert v == EOSVersion(v).version
13+
14+
15+
def test_version_comparisons():
16+
"""
17+
Test version comparison
18+
"""
19+
old_version = "4.21.7.1M"
20+
new_verion = "4.23.0F"
21+
22+
assert EOSVersion(old_version) < EOSVersion(new_verion)
23+
assert EOSVersion(new_verion) > EOSVersion(old_version)
24+
assert EOSVersion(old_version) <= EOSVersion(new_verion)
25+
assert EOSVersion(new_verion) >= EOSVersion(old_version)
26+
assert not EOSVersion(old_version) < EOSVersion(old_version)
27+
assert EOSVersion(old_version) == EOSVersion(old_version)
28+
assert EOSVersion(old_version) <= EOSVersion(old_version)

0 commit comments

Comments
 (0)