Show virtual circuit connections on interfaces

This commit is contained in:
Jeremy Stretch 2024-11-07 16:41:05 -05:00
parent 73b74d4ce8
commit 4426f47106
5 changed files with 82 additions and 1 deletions

View File

@ -1,3 +1,5 @@
from functools import cached_property
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
@ -139,3 +141,18 @@ class VirtualCircuitTermination(
@property
def parent_object(self):
return self.virtual_circuit
@cached_property
def peer_terminations(self):
if self.role == VirtualCircuitTerminationRoleChoices.ROLE_PEER:
return self.virtual_circuit.terminations.exclude(pk=self.pk).filter(
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER
)
if self.role == VirtualCircuitTerminationRoleChoices.ROLE_HUB:
return self.virtual_circuit.terminations.filter(
role=VirtualCircuitTerminationRoleChoices.ROLE_SPOKE
)
if self.role == VirtualCircuitTerminationRoleChoices.ROLE_SPOKE:
return self.virtual_circuit.terminations.filter(
role=VirtualCircuitTerminationRoleChoices.ROLE_HUB
)

View File

@ -980,6 +980,14 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd
def l2vpn_termination(self):
return self.l2vpn_terminations.first()
@cached_property
def connected_endpoints(self):
# If this is a virtual interface, return the remote endpoint of the connected
# virtual circuit, if any.
if self.is_virtual and hasattr(self, 'virtual_circuit_termination'):
return self.virtual_circuit_termination.peer_terminations
return super().connected_endpoints
#
# Pass-through ports

View File

@ -635,6 +635,14 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi
url_name='dcim:interface_list'
)
# Override PathEndpointTable.connection to accommodate virtual circuits
connection = columns.TemplateColumn(
accessor='_path__destinations',
template_code=INTERFACE_LINKTERMINATION,
verbose_name=_('Connection'),
orderable=False
)
class Meta(DeviceComponentTable.Meta):
model = models.Interface
fields = (

View File

@ -10,6 +10,20 @@ LINKTERMINATION = """
{% endfor %}
"""
INTERFACE_LINKTERMINATION = """
{% load i18n %}
{% if record.is_virtual and record.virtual_circuit_termination %}
{% for termination in record.connected_endpoints %}
<a href="{{ termination.interface.parent_object.get_absolute_url }}">{{ termination.interface.parent_object }}</a>
<i class="mdi mdi-chevron-right"></i>
<a href="{{ termination.interface.get_absolute_url }}">{{ termination.interface }}</a>
{% trans "via" %}
<a href="{{ termination.parent_object.get_absolute_url }}">{{ termination.parent_object }}</a>
{% if not forloop.last %}<br />{% endif %}
{% endfor %}
{% else %}""" + LINKTERMINATION + """{% endif %}
"""
CABLE_LENGTH = """
{% load helpers %}
{% if record.length %}{{ record.length|floatformat:"-2" }} {{ record.length_unit }}{% endif %}

View File

@ -139,7 +139,41 @@
</tr>
</table>
</div>
{% if not object.is_virtual %}
{% if object.is_virtual and object.virtual_circuit_termination %}
<div class="card">
<h2 class="card-header">{% trans "Virtual Circuit" %}</h2>
<table class="table table-hover attr-table">
<tr>
<th scope="row">{% trans "Provider" %}</th>
<td>{{ object.virtual_circuit_termination.virtual_circuit.provider|linkify }}</td>
</tr>
<tr>
<th scope="row">{% trans "Provider Network" %}</th>
<td>{{ object.virtual_circuit_termination.virtual_circuit.provider_network|linkify }}</td>
</tr>
<tr>
<th scope="row">{% trans "Circuit ID" %}</th>
<td>{{ object.virtual_circuit_termination.virtual_circuit|linkify }}</td>
</tr>
<tr>
<th scope="row">{% trans "Role" %}</th>
<td>{{ object.virtual_circuit_termination.get_role_display }}</td>
</tr>
<tr>
<th scope="row">{% trans "Connections" %}</th>
<td>
{% for termination in object.virtual_circuit_termination.peer_terminations %}
<a href="{{ termination.interface.parent_object.get_absolute_url }}">{{ termination.interface.parent_object }}</a>
<i class="mdi mdi-chevron-right"></i>
<a href="{{ termination.interface.get_absolute_url }}">{{ termination.interface }}</a>
({{ termination.get_role_display }})
{% if not forloop.last %}<br />{% endif %}
{% endfor %}
</td>
</tr>
</table>
</div>
{% elif not object.is_virtual %}
<div class="card">
<h2 class="card-header">{% trans "Connection" %}</h2>
{% if object.mark_connected %}