Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix issue #161 - add parsing of secondary ip from interfaces #251

Merged
merged 2 commits into from
Feb 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ pyflakes:
pyflakes pyeapi/ test/

flake8:
flake8 --ignore=E201,E202,E302,E303,E402,E731,W391 --exit-zero pyeapi/
flake8 --ignore=E201,E202,E302,E303,E402,E731,W391,N802 --max-line-length=100 test/
flake8 --ignore=E128,E201,E202,E302,E303,E402,E731,W391 --exit-zero pyeapi/
flake8 --ignore=E128,E201,E202,E302,E303,E402,E731,W391,N802 --max-line-length=100 test/
mharista marked this conversation as resolved.
Show resolved Hide resolved

check:
check-manifest
Expand Down
35 changes: 19 additions & 16 deletions pyeapi/api/ipinterfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,18 @@
SWITCHPORT_RE = re.compile(r'no switchport$', re.M)


class Ipinterfaces(EntityCollection):
class Ipinterfaces( EntityCollection ):

def get(self, name):
def get( self, name ):
"""Returns the specific IP interface properties

The Ipinterface resource returns the following:

* name (str): The name of the interface
* address (str): The IP address of the interface in the form
of A.B.C.D/E
of A.B.C.D/E (None if no ip configured)
* secondary (list): The list of secondary IP addresses of the
interface (if any configured)
* mtu (int): The configured value for IP MTU.


Expand All @@ -75,22 +77,21 @@ def get(self, name):
the current configuration of the node. If the specified
interface does not exist then None is returned.
"""
config = self.get_block('interface %s' % name)

if name[0:2] in ['Et', 'Po'] and not SWITCHPORT_RE.search(config,
re.M):
config = self.get_block( 'interface %s' % name )
if name[ 0:2 ] in [
'Et', 'Po' ] and not SWITCHPORT_RE.search( config, re.M ):
return None

resource = dict(name=name)
resource.update(self._parse_address(config))
resource.update(self._parse_mtu(config))
resource = dict( name=name )
resource.update( self._parse_address(config) )
resource.update( self._parse_mtu(config) )
return resource

def _parse_address(self, config):
def _parse_address( self, config ):
"""Parses the config block and returns the ip address value

The provided configuration block is scaned and the configured value
for the IP address is returned as a dict object. If the IP address
The provided configuration block is scanned and the configured value
for the IP address is returned as a dict object. If the IP address
value is not configured, then None is returned for the value

Args:
Expand All @@ -99,9 +100,11 @@ def _parse_address(self, config):
Return:
dict: A dict object intended to be merged into the resource dict
"""
match = re.search(r'ip address ([^\s]+)', config)
value = match.group(1) if match else None
return dict(address=value)
match = re.findall( r'ip address ([^\s]+)', config, re.M )
primary, secondary = ( match[0],
match[1:] ) if match else ( None, None )
return dict( address=primary,
secondary=secondary ) if secondary else dict( address=primary )

def _parse_mtu(self, config):
"""Parses the config block and returns the configured IP MTU value
Expand Down
3 changes: 2 additions & 1 deletion pyeapi/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@

from pyeapi.eapilib import HttpEapiConnection, HttpsEapiConnection
from pyeapi.eapilib import HttpsEapiCertConnection
from pyeapi.eapilib import HttpEapiSessionConnection, HttpsEapiSessionConnection
from pyeapi.eapilib import HttpEapiSessionConnection
from pyeapi.eapilib import HttpsEapiSessionConnection
from pyeapi.eapilib import SocketEapiConnection, HttpLocalEapiConnection
from pyeapi.eapilib import CommandError

Expand Down
2 changes: 1 addition & 1 deletion pyeapi/eapilib.py
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ def authentication(self, username, password):
_LOGGER.exception(exc)
self.socket_error = exc
self.error = exc
error_msg = 'Socket error during eAPI authentication: %s' % str(exc)
error_msg = f'Socket error during eAPI authentication: {exc}'
raise ConnectionError(str(self), error_msg)
except ValueError as exc:
_LOGGER.exception(exc)
Expand Down
8 changes: 2 additions & 6 deletions pyeapi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,6 @@ def make_iterable(value):
Returns:
An iterable object of type list
"""
if sys.version_info <= (3, 0):
# Convert unicode values to strings for Python 2
if isinstance(value, unicode):
value = str(value)
if isinstance(value, str) or isinstance(
value, dict) or isinstance(value, CliVariants):
value = [value]
Expand Down Expand Up @@ -259,5 +255,5 @@ class CliVariants:
"""
def __init__(self, *cli):
assert len( cli ) >= 2, 'must be initialized with 2 or more arguments'
self.variants = [ v if not isinstance(v, str) and isinstance(v, Iterable)
else [v] for v in cli ]
self.variants = [ v if not isinstance(v,
str) and isinstance(v, Iterable) else [v] for v in cli ]
6 changes: 6 additions & 0 deletions test/fixtures/running_config.text
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,12 @@ interface Loopback0
bfd interval 300 min_rx 300 multiplier 3
default ntp serve
!
interface Loopback2
description test fixture with secondary ip
ip address 2.2.2.2/32
ip address 3.255.255.1/24 secondary
ip address 4.255.255.1/24 secondary
!
interface Ethernet8
! the interface config is added separately covering test for issue #213
! it might be inconsistend with the rest of config, though all unit tests pass
Expand Down
11 changes: 8 additions & 3 deletions test/unit/test_api_ipinterfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,19 @@ def __init__(self, *args, **kwargs):
self.config = open(get_fixture('running_config.text')).read()

def test_get(self):
result = self.instance.get('Loopback0')
values = dict(name='Loopback0', address='1.1.1.1/32', mtu=1500)
result = self.instance.get( 'Loopback0' )
values = dict( name='Loopback0', address='1.1.1.1/32', mtu=1500 )
self.assertEqual( result, values )
# test interface with secondary ip
result = self.instance.get( 'Loopback2' )
values = dict( name='Loopback2', address='2.2.2.2/32',
secondary=['3.255.255.1/24', '4.255.255.1/24'], mtu=None )
self.assertEqual(result, values)

def test_getall(self):
result = self.instance.getall()
self.assertIsInstance(result, dict)
self.assertEqual(len(result), 3)
self.assertEqual(len(result), 4)

def test_instance_functions(self):
for intf in self.INTERFACES:
Expand Down