Skip to content
This repository has been archived by the owner on Jan 16, 2019. It is now read-only.

Commit

Permalink
Merge pull request #116 from napalm-automation/develop
Browse files Browse the repository at this point in the history
Release 0.6.1
  • Loading branch information
mirceaulinic authored Feb 8, 2017
2 parents 8271cb9 + b123c8b commit 2982aec
Show file tree
Hide file tree
Showing 23 changed files with 327 additions and 92 deletions.
89 changes: 63 additions & 26 deletions napalm_ios/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from napalm_base.exceptions import ReplaceConfigException, MergeConfigException
from napalm_base.utils import py23_compat
import napalm_base.constants as C
import napalm_base.helpers

# Easier to store these as constants
HOUR_SECONDS = 3600
Expand Down Expand Up @@ -359,6 +360,9 @@ def commit_config(self):
if ('Failed to apply command' in output) or \
('original configuration has been successfully restored' in output):
raise ReplaceConfigException("Candidate config could not be applied")
elif '%Please turn config archive on' in output:
msg = "napalm-ios replace() requires Cisco 'archive' feature to be enabled."
raise ReplaceConfigException(msg)
else:
# Merge operation
filename = self.merge_cfg
Expand Down Expand Up @@ -575,7 +579,27 @@ def get_lldp_neighbors(self):

for lldp_entry in split_output.splitlines():
# Example, twb-sf-hpsw1 Fa4 120 B 17
device_id, local_int_brief, hold_time, capability, remote_port = lldp_entry.split()
try:
device_id, local_int_brief, hold_time, capability, remote_port = lldp_entry.split()
except ValueError:
if len(lldp_entry.split()) == 4:
# Four fields might be long_name or missing capability
capability_missing = True if lldp_entry[46] == ' ' else False
if capability_missing:
device_id, local_int_brief, hold_time, remote_port = lldp_entry.split()
else:
# Might be long_name issue
tmp_field, hold_time, capability, remote_port = lldp_entry.split()
device_id = tmp_field[:20]
local_int_brief = tmp_field[20:]
# device_id might be abbreviated, try to get full name
lldp_tmp = self._lldp_detail_parser(local_int_brief)
device_id_new = lldp_tmp[3][0]
# Verify abbreviated and full name are consistent
if device_id_new[:20] == device_id:
device_id = device_id_new
else:
raise ValueError("Unable to obtain remote device name")
local_port = self._expand_interface_name(local_int_brief)

entry = {'port': remote_port, 'hostname': device_id}
Expand All @@ -584,6 +608,26 @@ def get_lldp_neighbors(self):

return lldp

def _lldp_detail_parser(self, interface):
command = "show lldp neighbors {} detail".format(interface)
output = self._send_command(command)

# Check if router supports the command
if '% Invalid input' in output:
raise ValueError("Command not supported by network device")

port_id = re.findall(r"Port id:\s+(.+)", output)
port_description = re.findall(r"Port Description(?:\s\-|:)\s+(.+)", output)
chassis_id = re.findall(r"Chassis id:\s+(.+)", output)
system_name = re.findall(r"System Name:\s+(.+)", output)
system_description = re.findall(r"System Description:\s*\n(.+)", output)
system_capabilities = re.findall(r"System Capabilities:\s+(.+)", output)
enabled_capabilities = re.findall(r"Enabled Capabilities:\s+(.+)", output)
remote_address = re.findall(r"Management Addresses:\n\s+(?:IP|Other)(?::\s+?)(.+)",
output)
return [port_id, port_description, chassis_id, system_name, system_description,
system_capabilities, enabled_capabilities, remote_address]

def get_lldp_neighbors_detail(self, interface=''):
"""
IOS implementation of get_lldp_neighbors_detail.
Expand All @@ -602,26 +646,9 @@ def get_lldp_neighbors_detail(self, interface=''):
lldp_neighbors = {}

for interface in lldp_neighbors:
command = "show lldp neighbors {} detail".format(interface)
output = self._send_command(command)

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

local_port = interface
port_id = re.findall(r"Port id:\s+(.+)", output)
port_description = re.findall(r"Port Description(?:\s\-|:)\s+(.+)", output)
chassis_id = re.findall(r"Chassis id:\s+(.+)", output)
system_name = re.findall(r"System Name:\s+(.+)", output)
system_description = re.findall(r"System Description:\s*\n(.+)", output)
system_capabilities = re.findall(r"System Capabilities:\s+(.+)", output)
enabled_capabilities = re.findall(r"Enabled Capabilities:\s+(.+)", output)
remote_address = re.findall(r"Management Addresses:\n\s+(?:IP|Other)(?::\s+?)(.+)",
output)
number_entries = len(port_id)
lldp_fields = [port_id, port_description, chassis_id, system_name, system_description,
system_capabilities, enabled_capabilities, remote_address]
lldp_fields = self._lldp_detail_parser(interface)
number_entries = len(lldp_fields[0])

# re.findall will return a list. Make sure same number of entries always returned.
for test_list in lldp_fields:
Expand Down Expand Up @@ -847,6 +874,7 @@ def get_interfaces(self):
match_mac = re.match(mac_regex, interface_output, flags=re.DOTALL)
group_mac = match_mac.groupdict()
mac_address = group_mac["mac_address"]
mac_address = napalm_base.helpers.mac(mac_address)
interface_list[interface]['mac_address'] = py23_compat.text_type(mac_address)
except AttributeError:
interface_list[interface]['mac_address'] = u'N/A'
Expand Down Expand Up @@ -1341,7 +1369,7 @@ def get_arp_table(self):
raise ValueError("Invalid MAC Address detected: {}".format(mac))
entry = {
'interface': interface,
'mac': mac,
'mac': napalm_base.helpers.mac(mac),
'ip': address,
'age': age
}
Expand Down Expand Up @@ -1503,7 +1531,7 @@ def process_mac_fields(vlan, mac, mac_type, interface):
else:
active = False
return {
'mac': mac,
'mac': napalm_base.helpers.mac(mac),
'interface': interface,
'vlan': int(vlan),
'static': static,
Expand Down Expand Up @@ -1620,7 +1648,8 @@ def get_snmp_information(self):
snmp_dict['chassis_id'] = snmp_chassis
return snmp_dict

def ping(self, destination, source='', ttl=255, timeout=2, size=100, count=5):
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 and returns a dictionary with the result.
Expand All @@ -1640,7 +1669,11 @@ def ping(self, destination, source='', ttl=255, timeout=2, size=100, count=5):
* rtt (float)
"""
ping_dict = {}
command = 'ping {}'.format(destination)
# vrf needs to be right after the ping command
if vrf:
command = 'ping vrf {} {}'.format(vrf, destination)
else:
command = 'ping {}'.format(destination)
command += ' timeout {}'.format(timeout)
command += ' size {}'.format(size)
command += ' repeat {}'.format(count)
Expand Down Expand Up @@ -1691,7 +1724,7 @@ def ping(self, destination, source='', ttl=255, timeout=2, size=100, count=5):
return ping_dict

def traceroute(self, destination, source=C.TRACEROUTE_SOURCE,
ttl=C.TRACEROUTE_TTL, timeout=C.TRACEROUTE_TIMEOUT):
ttl=C.TRACEROUTE_TTL, timeout=C.TRACEROUTE_TIMEOUT, vrf=C.TRACEROUTE_VRF):
"""
Executes traceroute on the device and returns a dictionary with the result.
Expand All @@ -1712,7 +1745,11 @@ def traceroute(self, destination, source=C.TRACEROUTE_SOURCE,
* host_name (str)
"""

command = "traceroute {}".format(destination)
# vrf needs to be right after the traceroute command
if vrf:
command = "traceroute vrf {} {}".format(vrf, destination)
else:
command = "traceroute {}".format(destination)
if source:
command += " source {}".format(source)
if ttl:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

setup(
name="napalm-ios",
version="0.6.0",
version="0.6.1",
packages=find_packages(),
author="Kirk Byers",
author_email="[email protected]",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
[{
"interface": "Vlan20",
"ip": "172.29.50.1",
"mac": "84b8.0276.ac0e",
"mac": "84:B8:02:76:AC:0E",
"age": 8.0
}, {
"interface": "Vlan20",
"ip": "172.29.50.2",
"mac": "0019.0725.344a",
"mac": "00:19:07:25:34:4A",
"age": 221.0
}, {
"interface": "Vlan20",
"ip": "172.29.50.3",
"mac": "0024.f7dd.7741",
"mac": "00:24:F7:DD:77:41",
"age": 0.0
}, {
"interface": "Vlan20",
"ip": "172.29.50.10",
"mac": "6805.ca12.71c2",
"mac": "68:05:CA:12:71:C2",
"age": 37.0
}, {
"interface": "Vlan41",
"ip": "172.29.52.33",
"mac": "84b8.0276.ac0e",
"mac": "84:B8:02:76:AC:0E",
"age": 61.0
}, {
"interface": "Vlan41",
"ip": "172.29.52.34",
"mac": "0024.f7dd.7743",
"mac": "00:24:F7:DD:77:43",
"age": 0.0
}, {
"interface": "Vlan41",
"ip": "172.29.52.40",
"mac": "a099.9b1c.dfa7",
"mac": "A0:99:9B:1C:DF:A7",
"age": 3.0
}, {
"interface": "Vlan41",
"ip": "192.168.81.34",
"mac": "0024.f7dd.7743",
"mac": "00:24:F7:DD:77:43",
"age": 0.0
}]
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
[{
"interface": "",
"ip": "172.29.50.1",
"mac": "84b8.0276.ac0e",
"mac": "84:B8:02:76:AC:0E",
"age": 8.0
}, {
"interface": "Vlan20",
"ip": "172.29.50.2",
"mac": "0019.0725.344a",
"mac": "00:19:07:25:34:4A",
"age": 221.0
}, {
"interface": "Vlan20",
"ip": "172.29.50.3",
"mac": "0024.f7dd.7741",
"mac": "00:24:F7:DD:77:41",
"age": 0.0
}, {
"interface": "Vlan20",
"ip": "172.29.50.10",
"mac": "6805.ca12.71c2",
"mac": "68:05:CA:12:71:C2",
"age": 37.0
}, {
"interface": "Vlan41",
"ip": "172.29.52.33",
"mac": "84b8.0276.ac0e",
"mac": "84:B8:02:76:AC:0E",
"age": 61.0
}, {
"interface": "Vlan41",
"ip": "172.29.52.34",
"mac": "0024.f7dd.7743",
"mac": "00:24:F7:DD:77:43",
"age": 0.0
}, {
"interface": "Vlan41",
"ip": "172.29.52.40",
"mac": "a099.9b1c.dfa7",
"mac": "A0:99:9B:1C:DF:A7",
"age": 3.0
}, {
"interface": "Vlan41",
"ip": "192.168.81.34",
"mac": "0024.f7dd.7743",
"mac": "00:24:F7:DD:77:43",
"age": 0.0
}]
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{
"GigabitEthernet3": {
"speed": 1000,
"mac_address": "0800.2782.516b",
"mac_address": "08:00:27:82:51:6B",
"is_up": false,
"last_flapped": -1.0,
"description": "N/A",
"is_enabled": false
},
"GigabitEthernet2": {
"speed": 1000,
"mac_address": "0800.2779.e896",
"mac_address": "08:00:27:79:E8:96",
"is_up": true,
"last_flapped": -1.0,
"description": "blah bleh",
"is_enabled": true
},
"GigabitEthernet1": {
"speed": 1000,
"mac_address": "0800.27f8.e842",
"mac_address": "08:00:27:F8:E8:42",
"is_up": true,
"last_flapped": -1.0,
"description": "N/A",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"GigabitEthernet1": [{
"port": "17",
"hostname": "twb-sf-hpsw1.local.domain"
}],
"GigabitEthernet2": [{
"port": "18",
"hostname": "twb-sf-hpsw2"
}]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
GigabitEthernet1 is up, line protocol is up
Hardware is CSR vNIC, address is 0800.27f8.e842 (bia 0800.27f8.e842)
Internet address is 10.0.2.15/24
MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec,
reliability 255/255, txload 1/255, rxload 1/255
Encapsulation ARPA, loopback not set
Keepalive set (10 sec)
Full Duplex, 1000Mbps, link type is auto, media type is RJ45
output flow-control is unsupported, input flow-control is unsupported
ARP type: ARPA, ARP Timeout 04:00:00
Last input 00:42:01, output 00:00:05, output hang never
Last clearing of "show interface" counters never
Input queue: 0/375/0/0 (size/max/drops/flushes); Total output drops: 0
Queueing strategy: fifo
Output queue: 0/40 (size/max)
5 minute input rate 1000 bits/sec, 1 packets/sec
5 minute output rate 1000 bits/sec, 1 packets/sec
14028 packets input, 1766902 bytes, 0 no buffer
Received 0 broadcasts (0 IP multicasts)
0 runts, 0 giants, 0 throttles
0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored
0 watchdog, 0 multicast, 0 pause input
9446 packets output, 1379617 bytes, 0 underruns
0 output errors, 0 collisions, 0 interface resets
0 unknown protocol drops
0 babbles, 0 late collision, 0 deferred
0 lost carrier, 0 no carrier, 0 pause output
0 output buffer failures, 0 output buffers swapped out
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
GigabitEthernet2 is up, line protocol is up
Hardware is CSR vNIC, address is 0800.2779.e896 (bia 0800.2779.e896)
Description: blah bleh
Internet address is 192.168.0.1/24
MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec,
reliability 255/255, txload 1/255, rxload 1/255
Encapsulation ARPA, loopback not set
Keepalive set (10 sec)
Full Duplex, 1000Mbps, link type is auto, media type is RJ45
output flow-control is unsupported, input flow-control is unsupported
ARP type: ARPA, ARP Timeout 04:00:00
Last input 00:00:04, output 00:00:05, output hang never
Last clearing of "show interface" counters never
Input queue: 0/375/0/0 (size/max/drops/flushes); Total output drops: 0
Queueing strategy: fifo
Output queue: 0/40 (size/max)
5 minute input rate 0 bits/sec, 0 packets/sec
5 minute output rate 0 bits/sec, 0 packets/sec
118 packets input, 11502 bytes, 0 no buffer
Received 0 broadcasts (0 IP multicasts)
0 runts, 0 giants, 0 throttles
0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored
0 watchdog, 0 multicast, 0 pause input
177 packets output, 19267 bytes, 0 underruns
0 output errors, 0 collisions, 1 interface resets
0 unknown protocol drops
0 babbles, 0 late collision, 0 deferred
0 lost carrier, 0 no carrier, 0 pause output
0 output buffer failures, 0 output buffers swapped out

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Capability codes:
(R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device
(W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other

Device ID Local Intf Hold-time Capability Port ID
twb-sf-hpsw1.local.dGi1 120 B 17
twb-sf-hpsw2 Gi2 120 B 18

Total entries displayed: 2
Loading

0 comments on commit 2982aec

Please sign in to comment.