Repository: napalm-automation/napalm

Issue:
NXOS_SSH: get_interfaces_ip fails with KeyError when interface have no IP addr assigned to it.
### Description of Issue/Question
Calling get_interfaces_ip with nxos_ssh on a devices containing Interfaces without IP assigned to it, it fails with a key error.

*Note*: Please check https://guides.github.com/features/mastering-markdown/
to see how to properly format your request.

### Did you follow the steps from https://github.com/napalm-automation/napalm#faq
(Place an ``x`` between the square brackets where applicable)

- [ x] Yes
- [ ] No


### Setup

### napalm version
(Paste verbatim output from `pip freeze | grep napalm` between quotes below)

```
napalm==2.4.0
```

### Network operating system version
(Paste verbatim output from `show version` - or equivalent - between quotes below)

```
Cisco Nexus Operating System (NX-OS) Software
TAC support: http://www.cisco.com/tac
Copyright (C) 2002-2019, Cisco and/or its affiliates.
All rights reserved.
The copyrights to certain works contained in this software are
owned by other third parties and used and distributed under their own
licenses, such as open source.  This software is provided "as is," and unless
otherwise stated, there is no warranty, express or implied, including but not
limited to warranties of merchantability and fitness for a particular purpose.
Certain components of this software are licensed under
the GNU General Public License (GPL) version 2.0 or 
GNU General Public License (GPL) version 3.0  or the GNU
Lesser General Public License (LGPL) Version 2.1 or 
Lesser General Public License (LGPL) Version 2.0. 
A copy of each such license is available at
http://www.opensource.org/licenses/gpl-2.0.php and
http://opensource.org/licenses/gpl-3.0.html and
http://www.opensource.org/licenses/lgpl-2.1.php and
http://www.gnu.org/licenses/old-licenses/library.txt.

Software
  BIOS: version 07.65
  NXOS: version 7.0(3)I7(6)
  BIOS compile time:  09/04/2018
  NXOS image file is: bootflash:///nxos.7.0.3.I7.6.bin
  NXOS compile time:  3/5/2019 13:00:00 [03/05/2019 22:04:55]


Hardware
  cisco Nexus9000 C93108TC-EX chassis 
  Intel(R) Xeon(R) CPU  @ 1.80GHz with 24633600 kB of memory.
  Processor Board ID FDO21332HC8

  Device name: ams1dc1-net-f02lf17.ams1
  bootflash:   53298520 kB
Kernel uptime is 53 day(s), 21 hour(s), 14 minute(s), 55 second(s)

Last reset at 770279 usecs after Thu May 23 15:07:16 2019
  Reason: Power Down/UP epld upgrade process
  System version: 7.0(3)I7(6)
  Service: Power Down/UP epld upgrade process

plugin
  Core Plugin, Ethernet Plugin

Active Package(s):

```

### Steps to Reproduce the Issue
Call get_interfaces_ip with nxos_ssh driver on a device containing at least 1 interface without an IP address assigned to it.

### Error Traceback

```
$ napalm -v nxos_ssh --user itifous --password ***** n9k-hostname call get_interfaces_ip
2019-07-16 13:51:56,644 - napalm - ERROR - method - Failed: list index out of range

================= Traceback =================

Traceback (most recent call last):
  File "/home/itifous/.local/share/virtualenvs/netbox-netprod-importer-1U3vzfIV/bin/napalm", line 11, in <module>
    load_entry_point('napalm', 'console_scripts', 'napalm')()
  File "/home/itifous/.local/share/virtualenvs/netbox-netprod-importer-1U3vzfIV/lib/python3.7/site-packages/napalm-2.4.0-py3.7.egg/napalm/base/clitools/cl_napalm.py", line 309, in main
    run_tests(args)
  File "/home/itifous/.local/share/virtualenvs/netbox-netprod-importer-1U3vzfIV/lib/python3.7/site-packages/napalm-2.4.0-py3.7.egg/napalm/base/clitools/cl_napalm.py", line 292, in run_tests
    call_getter(device, args.method, **method_kwargs)
  File "/home/itifous/.local/share/virtualenvs/netbox-netprod-importer-1U3vzfIV/lib/python3.7/site-packages/napalm-2.4.0-py3.7.egg/napalm/base/clitools/cl_napalm.py", line 31, in wrapper
    r = func(*args, **kwargs)
  File "/home/itifous/.local/share/virtualenvs/netbox-netprod-importer-1U3vzfIV/lib/python3.7/site-packages/napalm-2.4.0-py3.7.egg/napalm/base/clitools/cl_napalm.py", line 256, in call_getter
    r = func(**kwargs)
  File "/home/itifous/.local/share/virtualenvs/netbox-netprod-importer-1U3vzfIV/lib/python3.7/site-packages/napalm-2.4.0-py3.7.egg/napalm/nxos_ssh/nxos_ssh.py", line 892, in get_interfaces_ip
    prefix_len = int(line.split()[5].split("/")[1])
IndexError: list index out of range

```
Cause by : 
``` 
Vlan1003, Interface status: protocol-up/link-up/admin-up, iod: 3,
  IP address: none
  IP broadcast address: 255.255.255.255
  IP multicast groups locally joined: none
  IP MTU: 1500 bytes (using link MTU)
  IP proxy ARP : disabled
  IP Local Proxy ARP : disabled
  IP multicast routing: disabled
  IP icmp redirects: disabled
  IP directed-broadcast: disabled 
  IP Forwarding: enabled 
  IP icmp unreachables (except port): disabled
  IP icmp port-unreachable: enabled
  IP unicast reverse path forwarding: none
  IP load sharing: none 
  IP interface statistics last reset: never
  IP interface software stats: (sent/received/forwarded/originated/consumed)
......
.....
```

The method get_interfaces_ip does not check against a 'none' string before processing the IP address : 
```ipdb> list                                                                                                                                                                                                                                                                                             
    889             if "IP address" in line:
    890                 ip_address = line.split(",")[0].split()[2]
    891                 try:
 -->   892                     prefix_len = int(line.split()[5].split("/")[1])
    893                 except ValueError:
    894                     prefix_len = "N/A"
    895                 val = {"prefix_length": prefix_len}
    896                 v4_interfaces.setdefault(interface, {})[ip_address] = val
    897 
    898         v6_interfaces = {}
    899         for line in output_v6.splitlines():
```

```> /home/itifous/.local/share/virtualenvs/netbox-netprod-importer-1U3vzfIV/lib/python3.7/site-packages/napalm-2.4.0-py3.7.egg/napalm/nxos_ssh/nxos_ssh.py(892)get_interfaces_ip()
    891                 try:
--> 892                     prefix_len = int(line.split()[5].split("/")[1])
    893                 except ValueError:

ipdb> line                                                                                                                                                                                                                                                                                             
'  IP address: none'
   ```

I think simply check against the 'none' str could fix the issue, I will file a PR.




Discussion:

Resolving patch:
diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py
--- a/napalm/nxos_ssh/nxos_ssh.py
+++ b/napalm/nxos_ssh/nxos_ssh.py
@@ -994,10 +994,14 @@ def get_interfaces_ip(self):
                 ip_address = line.split(",")[0].split()[2]
                 try:
                     prefix_len = int(line.split()[5].split("/")[1])
-                except ValueError:
+                except (ValueError, IndexError):
                     prefix_len = "N/A"
-                val = {"prefix_length": prefix_len}
-                v4_interfaces.setdefault(interface, {})[ip_address] = val
+
+                if ip_address == "none":
+                    v4_interfaces.setdefault(interface, {})
+                else:
+                    val = {"prefix_length": prefix_len}
+                    v4_interfaces.setdefault(interface, {})[ip_address] = val
 
         v6_interfaces = {}
         for line in output_v6.splitlines():
@@ -1028,6 +1032,10 @@ def get_interfaces_ip(self):
                 prefix_len = int(prefix_len)
                 val = {"prefix_length": prefix_len}
                 v6_interfaces.setdefault(interface, {})[ip_address] = val
+            else:
+                # match the following format:
+                # IPv6 address: none
+                v6_interfaces.setdefault(interface, {})
 
         # Join data from intermediate dictionaries.
         for interface, data in v4_interfaces.items():


Test patch:
diff --git a/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/expected_result.json b/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/expected_result.json
new file mode 100644
--- /dev/null
+++ b/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/expected_result.json
@@ -0,0 +1,51 @@
+{
+    "Ethernet2/1": {
+        "ipv4": {
+            "1.1.1.1": {
+                "prefix_length": 24
+            }
+        }
+    },
+    "Ethernet2/2": {
+        "ipv4": {
+            "2.2.2.2": {
+                "prefix_length": 27
+            }, 
+            "3.3.3.3": {
+                "prefix_length": 25
+            }
+        }
+    }, 
+    "Ethernet2/3": {
+        "ipv4": {
+            "4.4.4.4": {
+                "prefix_length": 16
+            }
+        }, 
+        "ipv6": {
+            "fe80::2ec2:60ff:fe4f:feb2": {
+                "prefix_length": 64
+            }, 
+            "2001:db8::1": {
+                "prefix_length": 10
+            }
+        }
+    }, 
+    "Ethernet2/4": {
+        "ipv6": {
+            "fe80::2ec2:60ff:fe4f:feb2": {
+                "prefix_length": 64
+            }, 
+            "2001:11:2233::a1": {
+                "prefix_length": 24
+            }, 
+            "2001:cc11:22bb:0:2ec2:60ff:fe4f:feb2": {
+                "prefix_length": 64
+            }
+        }
+    },
+    "Vlan1003":{
+      "ipv4": {},
+      "ipv6": {}
+    }
+}
diff --git a/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/show_ip_interface_vrf_all.txt b/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/show_ip_interface_vrf_all.txt
new file mode 100644
--- /dev/null
+++ b/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/show_ip_interface_vrf_all.txt
@@ -0,0 +1,118 @@
+IP Interface Status for VRF "default"
+Ethernet2/1, Interface status: protocol-up/link-up/admin-up, iod: 37,
+  IP address: 1.1.1.1, IP subnet: 1.1.1.0/24 route-preference: 0, tag: 0
+  IP broadcast address: 255.255.255.255
+  IP multicast groups locally joined: none
+  IP MTU: 1500 bytes (using link MTU)
+  IP primary address route-preference: 0, tag: 0
+  IP proxy ARP : disabled
+  IP Local Proxy ARP : disabled
+  IP multicast routing: disabled
+  IP icmp redirects: enabled
+  IP directed-broadcast: disabled
+  IP Forwarding: disabled
+  IP icmp unreachables (except port): disabled
+  IP icmp port-unreachable: enabled
+  IP unicast reverse path forwarding: none
+  IP load sharing: none
+  IP interface statistics last reset: never
+  IP interface software stats: (sent/received/forwarded/originated/consumed)
+    Unicast packets    : 59/57/0/237/292
+    Unicast bytes      : 4829/3619/0/15823/18232
+    Multicast packets  : 0/0/0/0/0
+    Multicast bytes    : 0/0/0/0/0
+    Broadcast packets  : 0/0/0/0/0
+    Broadcast bytes    : 0/0/0/0/0
+    Labeled packets    : 0/0/0/0/0
+    Labeled bytes      : 0/0/0/0/0
+  WCCP Redirect outbound: disabled
+  WCCP Redirect inbound: disabled
+  WCCP Redirect exclude: disabled
+Ethernet2/2, Interface status: protocol-up/link-up/admin-up, iod: 38,
+  IP address: 2.2.2.2, IP subnet: 2.2.2.0/27 route-preference: 0, tag: 0
+  IP address: 3.3.3.3, IP subnet: 3.3.3.0/25 secondary route-preference: 0, tag: 0
+  IP broadcast address: 255.255.255.255
+  IP multicast groups locally joined: none
+  IP MTU: 1500 bytes (using link MTU)
+  IP primary address route-preference: 0, tag: 0
+  IP proxy ARP : disabled
+  IP Local Proxy ARP : disabled
+  IP multicast routing: disabled
+  IP icmp redirects: disabled
+  IP directed-broadcast: disabled
+  IP Forwarding: disabled
+  IP icmp unreachables (except port): disabled
+  IP icmp port-unreachable: enabled
+  IP unicast reverse path forwarding: none
+  IP load sharing: none
+  IP interface statistics last reset: never
+  IP interface software stats: (sent/received/forwarded/originated/consumed)
+    Unicast packets    : 0/0/0/0/0
+    Unicast bytes      : 0/0/0/0/0
+    Multicast packets  : 0/0/0/0/0
+    Multicast bytes    : 0/0/0/0/0
+    Broadcast packets  : 0/0/0/0/0
+    Broadcast bytes    : 0/0/0/0/0
+    Labeled packets    : 0/0/0/0/0
+    Labeled bytes      : 0/0/0/0/0
+  WCCP Redirect outbound: disabled
+  WCCP Redirect inbound: disabled
+  WCCP Redirect exclude: disabled
+Ethernet2/3, Interface status: protocol-up/link-up/admin-up, iod: 39,
+  IP address: 4.4.4.4, IP subnet: 4.4.0.0/16 route-preference: 0, tag: 0
+  IP broadcast address: 255.255.255.255
+  IP multicast groups locally joined: none
+  IP MTU: 1500 bytes (using link MTU)
+  IP primary address route-preference: 0, tag: 0
+  IP proxy ARP : disabled
+  IP Local Proxy ARP : disabled
+  IP multicast routing: disabled
+  IP icmp redirects: enabled
+  IP directed-broadcast: disabled
+  IP Forwarding: disabled
+  IP icmp unreachables (except port): disabled
+  IP icmp port-unreachable: enabled
+  IP unicast reverse path forwarding: none
+  IP load sharing: none
+  IP interface statistics last reset: never
+  IP interface software stats: (sent/received/forwarded/originated/consumed)
+    Unicast packets    : 4/4/0/14/18
+    Unicast bytes      : 408/336/0/1248/1512
+    Multicast packets  : 0/0/0/0/0
+    Multicast bytes    : 0/0/0/0/0
+    Broadcast packets  : 0/0/0/0/0
+    Broadcast bytes    : 0/0/0/0/0
+    Labeled packets    : 0/0/0/0/0
+    Labeled bytes      : 0/0/0/0/0
+  WCCP Redirect outbound: disabled
+  WCCP Redirect inbound: disabled
+  WCCP Redirect exclude: disabled
+Vlan1003, Interface status: protocol-up/link-up/admin-up, iod: 13,
+  IP address: none
+  IP broadcast address: 255.255.255.255
+  IP multicast groups locally joined: none
+  IP MTU: 1500 bytes (using link MTU)
+  IP proxy ARP : disabled
+  IP Local Proxy ARP : disabled
+  IP multicast routing: disabled
+  IP icmp redirects: disabled
+  IP directed-broadcast: disabled 
+  IP Forwarding: enabled 
+  IP icmp unreachables (except port): disabled
+  IP icmp port-unreachable: enabled
+  IP unicast reverse path forwarding: none
+  IP load sharing: none 
+  IP interface statistics last reset: never
+  IP interface software stats: (sent/received/forwarded/originated/consumed)
+    Unicast packets    : 0/13/0/0/12
+    Unicast bytes      : 0/4288/0/0/4228
+    Multicast packets  : 0/0/0/0/0
+    Multicast bytes    : 0/0/0/0/0
+    Broadcast packets  : 0/0/0/0/0
+    Broadcast bytes    : 0/0/0/0/0
+    Labeled packets    : 0/0/0/0/0
+    Labeled bytes      : 0/0/0/0/0
+  WCCP Redirect outbound: disabled
+  WCCP Redirect inbound: disabled
+  WCCP Redirect exclude: disabled
+
diff --git a/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/show_ipv6_interface_vrf_all.txt b/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/show_ipv6_interface_vrf_all.txt
new file mode 100644
--- /dev/null
+++ b/test/nxos_ssh/mocked_data/test_get_interfaces_ip/ip_address_none/show_ipv6_interface_vrf_all.txt
@@ -0,0 +1,65 @@
+IPv6 Interface Status for VRF "default"
+Ethernet2/3, Interface status: protocol-up/link-up/admin-up, iod: 39
+  IPv6 address:
+    2001:db8::1/10 [VALID]
+  IPv6 subnet:  2000::/10
+  IPv6 link-local address: fe80::2ec2:60ff:fe4f:feb2 (default) [VALID]
+  IPv6 virtual addresses configured: none
+  IPv6 multicast routing: disabled
+  IPv6 report link local: disabled
+  IPv6 Forwarding feature: disabled
+  IPv6 multicast groups locally joined:
+      ff02::2  ff02::1  ff02::1:ff00:1  ff02::1:ff4f:feb2
+      ff02::1:ff00:0
+  IPv6 multicast (S,G) entries joined: none
+  IPv6 MTU: 1500 (using link MTU)
+  IPv6 unicast reverse path forwarding: none
+  IPv6 load sharing: none
+  IPv6 interface statistics last reset: never
+  IPv6 interface RP-traffic statistics: (forwarded/originated/consumed)
+    Unicast packets:      0/0/0
+    Unicast bytes:        0/0/0
+    Multicast packets:    0/15/0
+    Multicast bytes:      0/1590/0
+Ethernet2/4, Interface status: protocol-up/link-up/admin-up, iod: 40
+  IPv6 address:
+    2001:11:2233::a1/24 [VALID]
+    2001:cc11:22bb:0:2ec2:60ff:fe4f:feb2/64 [VALID]
+  IPv6 subnet:  2001::/24
+  IPv6 link-local address: fe80::2ec2:60ff:fe4f:feb2 (default) [VALID]
+  IPv6 virtual addresses configured: none
+  IPv6 multicast routing: disabled
+  IPv6 report link local: disabled
+  IPv6 Forwarding feature: disabled
+  IPv6 multicast groups locally joined:
+      ff02::1:ff4f:feb2  ff02::2  ff02::1  ff02::1:ff00:a1
+      ff02::1:ff4f:feb2  ff02::1:ff00:0
+  IPv6 multicast (S,G) entries joined: none
+  IPv6 MTU: 1500 (using link MTU)
+  IPv6 unicast reverse path forwarding: none
+  IPv6 load sharing: none
+  IPv6 interface statistics last reset: never
+  IPv6 interface RP-traffic statistics: (forwarded/originated/consumed)
+    Unicast packets:      0/0/0
+    Unicast bytes:        0/0/0
+    Multicast packets:    0/18/0
+    Multicast bytes:      0/2076/0
+Vlan1003, Interface status: protocol-up/link-up/admin-up, iod: 13
+  IPv6 address: none
+  IPv6 link-local address: 0:: (default) [NONE]
+  IPv6 virtual addresses configured: none
+  IPv6 multicast routing: disabled
+  IPv6 report link local: disabled
+  IPv6 Forwarding feature: enabled
+  IPv6 multicast groups locally joined: none
+  IPv6 multicast (S,G) entries joined: none
+  IPv6 MTU: 1500 (using link MTU)
+  IPv6 unicast reverse path forwarding: none
+  IPv6 load sharing: none
+  IPv6 interface statistics last reset: never
+  IPv6 interface RP-traffic statistics: (forwarded/originated/consumed)
+    Unicast packets:      0/0/0
+    Unicast bytes:        0/0/0
+    Multicast packets:    0/0/0
+    Multicast bytes:      0/0/0
+