mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-15 12:08:17 -06:00
Rewrite trace for nested MUXes
This commit is contained in:
parent
c17a6f4184
commit
5014217052
@ -296,3 +296,9 @@ class CircuitTermination(CableTermination):
|
|||||||
return CircuitTermination.objects.prefetch_related('site').get(circuit=self.circuit, term_side=peer_side)
|
return CircuitTermination.objects.prefetch_related('site').get(circuit=self.circuit, term_side=peer_side)
|
||||||
except CircuitTermination.DoesNotExist:
|
except CircuitTermination.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_peer_port(self):
|
||||||
|
peer_termination = self.get_peer_termination()
|
||||||
|
if peer_termination is None:
|
||||||
|
return None
|
||||||
|
return peer_termination
|
||||||
|
@ -74,7 +74,7 @@ class CableTraceMixin(object):
|
|||||||
# Initialize the path array
|
# Initialize the path array
|
||||||
path = []
|
path = []
|
||||||
|
|
||||||
for near_end, cable, far_end in obj.trace(follow_circuits=True):
|
for near_end, cable, far_end in obj.trace():
|
||||||
|
|
||||||
# Serialize each object
|
# Serialize each object
|
||||||
serializer_a = get_serializer_for_model(near_end, prefix='Nested')
|
serializer_a = get_serializer_for_model(near_end, prefix='Nested')
|
||||||
|
@ -101,7 +101,10 @@ class CableTermination(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def trace(self, position=1, follow_circuits=False, cable_history=None):
|
def get_peer_port(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def trace(self, cable_history=None):
|
||||||
"""
|
"""
|
||||||
Return a list representing a complete cable path, with each individual segment represented as a three-tuple:
|
Return a list representing a complete cable path, with each individual segment represented as a three-tuple:
|
||||||
[
|
[
|
||||||
@ -110,39 +113,6 @@ class CableTermination(models.Model):
|
|||||||
(termination E, cable, termination F)
|
(termination E, cable, termination F)
|
||||||
]
|
]
|
||||||
"""
|
"""
|
||||||
def get_peer_port(termination, position=1, follow_circuits=False):
|
|
||||||
from circuits.models import CircuitTermination
|
|
||||||
|
|
||||||
# Map a front port to its corresponding rear port
|
|
||||||
if isinstance(termination, FrontPort):
|
|
||||||
return termination.rear_port, termination.rear_port_position
|
|
||||||
|
|
||||||
# Map a rear port/position to its corresponding front port
|
|
||||||
elif isinstance(termination, RearPort):
|
|
||||||
if position not in range(1, termination.positions + 1):
|
|
||||||
raise Exception("Invalid position for {} ({} positions): {})".format(
|
|
||||||
termination, termination.positions, position
|
|
||||||
))
|
|
||||||
try:
|
|
||||||
peer_port = FrontPort.objects.get(
|
|
||||||
rear_port=termination,
|
|
||||||
rear_port_position=position,
|
|
||||||
)
|
|
||||||
return peer_port, 1
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
# Follow a circuit to its other termination
|
|
||||||
elif isinstance(termination, CircuitTermination) and follow_circuits:
|
|
||||||
peer_termination = termination.get_peer_termination()
|
|
||||||
if peer_termination is None:
|
|
||||||
return None, None
|
|
||||||
return peer_termination, position
|
|
||||||
|
|
||||||
# Termination is not a pass-through port
|
|
||||||
else:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
if not self.cable:
|
if not self.cable:
|
||||||
return [(self, None, None)]
|
return [(self, None, None)]
|
||||||
|
|
||||||
@ -153,22 +123,33 @@ class CableTermination(models.Model):
|
|||||||
raise LoopDetected()
|
raise LoopDetected()
|
||||||
cable_history.append(self.cable)
|
cable_history.append(self.cable)
|
||||||
|
|
||||||
far_end = self.cable.termination_b if self.cable.termination_a == self else self.cable.termination_a
|
far_end = self.cable.termination_b if self._cabled_as_a.exists() else self.cable.termination_a
|
||||||
path = [(self, self.cable, far_end)]
|
path = [(self, self.cable, far_end)]
|
||||||
|
|
||||||
peer_port, position = get_peer_port(far_end, position, follow_circuits)
|
peer_port = far_end.get_peer_port()
|
||||||
if peer_port is None:
|
|
||||||
|
if isinstance(far_end, RearPort) and far_end.positions > 1:
|
||||||
|
# We don't want to start tracing from a front port here, that is handled separately (see below)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
try:
|
while peer_port:
|
||||||
next_segment = peer_port.trace(position, follow_circuits, cable_history)
|
path += peer_port.trace(cable_history)
|
||||||
except LoopDetected:
|
|
||||||
return path
|
|
||||||
|
|
||||||
if next_segment is None:
|
if isinstance(far_end, FrontPort) and isinstance(peer_port, RearPort) and peer_port.positions > 1:
|
||||||
return path + [(peer_port, None, None)]
|
# Trace the rear port separately, then continue with the corresponding front port
|
||||||
|
saved_rear_port_position = far_end.rear_port_position
|
||||||
|
|
||||||
return path + next_segment
|
far_end = path[-1][2]
|
||||||
|
peer_port = None
|
||||||
|
if isinstance(far_end, RearPort):
|
||||||
|
# The trace ends with a rear port, find the corresponding front port
|
||||||
|
peer_port = far_end.get_peer_port(saved_rear_port_position)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Everything else has already been handled by simple recursion
|
||||||
|
peer_port = None
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
||||||
def get_cable_peer(self):
|
def get_cable_peer(self):
|
||||||
if self.cable is None:
|
if self.cable is None:
|
||||||
@ -2471,6 +2452,9 @@ class FrontPort(CableTermination, ComponentModel):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_peer_port(self):
|
||||||
|
return self.rear_port
|
||||||
|
|
||||||
|
|
||||||
class RearPort(CableTermination, ComponentModel):
|
class RearPort(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
@ -2513,6 +2497,21 @@ class RearPort(CableTermination, ComponentModel):
|
|||||||
self.description,
|
self.description,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_peer_port(self, position=1):
|
||||||
|
if position not in range(1, self.positions + 1):
|
||||||
|
raise Exception("Invalid position for {} ({} positions): {})".format(
|
||||||
|
self, self.positions, position
|
||||||
|
))
|
||||||
|
|
||||||
|
try:
|
||||||
|
peer_port = FrontPort.objects.get(
|
||||||
|
rear_port=self,
|
||||||
|
rear_port_position=position,
|
||||||
|
)
|
||||||
|
return peer_port
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Device bays
|
# Device bays
|
||||||
@ -2853,14 +2852,15 @@ class Cable(ChangeLoggedModel):
|
|||||||
))
|
))
|
||||||
|
|
||||||
# A component with multiple positions must be connected to a component with an equal number of positions
|
# A component with multiple positions must be connected to a component with an equal number of positions
|
||||||
term_a_positions = getattr(self.termination_a, 'positions', 1)
|
# FIXME SJMS not really, they can be connected through a chain of links
|
||||||
term_b_positions = getattr(self.termination_b, 'positions', 1)
|
# term_a_positions = getattr(self.termination_a, 'positions', 1)
|
||||||
if term_a_positions != term_b_positions:
|
# term_b_positions = getattr(self.termination_b, 'positions', 1)
|
||||||
raise ValidationError(
|
# if term_a_positions != term_b_positions:
|
||||||
"{} has {} positions and {} has {}. Both terminations must have the same number of positions.".format(
|
# raise ValidationError(
|
||||||
self.termination_a, term_a_positions, self.termination_b, term_b_positions
|
# "{} has {} positions and {} has {}. Both terminations must have the same number of positions.".format(
|
||||||
)
|
# self.termination_a, term_a_positions, self.termination_b, term_b_positions
|
||||||
)
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
# A termination point cannot be connected to itself
|
# A termination point cannot be connected to itself
|
||||||
if self.termination_a == self.termination_b:
|
if self.termination_a == self.termination_b:
|
||||||
|
@ -1752,7 +1752,7 @@ class CableTraceView(PermissionRequiredMixin, View):
|
|||||||
|
|
||||||
return render(request, 'dcim/cable_trace.html', {
|
return render(request, 'dcim/cable_trace.html', {
|
||||||
'obj': obj,
|
'obj': obj,
|
||||||
'trace': obj.trace(follow_circuits=True),
|
'trace': obj.trace(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user