Skip to content

Commit 9e9f6e6

Browse files
authored
Add generate_switchport_trunk func (#1062)
* Add `generate_switchport_trunk` func This should fix #1061 by splitting switchport vlan commands into several if resulted vlan lexeme will be more than 220 symbols. * test(l2_interface): add test for multiline trunk generation * Add changelog entry * fix(changelog): fragmets file extention * fix(test l2_interfaces): python style * fix(test_ios_l2_interfaces): tests
1 parent 666b390 commit 9e9f6e6

File tree

4 files changed

+224
-4
lines changed

4 files changed

+224
-4
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
bugfixes:
3+
- l2_interfaces - If a large number of VLANs are affected, the configuration will now be correctly split into several commands.

plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
L2_interfacesTemplate,
3232
)
3333
from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
34+
generate_switchport_trunk,
3435
normalize_interface,
3536
vlan_list_to_range,
3637
vlan_range_to_list,
@@ -136,11 +137,10 @@ def compare_list(self, want, have):
136137
),
137138
)
138139
if self.state != "deleted" and cmd_always: # add configuration needed
139-
add = "add " if have.get("trunk", {}).get(vlan, []) else ""
140-
self.commands.append(
141-
"switchport trunk {0} vlan {1}{2}".format(
140+
self.commands.extend(
141+
generate_switchport_trunk(
142142
vlan.split("_", maxsplit=1)[0],
143-
add,
143+
have.get("trunk", {}).get(vlan, []),
144144
vlan_list_to_range(sorted(cmd_always)),
145145
),
146146
)

plugins/module_utils/network/ios/utils/utils.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,35 @@ def sort_dict(dictionary):
422422
else:
423423
sorted_dict[key] = value
424424
return sorted_dict
425+
426+
427+
def generate_switchport_trunk(type, add, vlans_range):
428+
"""
429+
Generates a list of switchport commands based on the trunk type and VLANs range.
430+
Ensures that the length of VLANs lexeme in a command does not exceed 220 characters.
431+
"""
432+
433+
def append_command():
434+
command_prefix = f"switchport trunk {type} vlan "
435+
if add or commands:
436+
command_prefix += "add "
437+
commands.append(command_prefix + ",".join(current_chunk))
438+
439+
commands = []
440+
current_chunk = []
441+
current_length = 0
442+
443+
for vrange in vlans_range.split(","):
444+
next_addition = vrange if not current_chunk else "," + vrange
445+
if current_length + len(next_addition) <= 220:
446+
current_chunk.append(vrange)
447+
current_length += len(next_addition)
448+
else:
449+
append_command()
450+
current_chunk = [vrange]
451+
current_length = len(vrange)
452+
453+
if current_chunk:
454+
append_command()
455+
456+
return commands

tests/unit/modules/network/ios/test_ios_l2_interfaces.py

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,3 +793,188 @@ def test_ios_l2_interfaces_fiveGibBit(self):
793793
result = self.execute_module(changed=True)
794794
self.maxDiff = None
795795
self.assertEqual(sorted(result["commands"]), sorted(commands))
796+
797+
def test_ios_l2_interfaces_trunk_multiline_merge(self):
798+
self.execute_show_command.return_value = dedent(
799+
"""\
800+
interface GigabitEthernet0/2
801+
switchport trunk allowed vlan 10-20,40
802+
switchport trunk encapsulation dot1q
803+
switchport trunk native vlan 10
804+
switchport trunk pruning vlan 10,20
805+
switchport mode trunk
806+
""",
807+
)
808+
set_module_args(
809+
dict(
810+
config=[
811+
dict(
812+
mode="trunk",
813+
name="GigabitEthernet0/2",
814+
trunk=dict(
815+
allowed_vlans=["60-70"] + [str(vlan) for vlan in range(101, 500, 2)],
816+
encapsulation="isl",
817+
native_vlan=20,
818+
pruning_vlans=["10", "20", "30-40"],
819+
),
820+
),
821+
],
822+
state="merged",
823+
),
824+
)
825+
commands = [
826+
"interface GigabitEthernet0/2",
827+
"switchport trunk encapsulation isl",
828+
"switchport trunk native vlan 20",
829+
"switchport trunk allowed vlan add 60-70,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,"
830+
+ "149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205",
831+
"switchport trunk allowed vlan add 207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,257,"
832+
+ "259,261,263,265,267,269,271,273,275,277,279,281,283,285,287,289,291,293,295,297,299,301,303,305,307,309,311,313,315",
833+
"switchport trunk allowed vlan add 317,319,321,323,325,327,329,331,333,335,337,339,341,343,345,347,349,351,353,355,357,359,361,363,365,367,"
834+
+ "369,371,373,375,377,379,381,383,385,387,389,391,393,395,397,399,401,403,405,407,409,411,413,415,417,419,421,423,425",
835+
"switchport trunk allowed vlan add 427,429,431,433,435,437,439,441,443,445,447,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477,"
836+
+ "479,481,483,485,487,489,491,493,495,497,499",
837+
"switchport trunk pruning vlan add 30-40",
838+
]
839+
result = self.execute_module(changed=True)
840+
self.maxDiff = None
841+
self.assertEqual(result["commands"], commands)
842+
843+
def test_ios_l2_interfaces_trunk_multiline_replace(self):
844+
self.execute_show_command.return_value = dedent(
845+
"""\
846+
interface GigabitEthernet0/2
847+
switchport trunk allowed vlan 10-20,40
848+
switchport trunk encapsulation dot1q
849+
switchport trunk native vlan 10
850+
switchport trunk pruning vlan 10,20
851+
switchport mode trunk
852+
""",
853+
)
854+
set_module_args(
855+
dict(
856+
config=[
857+
dict(
858+
mode="trunk",
859+
name="GigabitEthernet0/2",
860+
trunk=dict(
861+
allowed_vlans=["60-70"] + [str(vlan) for vlan in range(101, 500, 2)],
862+
encapsulation="isl",
863+
native_vlan=20,
864+
pruning_vlans=["10", "20", "30-40"],
865+
),
866+
),
867+
],
868+
state="replaced",
869+
),
870+
)
871+
commands = [
872+
"interface GigabitEthernet0/2",
873+
"switchport trunk encapsulation isl",
874+
"switchport trunk native vlan 20",
875+
"switchport trunk allowed vlan remove 10-20,40",
876+
"switchport trunk allowed vlan add 60-70,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,"
877+
+ "149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205",
878+
"switchport trunk allowed vlan add 207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,257,"
879+
+ "259,261,263,265,267,269,271,273,275,277,279,281,283,285,287,289,291,293,295,297,299,301,303,305,307,309,311,313,315",
880+
"switchport trunk allowed vlan add 317,319,321,323,325,327,329,331,333,335,337,339,341,343,345,347,349,351,353,355,357,359,361,363,365,367,"
881+
+ "369,371,373,375,377,379,381,383,385,387,389,391,393,395,397,399,401,403,405,407,409,411,413,415,417,419,421,423,425",
882+
"switchport trunk allowed vlan add 427,429,431,433,435,437,439,441,443,445,447,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477,"
883+
+ "479,481,483,485,487,489,491,493,495,497,499",
884+
"switchport trunk pruning vlan add 30-40",
885+
]
886+
result = self.execute_module(changed=True)
887+
self.maxDiff = None
888+
self.assertEqual(result["commands"], commands)
889+
890+
def test_ios_l2_interfaces_trunk_multiline_replace_init(self):
891+
self.execute_show_command.return_value = dedent(
892+
"""\
893+
interface GigabitEthernet0/2
894+
switchport trunk encapsulation dot1q
895+
switchport trunk native vlan 10
896+
switchport trunk pruning vlan 10,20
897+
switchport mode trunk
898+
""",
899+
)
900+
set_module_args(
901+
dict(
902+
config=[
903+
dict(
904+
mode="trunk",
905+
name="GigabitEthernet0/2",
906+
trunk=dict(
907+
allowed_vlans=["60-70"] + [str(vlan) for vlan in range(101, 500, 2)],
908+
encapsulation="isl",
909+
native_vlan=20,
910+
pruning_vlans=["10", "20", "30-40"],
911+
),
912+
),
913+
],
914+
state="replaced",
915+
),
916+
)
917+
commands = [
918+
"interface GigabitEthernet0/2",
919+
"switchport trunk encapsulation isl",
920+
"switchport trunk native vlan 20",
921+
"switchport trunk allowed vlan 60-70,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,153,"
922+
+ "155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205",
923+
"switchport trunk allowed vlan add 207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,257,259,"
924+
+ "261,263,265,267,269,271,273,275,277,279,281,283,285,287,289,291,293,295,297,299,301,303,305,307,309,311,313,315",
925+
"switchport trunk allowed vlan add 317,319,321,323,325,327,329,331,333,335,337,339,341,343,345,347,349,351,353,355,357,359,361,363,365,367,369,"
926+
+ "371,373,375,377,379,381,383,385,387,389,391,393,395,397,399,401,403,405,407,409,411,413,415,417,419,421,423,425",
927+
"switchport trunk allowed vlan add 427,429,431,433,435,437,439,441,443,445,447,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477,479,"
928+
+ "481,483,485,487,489,491,493,495,497,499",
929+
"switchport trunk pruning vlan add 30-40",
930+
]
931+
result = self.execute_module(changed=True)
932+
self.maxDiff = None
933+
self.assertEqual(result["commands"], commands)
934+
935+
def test_ios_l2_interfaces_trunk_multiline_overridden(self):
936+
self.execute_show_command.return_value = dedent(
937+
"""\
938+
interface GigabitEthernet0/2
939+
switchport trunk allowed vlan 10-20,40
940+
switchport trunk encapsulation dot1q
941+
switchport trunk native vlan 10
942+
switchport trunk pruning vlan 10,20
943+
switchport mode trunk
944+
""",
945+
)
946+
set_module_args(
947+
dict(
948+
config=[
949+
dict(
950+
mode="trunk",
951+
name="GigabitEthernet0/2",
952+
trunk=dict(
953+
allowed_vlans=["60-70"] + [str(vlan) for vlan in range(101, 500, 2)],
954+
encapsulation="isl",
955+
native_vlan=20,
956+
pruning_vlans=["10", "20", "30-40"],
957+
),
958+
),
959+
],
960+
state="overridden",
961+
),
962+
)
963+
commands = [
964+
"interface GigabitEthernet0/2",
965+
"switchport trunk encapsulation isl",
966+
"switchport trunk native vlan 20",
967+
"switchport trunk allowed vlan remove 10-20,40",
968+
"switchport trunk allowed vlan add 60-70,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149,151,"
969+
+ "153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205",
970+
"switchport trunk allowed vlan add 207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,255,257,259,"
971+
+ "261,263,265,267,269,271,273,275,277,279,281,283,285,287,289,291,293,295,297,299,301,303,305,307,309,311,313,315",
972+
"switchport trunk allowed vlan add 317,319,321,323,325,327,329,331,333,335,337,339,341,343,345,347,349,351,353,355,357,359,361,363,365,367,369,"
973+
+ "371,373,375,377,379,381,383,385,387,389,391,393,395,397,399,401,403,405,407,409,411,413,415,417,419,421,423,425",
974+
"switchport trunk allowed vlan add 427,429,431,433,435,437,439,441,443,445,447,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477,479,"
975+
+ "481,483,485,487,489,491,493,495,497,499",
976+
"switchport trunk pruning vlan add 30-40",
977+
]
978+
result = self.execute_module(changed=True)
979+
self.maxDiff = None
980+
self.assertEqual(result["commands"], commands)

0 commit comments

Comments
 (0)