mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 04:22:01 -06:00
Adapt tracing view to account for split ends (WIP)
This commit is contained in:
parent
5205c4963f
commit
29707cd496
@ -48,7 +48,7 @@ class CableTraceMixin(object):
|
||||
# Initialize the path array
|
||||
path = []
|
||||
|
||||
for near_end, cable, far_end in obj.trace():
|
||||
for near_end, cable, far_end in obj.trace()[0]:
|
||||
|
||||
# Serialize each object
|
||||
serializer_a = get_serializer_for_model(near_end, prefix='Nested')
|
||||
|
@ -92,7 +92,13 @@ class CableTermination(models.Model):
|
||||
|
||||
def trace(self):
|
||||
"""
|
||||
Return a list representing a complete cable path, with each individual segment represented as a three-tuple:
|
||||
Return two items: the traceable portion of a cable path, and the termination points where it splits (if any).
|
||||
This occurs when the trace is initiated from a midpoint along a path which traverses a RearPort. In cases where
|
||||
the originating endpoint is unknown, it is not possible to know which corresponding FrontPort to follow.
|
||||
|
||||
The path is a list representing a complete cable path, with each individual segment represented as a
|
||||
three-tuple:
|
||||
|
||||
[
|
||||
(termination A, cable, termination B),
|
||||
(termination C, cable, termination D),
|
||||
@ -157,12 +163,12 @@ class CableTermination(models.Model):
|
||||
if not endpoint.cable:
|
||||
path.append((endpoint, None, None))
|
||||
logger.debug("No cable connected")
|
||||
return path
|
||||
return path, None
|
||||
|
||||
# Check for loops
|
||||
if endpoint.cable in [segment[1] for segment in path]:
|
||||
logger.debug("Loop detected!")
|
||||
return path
|
||||
return path, None
|
||||
|
||||
# Record the current segment in the path
|
||||
far_end = endpoint.get_cable_peer()
|
||||
@ -172,9 +178,13 @@ class CableTermination(models.Model):
|
||||
))
|
||||
|
||||
# Get the peer port of the far end termination
|
||||
endpoint = get_peer_port(far_end)
|
||||
try:
|
||||
endpoint = get_peer_port(far_end)
|
||||
except CableTraceSplit as e:
|
||||
return path, e.termination.frontports.all()
|
||||
|
||||
if endpoint is None:
|
||||
return path
|
||||
return path, None
|
||||
|
||||
def get_cable_peer(self):
|
||||
if self.cable is None:
|
||||
@ -191,15 +201,13 @@ class CableTermination(models.Model):
|
||||
endpoints = []
|
||||
|
||||
# Get the far end of the last path segment
|
||||
try:
|
||||
endpoint = self.trace()[-1][2]
|
||||
if endpoint is not None:
|
||||
endpoints.append(endpoint)
|
||||
|
||||
# We've hit a RearPort mapped to multiple FrontPorts. Recurse to trace each of them individually.
|
||||
except CableTraceSplit as e:
|
||||
for frontport in e.termination.frontports.all():
|
||||
endpoints.extend(frontport.get_path_endpoints())
|
||||
path, split_ends = self.trace()
|
||||
endpoint = path[-1][2]
|
||||
if split_ends is not None:
|
||||
for termination in split_ends:
|
||||
endpoints.extend(termination.get_path_endpoints())
|
||||
elif endpoint is not None:
|
||||
endpoints.append(endpoint)
|
||||
|
||||
return endpoints
|
||||
|
||||
|
@ -52,7 +52,7 @@ def update_connected_endpoints(instance, **kwargs):
|
||||
# Update any endpoints for this Cable.
|
||||
endpoints = instance.termination_a.get_path_endpoints() + instance.termination_b.get_path_endpoints()
|
||||
for endpoint in endpoints:
|
||||
path = endpoint.trace()
|
||||
path, split_ends = endpoint.trace()
|
||||
# Determine overall path status (connected or planned)
|
||||
path_status = True
|
||||
for segment in path:
|
||||
|
@ -32,6 +32,7 @@ from virtualization.models import VirtualMachine
|
||||
from . import filters, forms, tables
|
||||
from .choices import DeviceFaceChoices
|
||||
from .constants import NONCONNECTABLE_IFACE_TYPES
|
||||
from .exceptions import CableTraceSplit
|
||||
from .models import (
|
||||
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||
DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
|
||||
@ -2033,12 +2034,15 @@ class CableTraceView(PermissionRequiredMixin, View):
|
||||
def get(self, request, model, pk):
|
||||
|
||||
obj = get_object_or_404(model, pk=pk)
|
||||
trace = obj.trace()
|
||||
total_length = sum([entry[1]._abs_length for entry in trace if entry[1] and entry[1]._abs_length])
|
||||
path, split_ends = obj.trace()
|
||||
total_length = sum(
|
||||
[entry[1]._abs_length for entry in path if entry[1] and entry[1]._abs_length]
|
||||
)
|
||||
|
||||
return render(request, 'dcim/cable_trace.html', {
|
||||
'obj': obj,
|
||||
'trace': trace,
|
||||
'trace': path,
|
||||
'split_ends': split_ends,
|
||||
'total_length': total_length,
|
||||
})
|
||||
|
||||
|
@ -50,4 +50,19 @@
|
||||
</div>
|
||||
{% if not forloop.last %}<hr />{% endif %}
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="col-md-11 col-md-offset-1">
|
||||
{% if split_ends %}
|
||||
<h3 class="text-danger text-center"><i class="fa fa-warning"></i> Trace Split</h3>
|
||||
<p>Select a termination to continue:</p>
|
||||
<ul>
|
||||
{% for termination in split_ends %}
|
||||
<li><a href="{% url 'dcim:frontport_trace' pk=termination.pk %}">{{ termination.parent }} / {{ termination }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<h3 class="text-success text-center">Trace completed!</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
Loading…
Reference in New Issue
Block a user