From 67db8a0a7a1d32d3b82be14dc6d8130454eee72f Mon Sep 17 00:00:00 2001 From: David Barroso Date: Wed, 5 Apr 2017 10:10:24 +0200 Subject: [PATCH 1/7] Making napalm-eos ready for napalm-yang (#156) * Added profile * Removing unnecessary stuff * Ignore ctags file --- .coveragerc | 2 -- .gitignore | 2 ++ napalm_eos/eos.py | 2 ++ napalm_eos/oc_templates/openconfig_bgp.j2 | 41 ----------------------- 4 files changed, 4 insertions(+), 43 deletions(-) delete mode 100644 .coveragerc delete mode 100644 napalm_eos/oc_templates/openconfig_bgp.j2 diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 858dc71..0000000 --- a/.coveragerc +++ /dev/null @@ -1,2 +0,0 @@ -[report] -omit = napalm_base/openconfig_bindings/* diff --git a/.gitignore b/.gitignore index 60cd474..a72517b 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,5 @@ report.json test/unit/TestEOSDriverKB2.py test/unit/eos/cleanup.sh test/unit/eos/prep_test.sh + +tags diff --git a/napalm_eos/eos.py b/napalm_eos/eos.py index c726900..16d932c 100644 --- a/napalm_eos/eos.py +++ b/napalm_eos/eos.py @@ -85,6 +85,8 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.enablepwd = optional_args.get('enable_password', '') + self.profile = ["eos"] + def open(self): """Implementation of NAPALM method open.""" try: diff --git a/napalm_eos/oc_templates/openconfig_bgp.j2 b/napalm_eos/oc_templates/openconfig_bgp.j2 deleted file mode 100644 index ba1a998..0000000 --- a/napalm_eos/oc_templates/openconfig_bgp.j2 +++ /dev/null @@ -1,41 +0,0 @@ -no router bgp -router bgp {{ template_vars.bgp.global_.config.as_ }} - - {% if template_vars.bgp.global_.graceful_restart.config.enabled %} - bgp graceful-restart - bgp graceful-restart restart-time {{ template_vars.bgp.global_.graceful_restart.config.restart_time }} - bgp graceful-restart stalepath-time {{ template_vars.bgp.global_.graceful_restart.config.stale_routes_time|int }} - {% endif %} - - {% for name,afi_safi in template_vars.bgp.global_.afi_safis.afi_safi.iteritems() %} - {% if afi_safi.config.enabled %} - address-family {{ afi_safi.config.afi_safi_name|openconfig_to_eos_af }} - {% endif %} - {% if afi_safi.use_multiple_paths.ebgp.config.maximum_paths %} - maximum-paths {{ afi_safi.use_multiple_paths.ebgp.config.maximum_paths }} - {% endif %} - {% if afi_safi.use_multiple_paths.ibgp.config.maximum_paths %} - maximum-paths ibgp {{ afi_safi.use_multiple_paths.ibgp.config.maximum_paths }} - {% endif %} - {% endfor %} - - {% for address,neighbor in template_vars.bgp.neighbors.neighbor.iteritems() %} - {% if not neighbor.config.description|oc_attr_isdefault %} - neighbor {{ neighbor.config.neighbor_address }} description {{ neighbor.config.description }} - {% endif %} - {% if not neighbor.config.peer_as|oc_attr_isdefault %} - neighbor {{ neighbor.config.neighbor_address }} remote-as {{ neighbor.config.peer_as }} - {% endif %} - {% if neighbor.ebgp_multihop.enabled %} - neighbor {{ neighbor.config.neighbor_address }} ebgp-multihop {{ neighbor.ebgp_multihop.multihop_ttl }} - {% endif %} - - {% for afi,af in neighbor.afi_safis.afi_safi.iteritems() %} - {% if af.config.enabled %} - address-family {{ afi|openconfig_to_eos_af }} - neighbor {{ neighbor.config.neighbor_address }} activate - {% endif %} - {% endfor %} - {% endfor %} - -exit From 1f22af2d14de3bdf2f371ea94618c60ce4cca098 Mon Sep 17 00:00:00 2001 From: Ken Celenza Date: Sun, 30 Apr 2017 06:36:03 -0400 Subject: [PATCH 2/7] Remove comma (#159) Was unsure how some of this was working, (e.g. $Interfaces vs ${Interfaces} ) and see that the comma was left in. This PR is not ready to go in, just wanted to see if it made sense before adjusting the getter --- napalm_eos/utils/textfsm_templates/vrf.tpl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/napalm_eos/utils/textfsm_templates/vrf.tpl b/napalm_eos/utils/textfsm_templates/vrf.tpl index 110b992..5a12905 100644 --- a/napalm_eos/utils/textfsm_templates/vrf.tpl +++ b/napalm_eos/utils/textfsm_templates/vrf.tpl @@ -1,12 +1,17 @@ Value Required Name (\S+) Value Route_Distinguisher (\d+:\d+|) -Value List Interfaces (\S.+) +Value List Interfaces (.+?) Start ^\s\S+\s+(\d|<) -> Continue.Record - ^\s+${Name}\s+${Route_Distinguisher}\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+$Interfaces - ^\s+${Name}\s+${Route_Distinguisher}\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?), - ^\s+v6:(incomplete|(no )?routing)\s+$Interfaces - ^\s+v6:(incomplete|(no )?routing) -> Record - ^\s+$Interfaces + ^\s+${Name}\s+${Route_Distinguisher}\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+${Interfaces}(?:,|\s|$$) -> Continue + ^\s+\S+\s+(?:\d+:\d+|)\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+(.+?),\s${Interfaces}(\s|,|$$) -> Continue + ^\s+\S+\s+(?:\d+:\d+|)\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+(.+?),\s(.+?),\s${Interfaces}(\s|,|$$) -> Continue + ^\s+${Name}\s+${Route_Distinguisher}\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?), -> Continue + ^\s{33,37}v6:(incomplete|(no )?routing)\s+${Interfaces}(?:\s|,|$$) -> Continue + ^\s{33,37}v6:(incomplete|(no )?routing)\s+(.+?),\s+${Interfaces}(?:\s|,|$$) -> Continue + ^\s{33,37}v6:(incomplete|(no )?routing)\s+(.+?),\s+(.+?),\s+${Interfaces}(?:\s|,|$$) -> Continue + ^\s{58,62}\s+${Interfaces}(?:\s|,|$$) -> Continue + ^\s{58,62}\s+.+?,${Interfaces}(?:\s|,|$$) -> Continue + ^\s{58,62}\s+.+?,.+?,${Interfaces}(?:\s|,|$$) -> Continue From 8b85ba27019f16cc8e4203031d8cdb7cfb84de14 Mon Sep 17 00:00:00 2001 From: bewing Date: Sun, 30 Apr 2017 05:37:10 -0500 Subject: [PATCH 3/7] Fix #160 (#161) * Fix #160 * Fix #162 Add tests for DNS hostnames and a case for truncated output with DNS hostnames * Fix parsing unreach with/without dns and test --- napalm_eos/eos.py | 29 +++++++++++++++++-- .../test_ping/dns/expected_result.json | 2 ++ ...g_8_8_8_8_timeout_2_size_100_repeat_5.text | 10 +++++++ .../dns_truncated/expected_result.json | 1 + ...g_8_8_8_8_timeout_2_size_100_repeat_5.text | 10 +++++++ .../dns_unreach/expected_result.json | 1 + ...g_8_8_8_8_timeout_2_size_100_repeat_5.text | 10 +++++++ .../test_ping/normal/expected_result.json | 2 +- .../test_ping/truncated/expected_result.json | 1 + ...g_8_8_8_8_timeout_2_size_100_repeat_5.text | 10 +++++++ .../test_ping/unreach/expected_result.json | 1 + ...g_8_8_8_8_timeout_2_size_100_repeat_5.text | 10 +++++++ 12 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 test/unit/mocked_data/test_ping/dns/expected_result.json create mode 100644 test/unit/mocked_data/test_ping/dns/ping_8_8_8_8_timeout_2_size_100_repeat_5.text create mode 100644 test/unit/mocked_data/test_ping/dns_truncated/expected_result.json create mode 100644 test/unit/mocked_data/test_ping/dns_truncated/ping_8_8_8_8_timeout_2_size_100_repeat_5.text create mode 100644 test/unit/mocked_data/test_ping/dns_unreach/expected_result.json create mode 100644 test/unit/mocked_data/test_ping/dns_unreach/ping_8_8_8_8_timeout_2_size_100_repeat_5.text create mode 100644 test/unit/mocked_data/test_ping/truncated/expected_result.json create mode 100644 test/unit/mocked_data/test_ping/truncated/ping_8_8_8_8_timeout_2_size_100_repeat_5.text create mode 100644 test/unit/mocked_data/test_ping/unreach/expected_result.json create mode 100644 test/unit/mocked_data/test_ping/unreach/ping_8_8_8_8_timeout_2_size_100_repeat_5.text diff --git a/napalm_eos/eos.py b/napalm_eos/eos.py index 16d932c..f197fb2 100644 --- a/napalm_eos/eos.py +++ b/napalm_eos/eos.py @@ -1679,11 +1679,34 @@ def ping(self, destination, source=c.PING_SOURCE, ttl=c.PING_TTL, timeout=c.PING fields = line.split() if 'icmp' in line: if 'Unreachable' in line: - results_array.append({'ip_address': py23_compat.text_type(fields[1]), - 'rtt': 0.0}) + if "(" in fields[2]: + results_array.append( + { + 'ip_address': py23_compat.text_type(fields[2][1:-1]), + 'rtt': 0.0, + } + ) + else: + results_array.append({'ip_address': py23_compat.text_type(fields[1]), + 'rtt': 0.0}) + elif 'truncated' in line: + if "(" in fields[4]: + results_array.append( + { + 'ip_address': py23_compat.text_type(fields[4][1:-2]), + 'rtt': 0.0, + } + ) + else: + results_array.append( + { + 'ip_address': py23_compat.text_type(fields[3][:-1]), + 'rtt': 0.0, + } + ) elif fields[1] == 'bytes': m = fields[6][5:] - results_array.append({'ip_address': py23_compat.text_type(fields[3]), + results_array.append({'ip_address': py23_compat.text_type(fields[3][:-1]), 'rtt': float(m)}) elif 'packets transmitted' in line: ping_dict['success']['probes_sent'] = int(fields[0]) diff --git a/test/unit/mocked_data/test_ping/dns/expected_result.json b/test/unit/mocked_data/test_ping/dns/expected_result.json new file mode 100644 index 0000000..794fda8 --- /dev/null +++ b/test/unit/mocked_data/test_ping/dns/expected_result.json @@ -0,0 +1,2 @@ +{"success": {"packet_loss": 0, "rtt_stddev": 0.562, "rtt_min": 1.321, "results": [{"rtt": 1.78, "ip_address": "151.101.65.140"}, {"rtt": 1.41, "ip_address": "151.101.65.140"}, {"rtt": 1.32, "ip_address": "151.101.65.140"}, {"rtt": 2.84, "ip_address": "151.101.65.140"}, {"rtt": 1.44, "ip_address": "151.101.65.140"}], "rtt_avg": 1.760, "rtt_max": 2.840, "probes_sent": 5}} + diff --git a/test/unit/mocked_data/test_ping/dns/ping_8_8_8_8_timeout_2_size_100_repeat_5.text b/test/unit/mocked_data/test_ping/dns/ping_8_8_8_8_timeout_2_size_100_repeat_5.text new file mode 100644 index 0000000..8c1bc4c --- /dev/null +++ b/test/unit/mocked_data/test_ping/dns/ping_8_8_8_8_timeout_2_size_100_repeat_5.text @@ -0,0 +1,10 @@ +PING reddit.map.fastly.net (151.101.65.140) 72(100) bytes of data. +80 bytes from 151.101.65.140: icmp_seq=1 ttl=57 time=1.78 ms +80 bytes from 151.101.65.140: icmp_seq=2 ttl=57 time=1.41 ms +80 bytes from 151.101.65.140: icmp_seq=3 ttl=57 time=1.32 ms +80 bytes from 151.101.65.140: icmp_seq=4 ttl=57 time=2.84 ms +80 bytes from 151.101.65.140: icmp_seq=5 ttl=57 time=1.44 ms + +--- reddit.map.fastly.net ping statistics --- +5 packets transmitted, 5 received, 0% packet loss, time 9ms +rtt min/avg/max/mdev = 1.321/1.760/2.840/0.562 ms, ipg/ewma 2.434/1.779 ms diff --git a/test/unit/mocked_data/test_ping/dns_truncated/expected_result.json b/test/unit/mocked_data/test_ping/dns_truncated/expected_result.json new file mode 100644 index 0000000..7691760 --- /dev/null +++ b/test/unit/mocked_data/test_ping/dns_truncated/expected_result.json @@ -0,0 +1 @@ +{"success": {"packet_loss": 0, "rtt_stddev": 0.252, "rtt_min": 0.746, "results": [{"rtt": 0.0, "ip_address": "172.217.9.68"}, {"rtt": 0.0, "ip_address": "172.217.9.68"}, {"rtt": 0.0, "ip_address": "172.217.9.68"}, {"rtt": 0.0, "ip_address": "172.217.9.68"}, {"rtt": 0.0, "ip_address": "172.217.9.68"}], "rtt_avg": 1.170, "rtt_max": 1.466, "probes_sent": 5}} diff --git a/test/unit/mocked_data/test_ping/dns_truncated/ping_8_8_8_8_timeout_2_size_100_repeat_5.text b/test/unit/mocked_data/test_ping/dns_truncated/ping_8_8_8_8_timeout_2_size_100_repeat_5.text new file mode 100644 index 0000000..cfb6f54 --- /dev/null +++ b/test/unit/mocked_data/test_ping/dns_truncated/ping_8_8_8_8_timeout_2_size_100_repeat_5.text @@ -0,0 +1,10 @@ +PING www.google.com (172.217.9.68) 72(100) bytes of data. +72 bytes from ord38s09-in-f4.1e100.net (172.217.9.68): icmp_seq=1 ttl=52 (truncated) +72 bytes from ord38s09-in-f4.1e100.net (172.217.9.68): icmp_seq=2 ttl=52 (truncated) +72 bytes from ord38s09-in-f4.1e100.net (172.217.9.68): icmp_seq=3 ttl=52 (truncated) +72 bytes from ord38s09-in-f4.1e100.net (172.217.9.68): icmp_seq=4 ttl=52 (truncated) +72 bytes from ord38s09-in-f4.1e100.net (172.217.9.68): icmp_seq=5 ttl=52 (truncated) + +--- www.google.com ping statistics --- +5 packets transmitted, 5 received, 0% packet loss, time 7ms +rtt min/avg/max/mdev = 0.746/1.170/1.466/0.252 ms, ipg/ewma 1.750/1.306 ms diff --git a/test/unit/mocked_data/test_ping/dns_unreach/expected_result.json b/test/unit/mocked_data/test_ping/dns_unreach/expected_result.json new file mode 100644 index 0000000..32ad721 --- /dev/null +++ b/test/unit/mocked_data/test_ping/dns_unreach/expected_result.json @@ -0,0 +1 @@ +{"success": {"packet_loss": 5, "rtt_stddev": 0.0, "rtt_min": 0.0, "results": [{"rtt": 0.0, "ip_address": "10.213.1.254"}, {"rtt": 0.0, "ip_address": "10.213.1.254"}, {"rtt": 0.0, "ip_address": "10.213.1.254"}, {"rtt": 0.0, "ip_address": "10.213.1.254"}, {"rtt": 0.0, "ip_address": "10.213.1.254"}], "rtt_avg": 0.0, "rtt_max": 0.0, "probes_sent": 5}} diff --git a/test/unit/mocked_data/test_ping/dns_unreach/ping_8_8_8_8_timeout_2_size_100_repeat_5.text b/test/unit/mocked_data/test_ping/dns_unreach/ping_8_8_8_8_timeout_2_size_100_repeat_5.text new file mode 100644 index 0000000..6578233 --- /dev/null +++ b/test/unit/mocked_data/test_ping/dns_unreach/ping_8_8_8_8_timeout_2_size_100_repeat_5.text @@ -0,0 +1,10 @@ +PING bad.localdomain (10.213.1.102) 72(100) bytes of data. +From localhost.localdomain (10.213.1.254) icmp_seq=1 Destination Host Unreachable +From localhost.localdomain (10.213.1.254) icmp_seq=2 Destination Host Unreachable +From localhost.localdomain (10.213.1.254) icmp_seq=3 Destination Host Unreachable +From localhost.localdomain (10.213.1.254) icmp_seq=4 Destination Host Unreachable +From localhost.localdomain (10.213.1.254) icmp_seq=5 Destination Host Unreachable + +--- bad.localdomain ping statistics --- +5 packets transmitted, 0 received, +5 errors, 100% packet loss, time 4002ms +pipe 3 diff --git a/test/unit/mocked_data/test_ping/normal/expected_result.json b/test/unit/mocked_data/test_ping/normal/expected_result.json index cc2214f..e29c0ab 100644 --- a/test/unit/mocked_data/test_ping/normal/expected_result.json +++ b/test/unit/mocked_data/test_ping/normal/expected_result.json @@ -1,2 +1,2 @@ -{"success": {"packet_loss": 0, "rtt_stddev": 0.797, "rtt_min": 0.579, "results": [{"rtt": 0.579, "ip_address": "10.1.1.1:"}, {"rtt": 2.79, "ip_address": "10.1.1.1:"}, {"rtt": 0.984, "ip_address": "10.1.1.1:"}, {"rtt": 0.952, "ip_address": "10.1.1.1:"}, {"rtt": 0.833, "ip_address": "10.1.1.1:"}], "rtt_avg": 1.228, "rtt_max": 2.796, "probes_sent": 5}} +{"success": {"packet_loss": 0, "rtt_stddev": 0.797, "rtt_min": 0.579, "results": [{"rtt": 0.579, "ip_address": "10.1.1.1"}, {"rtt": 2.79, "ip_address": "10.1.1.1"}, {"rtt": 0.984, "ip_address": "10.1.1.1"}, {"rtt": 0.952, "ip_address": "10.1.1.1"}, {"rtt": 0.833, "ip_address": "10.1.1.1"}], "rtt_avg": 1.228, "rtt_max": 2.796, "probes_sent": 5}} diff --git a/test/unit/mocked_data/test_ping/truncated/expected_result.json b/test/unit/mocked_data/test_ping/truncated/expected_result.json new file mode 100644 index 0000000..c6ea523 --- /dev/null +++ b/test/unit/mocked_data/test_ping/truncated/expected_result.json @@ -0,0 +1 @@ +{"success": {"packet_loss": 0, "rtt_stddev": 0.181, "rtt_min": 10.999, "results": [{"rtt": 0.0, "ip_address": "8.8.8.8"}, {"rtt": 0.0, "ip_address": "8.8.8.8"}, {"rtt": 0.0, "ip_address": "8.8.8.8"}, {"rtt": 0.0, "ip_address": "8.8.8.8"}, {"rtt": 0.0, "ip_address": "8.8.8.8"}], "rtt_avg": 11.174, "rtt_max": 11.445, "probes_sent": 5}} diff --git a/test/unit/mocked_data/test_ping/truncated/ping_8_8_8_8_timeout_2_size_100_repeat_5.text b/test/unit/mocked_data/test_ping/truncated/ping_8_8_8_8_timeout_2_size_100_repeat_5.text new file mode 100644 index 0000000..1f53b54 --- /dev/null +++ b/test/unit/mocked_data/test_ping/truncated/ping_8_8_8_8_timeout_2_size_100_repeat_5.text @@ -0,0 +1,10 @@ +PING 8.8.8.8 (8.8.8.8) 72(100) bytes of data. +72 bytes from 8.8.8.8: icmp_seq=1 ttl=43 (truncated) +72 bytes from 8.8.8.8: icmp_seq=2 ttl=43 (truncated) +72 bytes from 8.8.8.8: icmp_seq=3 ttl=43 (truncated) +72 bytes from 8.8.8.8: icmp_seq=4 ttl=43 (truncated) +72 bytes from 8.8.8.8: icmp_seq=5 ttl=43 (truncated) + +--- 8.8.8.8 ping statistics --- +5 packets transmitted, 5 received, 0% packet loss, time 45ms +rtt min/avg/max/mdev = 10.999/11.174/11.445/0.181 ms, ipg/ewma 11.312/11.300 ms diff --git a/test/unit/mocked_data/test_ping/unreach/expected_result.json b/test/unit/mocked_data/test_ping/unreach/expected_result.json new file mode 100644 index 0000000..968deb6 --- /dev/null +++ b/test/unit/mocked_data/test_ping/unreach/expected_result.json @@ -0,0 +1 @@ +{"success": {"packet_loss": 5, "rtt_stddev": 0.0, "rtt_min": 0.0, "results": [{"rtt": 0.0, "ip_address": "10.0.2.15"}, {"rtt": 0.0, "ip_address": "10.0.2.15"}, {"rtt": 0.0, "ip_address": "10.0.2.15"}, {"rtt": 0.0, "ip_address": "10.0.2.15"}, {"rtt": 0.0, "ip_address": "10.0.2.15"}], "rtt_avg": 0.0, "rtt_max": 0.0, "probes_sent": 5}} diff --git a/test/unit/mocked_data/test_ping/unreach/ping_8_8_8_8_timeout_2_size_100_repeat_5.text b/test/unit/mocked_data/test_ping/unreach/ping_8_8_8_8_timeout_2_size_100_repeat_5.text new file mode 100644 index 0000000..0f0ec66 --- /dev/null +++ b/test/unit/mocked_data/test_ping/unreach/ping_8_8_8_8_timeout_2_size_100_repeat_5.text @@ -0,0 +1,10 @@ +PING 10.0.2.17 (10.0.2.17) 72(100) bytes of data. +From 10.0.2.15 icmp_seq=1 Destination Host Unreachable +From 10.0.2.15 icmp_seq=2 Destination Host Unreachable +From 10.0.2.15 icmp_seq=3 Destination Host Unreachable +From 10.0.2.15 icmp_seq=4 Destination Host Unreachable +From 10.0.2.15 icmp_seq=5 Destination Host Unreachable + +--- 10.0.2.17 ping statistics --- +5 packets transmitted, 0 received, +5 errors, 100% packet loss, time 4003ms +pipe 3 From 135bdd3c20be5929424ede16415e0867b586fa12 Mon Sep 17 00:00:00 2001 From: bewing Date: Mon, 26 Jun 2017 02:38:47 -0500 Subject: [PATCH 4/7] Update vrf textfsm template (#166) * Update vrf textfsm template * Revert network instance test case * Add test case for 7150 VRF --- napalm_eos/utils/textfsm_templates/vrf.tpl | 8 +- .../missing_v6/expected_result.json | 1 + .../missing_v6/show_ip_interface.json | 279 ++++++++++++++++++ .../missing_v6/show_ipv6_interface.json | 6 + .../missing_v6/show_vrf.text | 14 + 5 files changed, 304 insertions(+), 4 deletions(-) create mode 100644 test/unit/mocked_data/test_get_network_instances/missing_v6/expected_result.json create mode 100644 test/unit/mocked_data/test_get_network_instances/missing_v6/show_ip_interface.json create mode 100644 test/unit/mocked_data/test_get_network_instances/missing_v6/show_ipv6_interface.json create mode 100644 test/unit/mocked_data/test_get_network_instances/missing_v6/show_vrf.text diff --git a/napalm_eos/utils/textfsm_templates/vrf.tpl b/napalm_eos/utils/textfsm_templates/vrf.tpl index 5a12905..8d6a532 100644 --- a/napalm_eos/utils/textfsm_templates/vrf.tpl +++ b/napalm_eos/utils/textfsm_templates/vrf.tpl @@ -5,10 +5,10 @@ Value List Interfaces (.+?) Start ^\s\S+\s+(\d|<) -> Continue.Record - ^\s+${Name}\s+${Route_Distinguisher}\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+${Interfaces}(?:,|\s|$$) -> Continue - ^\s+\S+\s+(?:\d+:\d+|)\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+(.+?),\s${Interfaces}(\s|,|$$) -> Continue - ^\s+\S+\s+(?:\d+:\d+|)\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+(.+?),\s(.+?),\s${Interfaces}(\s|,|$$) -> Continue - ^\s+${Name}\s+${Route_Distinguisher}\s+(ipv4,ipv6\s+)?v4:(incomplete|(no )?routing(; multicast)?), -> Continue + ^\s+${Name}\s+${Route_Distinguisher}\s+(ipv4(,ipv6)?\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+${Interfaces}(?:,|\s|$$) -> Continue + ^\s+\S+\s+(?:\d+:\d+|)\s+(ipv4(,ipv6)?\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+(.+?),\s${Interfaces}(\s|,|$$) -> Continue + ^\s+\S+\s+(?:\d+:\d+|)\s+(ipv4(,ipv6)?\s+)?v4:(incomplete|(no )?routing(; multicast)?),\s+(.+?),\s(.+?),\s${Interfaces}(\s|,|$$) -> Continue + ^\s+${Name}\s+${Route_Distinguisher}\s+(ipv4(,ipv6)?\s+)?v4:(incomplete|(no )?routing(; multicast)?), -> Continue ^\s{33,37}v6:(incomplete|(no )?routing)\s+${Interfaces}(?:\s|,|$$) -> Continue ^\s{33,37}v6:(incomplete|(no )?routing)\s+(.+?),\s+${Interfaces}(?:\s|,|$$) -> Continue ^\s{33,37}v6:(incomplete|(no )?routing)\s+(.+?),\s+(.+?),\s+${Interfaces}(?:\s|,|$$) -> Continue diff --git a/test/unit/mocked_data/test_get_network_instances/missing_v6/expected_result.json b/test/unit/mocked_data/test_get_network_instances/missing_v6/expected_result.json new file mode 100644 index 0000000..14e3657 --- /dev/null +++ b/test/unit/mocked_data/test_get_network_instances/missing_v6/expected_result.json @@ -0,0 +1 @@ +{"TEST": {"interfaces": {"interface": {"Ethernet1": {}, "Vlan103": {}, "Vlan102": {}, "Vlan101": {}, "Vlan100": {}, "Vlan104": {}}}, "state": {"route_distinguisher": "0:1"}, "type": "L3VRF", "name": "TEST"}, "default": {"interfaces": {"interface": {"Management1": {}, "Ethernet3": {}}}, "state": {"route_distinguisher": ""}, "type": "DEFAULT_INSTANCE", "name": "default"}, "NON": {"interfaces": {"interface": {}}, "state": {"route_distinguisher": ""}, "type": "L3VRF", "name": "NON"}, "TEST2": {"interfaces": {"interface": {}}, "state": {"route_distinguisher": "1234:4321"}, "type": "L3VRF", "name": "TEST2"}, "MGMT": {"interfaces": {"interface": {"Vlan2": {}, "Vlan3": {}, "Vlan4": {}}}, "state": {"route_distinguisher": "0:0"}, "type": "L3VRF", "name": "MGMT"}} diff --git a/test/unit/mocked_data/test_get_network_instances/missing_v6/show_ip_interface.json b/test/unit/mocked_data/test_get_network_instances/missing_v6/show_ip_interface.json new file mode 100644 index 0000000..a697ecf --- /dev/null +++ b/test/unit/mocked_data/test_get_network_instances/missing_v6/show_ip_interface.json @@ -0,0 +1,279 @@ +{ + "interfaces": { + "Management1": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 23, + "address": "10.192.100.98" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Management1", + "urpf": "disable", + "interfaceStatus": "connected", + "enabled": true, + "mtu": 1500, + "vrf": "default", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "up", + "description": "" + }, + "Vlan3": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Vlan3", + "urpf": "disable", + "interfaceStatus": "notconnect", + "enabled": true, + "mtu": 1478, + "vrf": "MGMT", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "lowerLayerDown", + "description": "" + }, + "Ethernet3": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Ethernet3", + "urpf": "disable", + "interfaceStatus": "connected", + "enabled": true, + "mtu": 1500, + "vrf": "default", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "up", + "description": "" + }, + "Ethernet1": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Ethernet1", + "urpf": "disable", + "interfaceStatus": "connected", + "enabled": true, + "mtu": 1500, + "vrf": "TEST", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "up", + "description": "" + }, + "Vlan103": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Vlan103", + "urpf": "disable", + "interfaceStatus": "notconnect", + "enabled": true, + "mtu": 1478, + "vrf": "TEST", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "lowerLayerDown", + "description": "" + }, + "Vlan102": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Vlan102", + "urpf": "disable", + "interfaceStatus": "notconnect", + "enabled": true, + "mtu": 1478, + "vrf": "TEST", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "lowerLayerDown", + "description": "" + }, + "Vlan2": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Vlan2", + "urpf": "disable", + "interfaceStatus": "notconnect", + "enabled": true, + "mtu": 1478, + "vrf": "MGMT", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "lowerLayerDown", + "description": "" + }, + "Vlan100": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Vlan100", + "urpf": "disable", + "interfaceStatus": "notconnect", + "enabled": true, + "mtu": 1478, + "vrf": "TEST", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "lowerLayerDown", + "description": "" + }, + "Vlan4": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Vlan4", + "urpf": "disable", + "interfaceStatus": "notconnect", + "enabled": true, + "mtu": 1478, + "vrf": "MGMT", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "lowerLayerDown", + "description": "" + }, + "Vlan101": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Vlan101", + "urpf": "disable", + "interfaceStatus": "notconnect", + "enabled": true, + "mtu": 1478, + "vrf": "TEST", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "lowerLayerDown", + "description": "" + }, + "Vlan104": { + "interfaceAddress": { + "secondaryIpsOrderedList": [], + "broadcastAddress": "255.255.255.255", + "secondaryIps": {}, + "primaryIp": { + "maskLen": 0, + "address": "0.0.0.0" + }, + "virtualIp": { + "maskLen": 0, + "address": "0.0.0.0" + } + }, + "name": "Vlan104", + "urpf": "disable", + "interfaceStatus": "notconnect", + "enabled": true, + "mtu": 1478, + "vrf": "TEST", + "localProxyArp": false, + "proxyArp": false, + "lineProtocolStatus": "lowerLayerDown", + "description": "" + } + } +} diff --git a/test/unit/mocked_data/test_get_network_instances/missing_v6/show_ipv6_interface.json b/test/unit/mocked_data/test_get_network_instances/missing_v6/show_ipv6_interface.json new file mode 100644 index 0000000..5822560 --- /dev/null +++ b/test/unit/mocked_data/test_get_network_instances/missing_v6/show_ipv6_interface.json @@ -0,0 +1,6 @@ +{ + "interfaces": {}, + "errors": [ + "No IPv6 configured interfaces" + ] +} diff --git a/test/unit/mocked_data/test_get_network_instances/missing_v6/show_vrf.text b/test/unit/mocked_data/test_get_network_instances/missing_v6/show_vrf.text new file mode 100644 index 0000000..ff52fbb --- /dev/null +++ b/test/unit/mocked_data/test_get_network_instances/missing_v6/show_vrf.text @@ -0,0 +1,14 @@ +Maximum number of vrfs allowed: 14 + Vrf RD Protocols State Interfaces +------- ------------ ------------ ------------------------- ------------------- + MGMT 0:0 ipv4 v4:routing, Vlan2, Vlan3, Vlan4 + v6:no routing + + NON v4:incomplete, + v6:incomplete + + TEST 0:1 ipv4 v4:routing; multicast, Ethernet1, Vlan100, + v6:no routing Vlan101, Vlan102, + Vlan103, Vlan104 + TEST2 1234:4321 ipv4 v4:no routing, + v6:routing From 901382d5a219b3c7da2f29f58b24d87a5d60ee76 Mon Sep 17 00:00:00 2001 From: bewing Date: Mon, 26 Jun 2017 02:40:24 -0500 Subject: [PATCH 5/7] Fix #168 (#169) * Fixes #168 * Add unit test --- napalm_eos/eos.py | 6 +++++- .../test_get_users/no_sshkey/expected_result.json | 1 + .../test_get_users/no_sshkey/show_user_account.json | 13 +++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 test/unit/mocked_data/test_get_users/no_sshkey/expected_result.json create mode 100644 test/unit/mocked_data/test_get_users/no_sshkey/show_user_account.json diff --git a/napalm_eos/eos.py b/napalm_eos/eos.py index f197fb2..c73ccf9 100644 --- a/napalm_eos/eos.py +++ b/napalm_eos/eos.py @@ -1183,10 +1183,14 @@ def _sshkey_type(sshkey): user_details.pop('username', '') sshkey_value = user_details.pop('sshAuthorizedKey', '') sshkey_type, sshkey_value = _sshkey_type(sshkey_value) + if sshkey_value != '': + sshkey_list = [sshkey_value] + else: + sshkey_list = [] user_details.update({ 'level': user_details.pop('privLevel', 0), 'password': py23_compat.text_type(user_details.pop('secret', '')), - 'sshkeys': [sshkey_value] + 'sshkeys': sshkey_list }) users[user] = user_details diff --git a/test/unit/mocked_data/test_get_users/no_sshkey/expected_result.json b/test/unit/mocked_data/test_get_users/no_sshkey/expected_result.json new file mode 100644 index 0000000..b43a07a --- /dev/null +++ b/test/unit/mocked_data/test_get_users/no_sshkey/expected_result.json @@ -0,0 +1 @@ +{"another-dummy-test": {"level": 0, "password": "", "sshkeys": []}, "dummy-test": {"password": "", "sshkeys": [], "level": 15}} diff --git a/test/unit/mocked_data/test_get_users/no_sshkey/show_user_account.json b/test/unit/mocked_data/test_get_users/no_sshkey/show_user_account.json new file mode 100644 index 0000000..66d8835 --- /dev/null +++ b/test/unit/mocked_data/test_get_users/no_sshkey/show_user_account.json @@ -0,0 +1,13 @@ +{ + "users": { + "dummy-test": { + "username": "dummy-test", + "privLevel": 15 + }, + "another-dummy-test": { + "username": "another-dummy-test", + "privLevel": 0, + "password": "$1$waUQAEpO$kSmdRL84F5sCoWKHZ8/kU1" + } + } +} From b1040c569f4679178bdcd9f811ca99b88ad2cf61 Mon Sep 17 00:00:00 2001 From: Mircea Ulinic Date: Mon, 26 Jun 2017 10:40:37 +0100 Subject: [PATCH 6/7] Version 0.6.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b8bf84f..69a03fb 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="napalm-eos", - version="0.5.6", + version="0.6.0", packages=find_packages(), author="David Barroso, Mircea Ulinic", author_email="dbarrosop@dravetech.com, mircea@cloudflare.com", From 6d63a701ae05580c85237485bb3e15eb018c769c Mon Sep 17 00:00:00 2001 From: David Barroso Date: Mon, 26 Jun 2017 13:08:04 +0200 Subject: [PATCH 7/7] Fix optional_arg name for transport (#167) --- napalm_eos/eos.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/napalm_eos/eos.py b/napalm_eos/eos.py index c73ccf9..371cec3 100644 --- a/napalm_eos/eos.py +++ b/napalm_eos/eos.py @@ -76,7 +76,8 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) if optional_args is None: optional_args = {} - self.transport = optional_args.get('eos_transport', 'https') + # eos_transport is there for backwards compatibility, transport is the preferred method + self.transport = optional_args.get('transport', optional_args.get('eos_transport', 'https')) if self.transport == 'https': self.port = optional_args.get('port', 443)