Skip to content

Commit d44e47b

Browse files
gmuloccarl-baillargeonpre-commit-ci[bot]
authored
Feat(eos_designs): Add a future knob to raise when a L3 port-channel is configured without members (#6707)
Co-authored-by: Carl Baillargeon <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent e758012 commit d44e47b

9 files changed

Lines changed: 88 additions & 7 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
avd_design_future:
3+
raise_for_port_channels_without_members: true
4+
5+
type: l3leaf
6+
l3leaf:
7+
nodes:
8+
- bgp_as: 65000
9+
name: l3-port-channel-without-member-interfaces
10+
id: 1
11+
loopback_ipv4_pool: 192.168.0.0/24
12+
vtep_loopback_ipv4_pool: 192.168.1.0/24
13+
l3_port_channels:
14+
# No member interfaces
15+
- name: Port-Channel5
16+
ip_address: 172.16.0.2/30
17+
18+
expected_error_message: >-
19+
L3 Port-Channel 'Port-Channel5' must have at least one member interface defined.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
avd_design_future:
3+
raise_for_port_channels_without_members: true
4+
5+
type: l3leaf
6+
l3leaf:
7+
nodes:
8+
- bgp_as: 65000
9+
name: net-srv-l3-po-without-member-interfaces
10+
id: 1
11+
loopback_ipv4_pool: 192.168.0.0/24
12+
vtep_loopback_ipv4_pool: 192.168.1.0/24
13+
14+
tenants:
15+
- name: TENANT1
16+
vrfs:
17+
- name: VRF1
18+
l3_port_channels:
19+
# No member interfaces
20+
- name: Port-Channel10
21+
node: net-srv-l3-po-without-member-interfaces
22+
ip_address: 10.0.0.1/30
23+
24+
expected_error_message: >-
25+
L3 Port-Channel 'Port-Channel10' must have at least one member interface defined.

ansible_collections/arista/avd/extensions/molecule/eos_designs_negative_unit_tests/inventory/hosts.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ all:
354354
l3-port-channel-no-ip-address-subif:
355355
l3-port-channel-sub-interface-with-member-interfaces:
356356
l3-port-channel-sub-interface-with-mode:
357+
l3-port-channel-without-member-interfaces:
357358
management-eapi-vrf-name-use-inband-mgmt-vrf:
358359
missing-application-classification-application-profile:
359360
missing-application-classification-category:
@@ -439,6 +440,7 @@ all:
439440
net-srv-l3-po-sub-interface-with-mtu:
440441
net-srv-l3-po-sub-interface-without-ip:
441442
net-srv-l3-po-sub-interface-without-main-po:
443+
net-srv-l3-po-without-member-interfaces:
442444
network-services-l2vlan-pvlan-missing-primary:
443445
network-services-l2vlan-pvlan-platform-disabled:
444446
ntp-settings-server-vrf-missing-inband-mgmt-interface:

ansible_collections/arista/avd/roles/eos_designs/docs/tables/avd-design-future.md

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python-avd/pyavd/_eos_designs/schema/__init__.py

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python-avd/pyavd/_eos_designs/schema/schema_fragments/avd_design_future.schema.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,8 @@ keys:
1616
description: |-
1717
Deactivate the IPv4 unicast Address Family for BGP Peer Groups only when IPv4 is activated by default instead of always deactivating it.
1818
default: false
19+
raise_for_port_channels_without_members:
20+
type: bool
21+
description: |-
22+
Raise an error if an L3 Port-Channel is configured without any member interfaces.
23+
default: false

python-avd/pyavd/_eos_designs/structured_config/network_services/port_channel_interfaces.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,8 @@ def _set_l3_port_channels(
5555
"""
5656
for vrf in tenant.vrfs:
5757
for l3_port_channel in vrf.l3_port_channels:
58-
is_subinterface = "." in l3_port_channel.name
59-
60-
# Validation for l3_port_channel subinterface
61-
if is_subinterface:
58+
if is_subinterface := "." in l3_port_channel.name:
59+
# Validation for l3_port_channel subinterface
6260
if l3_port_channel.member_interfaces:
6361
msg = f"L3 Port-Channel sub-interface '{l3_port_channel.name}' has 'member_interfaces' set. This is not a valid setting."
6462
raise AristaAvdInvalidInputsError(msg)
@@ -70,6 +68,10 @@ def _set_l3_port_channels(
7068
# implies 'mtu' is set when not applicable for a sub-interface
7169
msg = f"L3 Port-Channel sub-interface '{l3_port_channel.name}' has 'mtu' set. This is not a valid setting."
7270
raise AristaAvdInvalidInputsError(msg)
71+
elif self.inputs.avd_design_future.raise_for_port_channels_without_members and not l3_port_channel.member_interfaces:
72+
# Validation: Non-subinterface port-channels must have at least one member interface
73+
msg = f"L3 Port-Channel '{l3_port_channel.name}' must have at least one member interface defined."
74+
raise AristaAvdInvalidInputsError(msg)
7375

7476
if not (interface_description := l3_port_channel.description):
7577
interface_description = "_".join(filter(None, [l3_port_channel.peer, l3_port_channel.peer_port_channel]))

python-avd/pyavd/_eos_designs/structured_config/underlay/port_channel_interfaces.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,19 @@ def _set_l3_port_channel(
124124
self: AvdStructuredConfigUnderlayProtocol, l3_port_channel: EosDesigns._DynamicKeys.DynamicNodeTypesItem.NodeTypes.NodesItem.L3PortChannelsItem
125125
) -> None:
126126
"""Set structured_configuration for one L3 Port-Channel."""
127-
# Validation for l3_port_channel subinterface
128127
if "." in l3_port_channel.name:
128+
# Validation for l3_port_channel subinterface
129129
if l3_port_channel.member_interfaces:
130130
msg = f"L3 Port-Channel sub-interface '{l3_port_channel.name}' has 'member_interfaces' set. This is not a valid setting."
131131
raise AristaAvdInvalidInputsError(msg)
132132
if l3_port_channel._get("mode"):
133133
# Implies 'mode' is set when not applicable for a sub-interface.
134134
msg = f"L3 Port-Channel sub-interface '{l3_port_channel.name}' has 'mode' set. This is not a valid setting."
135135
raise AristaAvdInvalidInputsError(msg)
136+
# Validation: Non-subinterface port-channels must have at least one member interface
137+
elif self.inputs.avd_design_future.raise_for_port_channels_without_members and not l3_port_channel.member_interfaces:
138+
msg = f"L3 Port-Channel '{l3_port_channel.name}' must have at least one member interface defined."
139+
raise AristaAvdInvalidInputsError(msg)
136140

137141
# build common portion of the interface cfg
138142
interface = self._get_l3_common_interface_cfg(l3_port_channel)

0 commit comments

Comments
 (0)