Add support for IOS vlan parsing filter. (#40555)

* Add support for IOS vlan parsing filter.
Example usage below:

{% set parsed_vlans = vlans | vlan_parser %}
switchport trunk allowed vlan {{ parsed_vlans[0] }}
{% for i in range (1, parsed_vlans | count) %}
switchport trunk allowed vlan add {{ parsed_vlans[i] }}

* Update test_network.py

Add import statement for filter

* Fixed PEP8 issues relating to comments

* Fix PEP8 issues related to blank lines

* Removed magic numbers for line lengths. This should generalize support
to other IOS-like NOS that use similar methods for listing vlans. The
default arguments for line lengths will still be specific to Cisco IOS.
The unit tests for line length are still specific to Cisco IOS.
pull/47196/merge
Steve Dodd 6 years ago committed by Sumit Jaiswal
parent 61ae6424a3
commit ee6ab5d5aa

@ -399,6 +399,79 @@ def comp_type5(unencrypted_password, encrypted_password, return_original=False):
return False
def vlan_parser(vlan_list, first_line_len=48, other_line_len=44):
'''
Input: Unsorted list of vlan integers
Output: Sorted string list of integers according to IOS-like vlan list rules
1. Vlans are listed in ascending order
2. Runs of 3 or more consecutive vlans are listed with a dash
3. The first line of the list can be first_line_len characters long
4. Subsequent list lines can be other_line_len characters
'''
# Sort and remove duplicates
sorted_list = sorted(set(vlan_list))
if sorted_list[0] < 1 or sorted_list[-1] > 4094:
raise AnsibleFilterError('Valid VLAN range is 1-4094')
parse_list = []
idx = 0
while idx < len(sorted_list):
start = idx
end = start
while end < len(sorted_list) - 1:
if sorted_list[end + 1] - sorted_list[end] == 1:
end += 1
else:
break
if start == end:
# Single VLAN
parse_list.append(str(sorted_list[idx]))
elif start + 1 == end:
# Run of 2 VLANs
parse_list.append(str(sorted_list[start]))
parse_list.append(str(sorted_list[end]))
else:
# Run of 3 or more VLANs
parse_list.append(str(sorted_list[start]) + '-' + str(sorted_list[end]))
idx = end + 1
line_count = 0
result = ['']
for vlans in parse_list:
# First line (" switchport trunk allowed vlan ")
if line_count == 0:
if len(result[line_count] + vlans) > first_line_len:
result.append('')
line_count += 1
result[line_count] += vlans + ','
else:
result[line_count] += vlans + ','
# Subsequent lines (" switchport trunk allowed vlan add ")
else:
if len(result[line_count] + vlans) > other_line_len:
result.append('')
line_count += 1
result[line_count] += vlans + ','
else:
result[line_count] += vlans + ','
# Remove trailing orphan commas
for idx in range(0, len(result)):
result[idx] = result[idx].rstrip(',')
# Sometimes text wraps to next line, but there are no remaining VLANs
if '' in result:
result.remove('')
return result
class FilterModule(object):
"""Filters for working with output from network devices"""
@ -408,7 +481,8 @@ class FilterModule(object):
'parse_xml': parse_xml,
'type5_pw': type5_pw,
'hash_salt': hash_salt,
'comp_type5': comp_type5
'comp_type5': comp_type5,
'vlan_parser': vlan_parser
}
def filters(self):

@ -23,7 +23,8 @@ import sys
import pytest
from units.compat import unittest
from ansible.plugins.filter.network import parse_xml, type5_pw, hash_salt, comp_type5
from ansible.plugins.filter.network import parse_xml, type5_pw, hash_salt, comp_type5, vlan_parser
from ansible.errors import AnsibleFilterError
fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures', 'network')
@ -165,3 +166,21 @@ class TestCompareType5(unittest.TestCase):
encrypted_password = '$1$nTc1$Z28sUTcWfXlvVe2x.3XAa.'
parsed = comp_type5(unencrypted_password, encrypted_password)
self.assertEqual(parsed, False)
class TestVlanParser(unittest.TestCase):
def test_compression(self):
raw_list = [1, 2, 3]
parsed_list = ['1-3']
self.assertEqual(vlan_parser(raw_list), parsed_list)
def test_single_line(self):
raw_list = [100, 1688, 3002, 3003, 3004, 3005, 3102, 3103, 3104, 3105, 3802, 3900, 3998, 3999]
parsed_list = ['100,1688,3002-3005,3102-3105,3802,3900,3998,3999']
self.assertEqual(vlan_parser(raw_list), parsed_list)
def test_multi_line(self):
raw_list = [100, 1688, 3002, 3004, 3005, 3050, 3102, 3104, 3105, 3151, 3802, 3900, 3998, 3999]
parsed_list = ['100,1688,3002,3004,3005,3050,3102,3104,3105,3151', '3802,3900,3998,3999']
self.assertEqual(vlan_parser(raw_list), parsed_list)

Loading…
Cancel
Save