Skip to content

Commit

Permalink
Fix the fix
Browse files Browse the repository at this point in the history
  • Loading branch information
ClausHolbechArista committed Feb 13, 2025
1 parent ea933f5 commit 1230ea8
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ interface Ethernet24
!
interface Ethernet51
no shutdown
switchport access vlan 123
channel-group 43 mode active
!
interface Ethernet52
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ interface Port-Channel101
interface Port-Channel222
description This should be the only one render and no vlan 666
no shutdown
switchport access vlan 666
switchport
mlag 222
!
Expand Down Expand Up @@ -580,6 +579,7 @@ interface Ethernet48
!
interface Ethernet51
shutdown
switchport access vlan 123
switchport
!
interface Ethernet52
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,8 @@ ethernet_interfaces:
id: 43
mode: active
peer_type: network_port
switchport:
access_vlan: 123
- name: Ethernet52
shutdown: false
channel_group:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@ ethernet_interfaces:
peer_type: network_port
switchport:
enabled: true
access_vlan: 123
- name: Ethernet52
shutdown: true
peer_type: network_port
Expand Down Expand Up @@ -765,7 +766,6 @@ port_channel_interfaces:
mlag: 222
switchport:
enabled: true
access_vlan: 666
service_routing_protocols_model: multi-agent
spanning_tree:
no_spanning_tree_vlan: '4094'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ network_ports:
structured_config:
description: This should be the only one render and no vlan 666

# Overwriting one interface from a range to ensure that we don't reuse objects in memory across multiple interfaces.
# We should only see updates for this interface.
custom_structured_configuration_ethernet_interfaces:
- name: Ethernet51
switchport:
access_vlan: 123

servers:
- name: CONNECTED_ENDPOINT_OVERWRITING_NETWORK_PORT
adapters:
Expand Down Expand Up @@ -261,6 +268,5 @@ custom_platform_settings:
reload_delay:
mlag: 300
non_mlag: 330
trident_forwarding_table_partition:
flexible exact-match 16000 l2-shared 18000 l3-shared
trident_forwarding_table_partition: flexible exact-match 16000 l2-shared 18000 l3-shared
22000
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,18 @@ def ethernet_interfaces(self: AvdStructuredConfigConnectedEndpointsProtocol) ->
if node_name != self.shared_utils.hostname:
continue

self.structured_config.ethernet_interfaces.append(self._get_ethernet_interface_cfg(adapter, node_index, connected_endpoint))

# Temporary list of ethernet interfaces to be added by network ports.
ethernet_interface, structured_config = self._get_ethernet_interface_cfg(adapter, node_index, connected_endpoint)
self.structured_config.ethernet_interfaces.append(ethernet_interface)
if structured_config:
self.custom_structured_configs.nested.ethernet_interfaces.obtain(ethernet_interface.name)._deepmerge(
structured_config, list_merge=self.custom_structured_configs.list_merge_strategy
)

# Temporary dict of ethernet interfaces to be added by network ports.
# We need this since network ports can override each other, so the last one "wins"
network_ports_ethernet_interfaces = EosCliConfigGen.EthernetInterfaces()
# Dict keyed by interface name. Value is a tuple of the interface config and any structured config for this interface.
network_ports_ethernet_interfaces: dict[str, tuple[EosCliConfigGen.EthernetInterfacesItem, EosCliConfigGen.EthernetInterfacesItem | None]] = {}

for network_port in self._filtered_network_ports:
connected_endpoint = EosDesigns._DynamicKeys.DynamicConnectedEndpointsItem.ConnectedEndpointsItem(name=network_port.endpoint or Undefined)
connected_endpoint._internal_data.type = "network_port"
Expand All @@ -65,19 +72,17 @@ def ethernet_interfaces(self: AvdStructuredConfigConnectedEndpointsProtocol) ->
network_port_as_adapter.switches = EosDesigns._DynamicKeys.DynamicConnectedEndpointsItem.ConnectedEndpointsItem.AdaptersItem.Switches(
[self.shared_utils.hostname]
)
# TODO: this fix is not enough as it only prevent the same objects to be reused in all the
# structured_config for network_port and it solves the initial issue
# but this does not prevent an aggregation of all the structured_configs which is not
# the correct behavior.
# Need to keep track of the "network_port" structured configs
network_port_as_adapter.structured_config = network_port.structured_config._deepcopy()
ethernet_interface = self._get_ethernet_interface_cfg(network_port_as_adapter, 0, connected_endpoint)

# Using __setitem__ to replace any previous network_port.
network_ports_ethernet_interfaces[ethernet_interface_name] = ethernet_interface

if network_ports_ethernet_interfaces:
self.structured_config.ethernet_interfaces.extend(network_ports_ethernet_interfaces)
network_ports_ethernet_interfaces[ethernet_interface_name] = self._get_ethernet_interface_cfg(network_port_as_adapter, 0, connected_endpoint)

# Now insert into the actual structured config and custom structured config
for ethernet_interface, structured_config in network_ports_ethernet_interfaces.values():
self.structured_config.ethernet_interfaces.append(ethernet_interface)
if structured_config:
self.custom_structured_configs.nested.ethernet_interfaces.obtain(ethernet_interface.name)._deepmerge(
structured_config, list_merge=self.custom_structured_configs.list_merge_strategy
)

def _update_ethernet_interface_cfg(
self: AvdStructuredConfigConnectedEndpointsProtocol,
Expand Down Expand Up @@ -128,7 +133,7 @@ def _get_ethernet_interface_cfg(
adapter: EosDesigns._DynamicKeys.DynamicConnectedEndpointsItem.ConnectedEndpointsItem.AdaptersItem,
node_index: int,
connected_endpoint: EosDesigns._DynamicKeys.DynamicConnectedEndpointsItem.ConnectedEndpointsItem,
) -> EosCliConfigGen.EthernetInterfacesItem:
) -> tuple[EosCliConfigGen.EthernetInterfacesItem, EosCliConfigGen.EthernetInterfacesItem | None]:
"""
Return structured configuration for one ethernet interface.
Expand All @@ -138,7 +143,8 @@ def _get_ethernet_interface_cfg(
connected_endpoint: The connected endpoint configuration item.
Returns:
The structured configuration for the ethernet interface.
The structured configuration for the ethernet interface
Any structured config
Raises:
AristaAvdError: If the lengths of the lists 'switches', 'switch_ports', and 'descriptions' (if used) do not match.
Expand Down Expand Up @@ -192,11 +198,6 @@ def _get_ethernet_interface_cfg(
eos_cli=adapter.raw_eos_cli,
)

if adapter.structured_config:
self.custom_structured_configs.nested.ethernet_interfaces.obtain(adapter.switch_ports[node_index])._deepmerge(
adapter.structured_config, list_merge=self.custom_structured_configs.list_merge_strategy
)

# Port-channel member
if adapter.port_channel.mode:
ethernet_interface.channel_group.id = channel_group_id
Expand Down Expand Up @@ -240,4 +241,4 @@ def _get_ethernet_interface_cfg(
if adapter.flowcontrol:
ethernet_interface.flowcontrol = adapter.flowcontrol

return ethernet_interface
return ethernet_interface, adapter.structured_config or None
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,15 @@ def port_channel_interfaces(self: AvdStructuredConfigConnectedEndpointsProtocol)
channel_group_id = adapter.port_channel.channel_id or default_channel_group_id

port_channel_interface_name = f"Port-Channel{channel_group_id}"
self.structured_config.port_channel_interfaces.append(
self._get_port_channel_interface_cfg(adapter, port_channel_interface_name, channel_group_id, connected_endpoint)

port_channel_interface, structured_config = self._get_port_channel_interface_cfg(
adapter, port_channel_interface_name, channel_group_id, connected_endpoint
)
self.structured_config.port_channel_interfaces.append(port_channel_interface)
if structured_config:
self.custom_structured_configs.nested.port_channel_interfaces.obtain(port_channel_interface.name)._deepmerge(
structured_config, list_merge=self.custom_structured_configs.list_merge_strategy
)

for subinterface in adapter.port_channel.subinterfaces:
if not subinterface.number:
Expand All @@ -61,9 +67,13 @@ def port_channel_interfaces(self: AvdStructuredConfigConnectedEndpointsProtocol)
)
)

# Temporary list of port-channel interfaces to be added by network ports.
# Temporary dict of port-channel interfaces to be added by network ports.
# We need this since network ports can override each other, so the last one "wins"
network_ports_port_channel_interfaces = EosCliConfigGen.PortChannelInterfaces()
# Dict keyed by interface name. Value is a tuple of the interface config and any structured config for this interface.
network_ports_port_channel_interfaces: dict[
str, tuple[EosCliConfigGen.PortChannelInterfacesItem, EosCliConfigGen.PortChannelInterfacesItem | None]
] = {}

for network_port in self._filtered_network_ports:
if not network_port.port_channel.mode:
continue
Expand All @@ -84,32 +94,47 @@ def port_channel_interfaces(self: AvdStructuredConfigConnectedEndpointsProtocol)
network_port_as_adapter.switches = EosDesigns._DynamicKeys.DynamicConnectedEndpointsItem.ConnectedEndpointsItem.AdaptersItem.Switches(
[self.shared_utils.hostname, ""]
)
# TODO: this is not enough cf the current test with structured_config from both ranges
network_port_as_adapter.port_channel.structured_config = network_port.port_channel.structured_config._deepcopy()

default_channel_group_id = int("".join(re.findall(r"\d", ethernet_interface_name)))
channel_group_id = network_port_as_adapter.port_channel.channel_id or default_channel_group_id

port_channel_interface_name = f"Port-Channel{channel_group_id}"

port_channel_interface = self._get_port_channel_interface_cfg(
# Using __setitem__ to replace any previous network_port.
network_ports_port_channel_interfaces[port_channel_interface_name] = self._get_port_channel_interface_cfg(
network_port_as_adapter, port_channel_interface_name, channel_group_id, connected_endpoint
)

# Using __setitem__ to replace any previous network_port.
network_ports_port_channel_interfaces[port_channel_interface_name] = port_channel_interface

if network_ports_port_channel_interfaces:
self.structured_config.port_channel_interfaces.extend(network_ports_port_channel_interfaces)
# Now insert into the actual structured config and custom structured config
for port_channel_interface, structured_config in network_ports_port_channel_interfaces.values():
self.structured_config.port_channel_interfaces.append(port_channel_interface)
if structured_config:
self.custom_structured_configs.nested.port_channel_interfaces.obtain(port_channel_interface.name)._deepmerge(
structured_config, list_merge=self.custom_structured_configs.list_merge_strategy
)

def _get_port_channel_interface_cfg(
self: AvdStructuredConfigConnectedEndpointsProtocol,
adapter: EosDesigns._DynamicKeys.DynamicConnectedEndpointsItem.ConnectedEndpointsItem.AdaptersItem,
port_channel_interface_name: str,
channel_group_id: int,
connected_endpoint: EosDesigns._DynamicKeys.DynamicConnectedEndpointsItem.ConnectedEndpointsItem,
) -> EosCliConfigGen.PortChannelInterfacesItem:
"""Return structured_config for one port_channel_interface."""
) -> tuple[EosCliConfigGen.PortChannelInterfacesItem, EosCliConfigGen.PortChannelInterfacesItem | None]:
"""
Return structured_config for one port_channel_interface.
Args:
adapter: The adapter item containing port-channel configuration.
port_channel_interface_name: The name of the port-channel interface.
channel_group_id: The channel group ID for the port-channel.
connected_endpoint: The connected endpoint item.
Returns:
The port-channel interface configuration
Any structured config
Raises:
AristaAvdInvalidInputsError: If the 'vlans' value is invalid for the given mode.
"""
peer = connected_endpoint.name
adapter_description = adapter.description
port_channel_description = adapter.port_channel.description
Expand Down Expand Up @@ -148,10 +173,6 @@ def _get_port_channel_interface_cfg(
validate_lldp=None if (adapter.validate_lldp if adapter.validate_lldp is not None else True) else False,
eos_cli=adapter.port_channel.raw_eos_cli,
)
if adapter.port_channel.structured_config:
self.custom_structured_configs.nested.port_channel_interfaces.obtain(port_channel_interface_name)._deepmerge(
adapter.port_channel.structured_config, list_merge=self.custom_structured_configs.list_merge_strategy
)

if adapter.port_channel.subinterfaces:
port_channel_interface.switchport.enabled = False
Expand Down Expand Up @@ -209,7 +230,7 @@ def _get_port_channel_interface_cfg(
port_channel_interface.lacp_fallback_mode = adapter.port_channel.lacp_fallback.mode
port_channel_interface.lacp_fallback_timeout = adapter.port_channel.lacp_fallback.timeout

return port_channel_interface
return port_channel_interface, adapter.port_channel.structured_config or None

def _get_port_channel_subinterface_cfg(
self: AvdStructuredConfigConnectedEndpointsProtocol,
Expand Down

0 comments on commit 1230ea8

Please sign in to comment.