Skip to content

Commit

Permalink
Merge branch 'develop' into f/enhance_get_interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
itdependsnetworks authored Jan 28, 2018
2 parents 4958ded + 5e99f32 commit c35c7d9
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 12 deletions.
119 changes: 113 additions & 6 deletions napalm_panos/panos.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,24 @@
import time

# local modules
from napalm_base.utils.string_parsers import convert_uptime_string_seconds
from napalm_base.exceptions import ConnectionException, ReplaceConfigException,\
MergeConfigException

try:
from napalm.base.utils.string_parsers import convert_uptime_string_seconds
from napalm.base.exceptions import ConnectionException
from napalm.base.exceptions import ReplaceConfigException
from napalm.base.exceptions import MergeConfigException
from napalm.base import NetworkDriver
from napalm.base.utils import py23_compat
except ImportError:
from napalm_base.utils.string_parsers import convert_uptime_string_seconds
from napalm_base.exceptions import ConnectionException
from napalm_base.exceptions import ReplaceConfigException
from napalm_base.exceptions import MergeConfigException
from napalm_base.base import NetworkDriver
from napalm_base.utils import py23_compat


from napalm_base.utils import py23_compat
from napalm_base.helpers import mac as standardize_mac

from netmiko import ConnectHandler
from netmiko import __version__ as netmiko_version

Expand Down Expand Up @@ -445,7 +451,7 @@ def get_route_to(self, destination='', protocol=''):
routes_table_xml = xmltodict.parse(self.device.xml_root())
routes_table_json = json.dumps(routes_table_xml['response']['result']['entry'])
routes_table = json.loads(routes_table_json)
except AttributeError:
except (AttributeError, KeyError):
routes_table = []

if isinstance(routes_table, dict):
Expand Down Expand Up @@ -554,3 +560,104 @@ def get_interfaces(self):
interface_dict[intf] = interface

return interface_dict

def get_interfaces_ip(self):
'''Return IP interface data.'''

def extract_ip_info(parsed_intf_dict):
'''
IPv4:
- Primary IP is in the '<ip>' tag. If no v4 is configured the return value is 'N/A'.
- Secondary IP's are in '<addr>'. If no secondaries, this field is not returned by
the xmltodict.parse() method.
IPv6:
- All addresses are returned in '<addr6>'. If no v6 configured, this is not returned
either by xmltodict.parse().
Example of XML response for an intf with multiple IPv4 and IPv6 addresses:
<response status="success">
<result>
<ifnet>
<entry>
<name>ethernet1/5</name>
<zone/>
<fwd>N/A</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6>
<member>fe80::d61d:71ff:fed8:fe14/64</member>
<member>2001::1234/120</member>
</addr6>
<tag>0</tag>
<ip>169.254.0.1/30</ip>
<id>20</id>
<addr>
<member>1.1.1.1/28</member>
</addr>
</entry>
{...}
</ifnet>
<hw>
{...}
</hw>
</result>
</response>
'''
intf = parsed_intf_dict['name']
_ip_info = {intf: {}}

v4_ip = parsed_intf_dict.get('ip')
secondary_v4_ip = parsed_intf_dict.get('addr')
v6_ip = parsed_intf_dict.get('addr6')

if v4_ip != 'N/A':
address, pref = v4_ip.split('/')
_ip_info[intf].setdefault('ipv4', {})[address] = {'prefix_length': int(pref)}

if secondary_v4_ip is not None:
members = secondary_v4_ip['member']
if not isinstance(members, list):
# If only 1 secondary IP is present, xmltodict converts field to a string, else
# it converts it to a list of strings.
members = [members]
for address in members:
address, pref = address.split('/')
_ip_info[intf].setdefault('ipv4', {})[address] = {'prefix_length': int(pref)}

if v6_ip is not None:
members = v6_ip['member']
if not isinstance(members, list):
# Same "1 vs many -> string vs list of strings" comment.
members = [members]
for address in members:
address, pref = address.split('/')
_ip_info[intf].setdefault('ipv6', {})[address] = {'prefix_length': int(pref)}

# Reset dictionary if no addresses were found.
if _ip_info == {intf: {}}:
_ip_info = {}

return _ip_info

ip_interfaces = {}
cmd = "<show><interface>all</interface></show>"

self.device.op(cmd=cmd)
interface_info_xml = xmltodict.parse(self.device.xml_root())
interface_info_json = json.dumps(
interface_info_xml['response']['result']['ifnet']['entry']
)
interface_info = json.loads(interface_info_json)

if isinstance(interface_info, dict):
# Same "1 vs many -> dict vs list of dicts" comment.
interface_info = [interface_info]

for interface_dict in interface_info:
ip_info = extract_ip_info(interface_dict)
if ip_info:
ip_interfaces.update(ip_info)

return ip_interfaces
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
napalm-base>=0.18.0
napalm>=2.3.0
pan-python
netmiko>=1.0.0
requests-toolbelt
Expand Down
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-panos",
version="0.4.2",
version="0.5.1",
packages=find_packages(),
author="Gabriele Gerbino",
author_email="[email protected]",
Expand Down
2 changes: 1 addition & 1 deletion test/unit/TestDriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import unittest

from napalm_panos import panos
from napalm_base.test.base import TestConfigNetworkDriver
from napalm.base.test.base import TestConfigNetworkDriver


class TestConfigDriver(unittest.TestCase, TestConfigNetworkDriver):
Expand Down
4 changes: 2 additions & 2 deletions test/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from builtins import super

import pytest
from napalm_base.test import conftest as parent_conftest
from napalm_base.test.double import BaseTestDouble
from napalm.base.test import conftest as parent_conftest
from napalm.base.test.double import BaseTestDouble

from napalm_panos import PANOSDriver as OriginalDriver

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<response status="success">
<result>
<ifnet>
<entry>
<name>ethernet1/1</name>
<zone>foo</zone>
<fwd>N/A</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6/>
<tag>0</tag>
<ip>N/A</ip>
<id>16</id>
<addr/>
</entry>
<entry>
<name>ethernet1/1.202</name>
<zone>foo</zone>
<fwd>vr:default</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6/>
<tag>202</tag>
<ip>157.191.8.17/28</ip>
<id>257</id>
<addr/>
</entry>
<entry>
<name>ethernet1/2</name>
<zone>Internet</zone>
<fwd>vr:default</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6/>
<tag>0</tag>
<ip>157.191.6.156/24</ip>
<id>18</id>
<addr>
<member>2.2.2.2/24</member>
</addr>
</entry>
<entry>
<name>ethernet1/3</name>
<zone/>
<fwd>N/A</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6/>
<tag>0</tag>
<ip>N/A</ip>
<id>19</id>
<addr/>
</entry>
<entry>
<name>ethernet1/3.301</name>
<zone/>
<fwd>vr:default</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6/>
<tag>301</tag>
<ip>172.24.255.1/26</ip>
<id>258</id>
<addr/>
</entry>
<entry>
<name>ethernet1/4</name>
<zone/>
<fwd>N/A</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6>
<member>fe80::d61d:71ff:fed8:fe14/64</member>
<member>2001::1234/120</member>
</addr6>
<tag>0</tag>
<ip>169.254.0.1/30</ip>
<id>20</id>
<addr>
<member>1.1.1.1/28</member>
</addr>
</entry>
<entry>
<name>loopback</name>
<zone/>
<fwd>N/A</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6/>
<tag>0</tag>
<ip>N/A</ip>
<id>3</id>
<addr/>
</entry>
<entry>
<name>loopback.100</name>
<zone>Mbar</zone>
<fwd>vr:default</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6/>
<tag>0</tag>
<ip>N/A</ip>
<id>256</id>
<member>2001::7890/84</member>
</entry>
<entry>
<name>tunnel</name>
<zone/>
<fwd>N/A</fwd>
<vsys>1</vsys>
<dyn-addr/>
<addr6/>
<tag>0</tag>
<ip>N/A</ip>
<id>4</id>
<addr/>
</entry>
</ifnet>
<hw>
<entry>
<name>ethernet1/1</name>
<duplex>full</duplex>
<type>0</type>
<state>up</state>
<st>10000/full/up</st>
<mac>d4:1d:71:d8:fe:10</mac>
<mode>(autoneg)</mode>
<speed>10000</speed>
<id>16</id>
</entry>
<entry>
<name>ethernet1/2</name>
<duplex>full</duplex>
<type>0</type>
<state>up</state>
<st>10000/full/up</st>
<mac>d4:1d:71:d8:fe:11</mac>
<mode>(autoneg)</mode>
<speed>10000</speed>
<id>17</id>
</entry>
<entry>
<name>ethernet1/3</name>
<duplex>full</duplex>
<type>0</type>
<state>up</state>
<st>10000/full/up</st>
<mac>d4:1d:71:d8:fe:12</mac>
<mode>(autoneg)</mode>
<speed>10000</speed>
<id>18</id>
</entry>
<entry>
<name>ethernet1/4</name>
<duplex>full</duplex>
<type>0</type>
<state>up</state>
<st>10000/full/up</st>
<mac>d4:1d:71:d8:fe:13</mac>
<mode>(autoneg)</mode>
<speed>10000</speed>
<id>19</id>
</entry>
<entry>
<name>loopback</name>
<duplex>[n/a]</duplex>
<type>5</type>
<state>up</state>
<st>[n/a]/[n/a]/up</st>
<mac>d4:1d:71:d8:fe:03</mac>
<mode>(unknown)</mode>
<speed>[n/a]</speed>
<id>3</id>
</entry>
<entry>
<name>tunnel</name>
<duplex>[n/a]</duplex>
<type>6</type>
<state>up</state>
<st>[n/a]/[n/a]/up</st>
<mac>d4:1d:71:d8:fe:04</mac>
<mode>(unknown)</mode>
<speed>[n/a]</speed>
<id>4</id>
</entry>
</hw>
</result>
</response>
Loading

0 comments on commit c35c7d9

Please sign in to comment.