Skip to content

Commit

Permalink
Merge branch 'develop' into ios-non-exact-route-lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
mirceaulinic authored Aug 19, 2020
2 parents 130bca9 + 0e23a55 commit bb8aad4
Show file tree
Hide file tree
Showing 16 changed files with 5,245 additions and 184 deletions.
9 changes: 7 additions & 2 deletions napalm/base/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,14 @@ def _netmiko_open(self, device_type, netmiko_optional_args=None):
except NetMikoTimeoutException:
raise ConnectionException("Cannot connect to {}".format(self.hostname))

# ensure in enable mode if not force disable
if not self.force_no_enable:
# Disable enable mode if force_no_enable is true (for NAPALM drivers
# that support force_no_enable)
try:
if not self.force_no_enable:
self._netmiko_device.enable()
except AttributeError:
self._netmiko_device.enable()

return self._netmiko_device

def _netmiko_close(self):
Expand Down
4 changes: 2 additions & 2 deletions napalm/eos/pyeapi_syntax_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def update_cli_version(self, version):
"""
self.cli_version = version

def run_commands(self, commands, **kwargs):
def run_commands(self, commands, *args, **kwargs):
"""
Run commands wrapper
:param commands: list of commands
Expand All @@ -39,4 +39,4 @@ def run_commands(self, commands, **kwargs):
else:
commands = [cli_convert(cmd, self.cli_version) for cmd in commands]

return super(Node, self).run_commands(commands, **kwargs)
return super(Node, self).run_commands(commands, *args, **kwargs)
30 changes: 24 additions & 6 deletions napalm/ios/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,13 +800,21 @@ def get_optics(self):
for optics_entry in split_output.splitlines():
# Example, Te1/0/1 34.6 3.29 -2.0 -3.5
try:
optics_entry = optics_entry.strip("-")
split_list = optics_entry.split()
except ValueError:
return {}

int_brief = split_list[0]
output_power = split_list[3]
input_power = split_list[4]
current = 0
if len(split_list) == 5:
int_brief = split_list[0]
output_power = split_list[3]
input_power = split_list[4]
elif len(split_list) >= 6:
int_brief = split_list[0]
current = split_list[3]
output_power = split_list[4]
input_power = split_list[5]

port = canonical_interface_name(int_brief)

Expand Down Expand Up @@ -842,7 +850,7 @@ def get_optics(self):
"max": -100.0,
},
"laser_bias_current": {
"instant": 0.0,
"instant": (float(current) if "current" else -100.0),
"avg": 0.0,
"min": 0.0,
"max": 0.0,
Expand Down Expand Up @@ -3115,7 +3123,7 @@ def get_users(self):
"""
username_regex = (
r"^username\s+(?P<username>\S+)\s+(?:privilege\s+(?P<priv_level>\S+)"
r"\s+)?(?:secret \d+\s+(?P<pwd_hash>\S+))?$"
r"\s+)?(?:(password|secret) \d+\s+(?P<pwd_hash>\S+))?$"
)
pub_keychain_regex = (
r"^\s+username\s+(?P<username>\S+)(?P<keys>(?:\n\s+key-hash\s+"
Expand All @@ -3124,6 +3132,9 @@ def get_users(self):
users = {}
command = "show run | section username"
output = self._send_command(command)
if "Invalid input detected" in output:
command = "show run | include username"
output = self._send_command(command)
for match in re.finditer(username_regex, output, re.M):
users[match.groupdict()["username"]] = {
"level": int(match.groupdict()["priv_level"])
Expand Down Expand Up @@ -3406,7 +3417,14 @@ def get_network_instances(self, name=""):
if "No interfaces" in first_part:
interfaces = {}
else:
interfaces = {itf: {} for itf in if_regex.group(1).split()}
interfaces = {
canonical_interface_name(itf, {"Vl": "Vlan"}): {}
for itf in if_regex.group(1).split()
}

# remove interfaces in the VRF from the default VRF
for item in interfaces:
del instances["default"]["interfaces"]["interface"][item]

instances[vrf_name] = {
"name": vrf_name,
Expand Down
113 changes: 113 additions & 0 deletions napalm/nxos_ssh/nxos_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,17 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None)
hostname, username, password, timeout=timeout, optional_args=optional_args
)
self.platform = "nxos_ssh"
self.connector_type_map = {
"1000base-LH": "LC_CONNECTOR",
"1000base-SX": "LC_CONNECTOR",
"1000base-T": "Unknown",
"10Gbase-LR": "LC_CONNECTOR",
"10Gbase-SR": "LC_CONNECTOR",
"SFP-H10GB-CU1M": "DAC_CONNECTOR",
"SFP-H10GB-CU1.45M": "DAC_CONNECTOR",
"SFP-H10GB-CU3M": "DAC_CONNECTOR",
"SFP-H10GB-CU3.45M": "DAC_CONNECTOR",
}

def open(self):
self.device = self._netmiko_open(
Expand Down Expand Up @@ -1528,3 +1539,105 @@ def get_vlans(self):
"interfaces": self._parse_vlan_ports(vlan["vlanshowplist-ifidx"]),
}
return vlans

def get_optics(self):
command = "show interface transceiver details"
output = self._send_command(command)

# Formatting data into return data structure
optics_detail = {}

# Extraction Regexps
port_ts_re = re.compile(r"^Ether.*?(?=\nEther|\Z)", re.M | re.DOTALL)
port_re = re.compile(r"^(Ether.*)[ ]*?$", re.M)
vendor_re = re.compile("name is (.*)$", re.M)
vendor_part_re = re.compile("part number is (.*)$", re.M)
vendor_rev_re = re.compile("revision is (.*)$", re.M)
serial_no_re = re.compile("serial number is (.*)$", re.M)
type_no_re = re.compile("type is (.*)$", re.M)
rx_instant_re = re.compile(r"Rx Power[ ]+(?:(\S+?)[ ]+dBm|(N.A))", re.M)
tx_instant_re = re.compile(r"Tx Power[ ]+(?:(\S+?)[ ]+dBm|(N.A))", re.M)
current_instant_re = re.compile(r"Current[ ]+(?:(\S+?)[ ]+mA|(N.A))", re.M)

port_ts_l = port_ts_re.findall(output)

for port_ts in port_ts_l:
port = port_re.search(port_ts).group(1)
# No transceiver is present in those case
if "transceiver is not present" in port_ts:
continue
if "transceiver is not applicable" in port_ts:
continue
port_detail = {"physical_channels": {"channel": []}}
# No metric present
vendor = vendor_re.search(port_ts).group(1)
vendor_part = vendor_part_re.search(port_ts).group(1)
vendor_rev = vendor_rev_re.search(port_ts).group(1)
serial_no = serial_no_re.search(port_ts).group(1)
type_s = type_no_re.search(port_ts).group(1)
state = {
"vendor": vendor.strip(),
"vendor_part": vendor_part.strip(),
"vendor_rev": vendor_rev.strip(),
"serial_no": serial_no.strip(),
"connector_type": self.connector_type_map.get(type_s, "Unknown"),
}
if "DOM is not supported" not in port_ts:
res = rx_instant_re.search(port_ts)
input_power = res.group(1) or res.group(2)
res = tx_instant_re.search(port_ts)
output_power = res.group(1) or res.group(2)
res = current_instant_re.search(port_ts)
current = res.group(1) or res.group(2)

# If interface is shutdown it returns "N/A" as output power
# or "N/A" as input power
# Converting that to -100.0 float
try:
float(output_power)
except ValueError:
output_power = -100.0
try:
float(input_power)
except ValueError:
input_power = -100.0
try:
float(current)
except ValueError:
current = -100.0

# Defaulting avg, min, max values to -100.0 since device does not
# return these values
optic_states = {
"index": 0,
"state": {
"input_power": {
"instant": (
float(input_power) if "input_power" else -100.0
),
"avg": -100.0,
"min": -100.0,
"max": -100.0,
},
"output_power": {
"instant": (
float(output_power) if "output_power" else -100.0
),
"avg": -100.0,
"min": -100.0,
"max": -100.0,
},
"laser_bias_current": {
"instant": (float(current) if "current" else -100.0),
"avg": 0.0,
"min": 0.0,
"max": 0.0,
},
},
}
port_detail["physical_channels"]["channel"].append(optic_states)

port_detail["state"] = state
optics_detail[port] = port_detail

return optics_detail
4 changes: 2 additions & 2 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
black==19.10b0
coveralls==2.1.0
coveralls==2.1.1
ddt==1.4.1
flake8-import-order==0.18.1
pytest==5.4.3
Expand All @@ -8,4 +8,4 @@ pytest-json==0.4.0
pytest-pythonpath==0.7.3
pylama==7.7.1
mock==4.0.2
tox==3.16.1
tox==3.18.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

setup(
name="napalm",
version="3.0.1",
version="3.1.0",
packages=find_packages(exclude=("test*",)),
test_suite="test_base",
author="David Barroso, Kirk Byers, Mircea Ulinic",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"default": {
"name": "default",
"type": "DEFAULT_INSTANCE",
"state": {
"route_distinguisher": ""
},
"interfaces": {
"interface": {
"Ethernet0/0": {},
"Ethernet0/1": {},
"Ethernet0/2": {},
"Ethernet0/3": {},
"Ethernet1/0": {},
"Ethernet1/1": {},
"Ethernet1/2": {},
"Ethernet1/3": {},
"Ethernet2/0": {},
"Ethernet2/1": {},
"Ethernet2/2": {},
"Ethernet2/3": {},
"Ethernet3/0": {},
"Ethernet3/1": {},
"Ethernet3/2": {},
"Ethernet3/3": {},
"Vlan1": {},
"Vlan2": {},
"Vlan3": {},
"Vlan4": {}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Interface IP-Address OK? Method Status Protocol
Ethernet0/0 172.29.29.220 YES manual up up
Ethernet0/1 unassigned YES unset up up
Ethernet0/2 unassigned YES unset up up
Ethernet0/3 unassigned YES unset up up
Ethernet1/0 unassigned YES unset up up
Ethernet1/1 unassigned YES unset up up
Ethernet1/2 unassigned YES unset up up
Ethernet1/3 unassigned YES unset up up
Ethernet2/0 unassigned YES unset up up
Ethernet2/1 unassigned YES unset up up
Ethernet2/2 unassigned YES unset up up
Ethernet2/3 unassigned YES unset up up
Ethernet3/0 unassigned YES unset up up
Ethernet3/1 unassigned YES unset up up
Ethernet3/2 unassigned YES unset up up
Ethernet3/3 unassigned YES unset up up
Vlan1 unassigned YES unset administratively down down
Vlan2 2.2.2.2 YES manual up up
Vlan3 3.3.3.3 YES manual up up
Vlan4 4.4.4.4 YES manual up up
Empty file.
Loading

0 comments on commit bb8aad4

Please sign in to comment.