mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 03:27:21 -06:00
First stab at cable path tracing and automatic endpoint connections
This commit is contained in:
parent
47c523a40b
commit
35f80f5085
@ -2372,9 +2372,49 @@ class Cable(ChangeLoggedModel):
|
|||||||
('termination_b_type', 'termination_b_id'),
|
('termination_b_type', 'termination_b_id'),
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: This should follow all cables in a path
|
|
||||||
def get_path_endpoints(self):
|
def get_path_endpoints(self):
|
||||||
"""
|
"""
|
||||||
Return the endpoints connected by this cable path.
|
Traverse both ends of a cable path and return its connected endpoints. Note that one or both endpoints may be
|
||||||
|
None.
|
||||||
"""
|
"""
|
||||||
return (self.termination_a, self.termination_b)
|
def trace_cable(termination, position=None):
|
||||||
|
|
||||||
|
# Given a front port, follow the cable connected to the corresponding rear port/position
|
||||||
|
if isinstance(termination, FrontPanelPort):
|
||||||
|
rear_port = termination.rear_port
|
||||||
|
port_type = ContentType.objects.get_for_model(rear_port)
|
||||||
|
next_cable = Cable.objects.filter(
|
||||||
|
Q(termination_a_type=port_type, termination_a_id=rear_port.pk) |
|
||||||
|
Q(termination_b_type=port_type, termination_b_id=rear_port.pk)
|
||||||
|
).first()
|
||||||
|
if next_cable is None:
|
||||||
|
return None
|
||||||
|
if next_cable.termination_a == termination.rear_port:
|
||||||
|
return trace_cable(next_cable.termination_b, termination.rear_port_position)
|
||||||
|
else:
|
||||||
|
return trace_cable(next_cable.termination_a, termination.rear_port_position)
|
||||||
|
|
||||||
|
# Given a rear port/position, follow the cable connected to the corresponding front port
|
||||||
|
if isinstance(termination, RearPanelPort):
|
||||||
|
if position is None:
|
||||||
|
raise Exception("Must specify a position when tracing a path from a rear panel port")
|
||||||
|
front_port = FrontPanelPort.objects.get(
|
||||||
|
rear_port=termination,
|
||||||
|
rear_port_position=position,
|
||||||
|
)
|
||||||
|
port_type = ContentType.objects.get_for_model(front_port)
|
||||||
|
next_cable = Cable.objects.filter(
|
||||||
|
Q(termination_a_type=port_type, termination_a_id=front_port.pk) |
|
||||||
|
Q(termination_b_type=port_type, termination_b_id=front_port.pk)
|
||||||
|
).first()
|
||||||
|
if next_cable is None:
|
||||||
|
return None
|
||||||
|
if next_cable.termination_a == front_port:
|
||||||
|
return trace_cable(next_cable.termination_b)
|
||||||
|
else:
|
||||||
|
return trace_cable(next_cable.termination_a)
|
||||||
|
|
||||||
|
# Termination is not a panel port, so we've reached the end of the path
|
||||||
|
return termination
|
||||||
|
|
||||||
|
return trace_cable(self.termination_a), trace_cable(self.termination_b)
|
||||||
|
@ -27,10 +27,11 @@ def update_connected_endpoints(instance, **kwargs):
|
|||||||
When a Cable is saved, update its connected endpoints.
|
When a Cable is saved, update its connected endpoints.
|
||||||
"""
|
"""
|
||||||
termination_a, termination_b = instance.get_path_endpoints()
|
termination_a, termination_b = instance.get_path_endpoints()
|
||||||
termination_a.connected_endpoint = termination_b
|
if termination_a is not None and termination_b is not None:
|
||||||
termination_a.save()
|
termination_a.connected_endpoint = termination_b
|
||||||
termination_b.connected_endpoint = termination_a
|
termination_a.save()
|
||||||
termination_b.save()
|
termination_b.connected_endpoint = termination_a
|
||||||
|
termination_b.save()
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=Cable)
|
@receiver(post_delete, sender=Cable)
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
<i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:interface_connect' termination_a_id=device.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-success btn-xs" title="Connect">
|
<a href="{% url 'dcim:interface_connect' termination_a_id=iface.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-success btn-xs" title="Connect">
|
||||||
<i class="glyphicon glyphicon-resize-small" aria-hidden="true"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -212,6 +212,13 @@ class ObjectEditView(GetReturnURLMixin, View):
|
|||||||
obj_created = not form.instance.pk
|
obj_created = not form.instance.pk
|
||||||
obj = form.save()
|
obj = form.save()
|
||||||
|
|
||||||
|
print("Connecting {} {} to {} {}".format(
|
||||||
|
obj.termination_a.device,
|
||||||
|
obj.termination_a,
|
||||||
|
obj.termination_b.device,
|
||||||
|
obj.termination_b
|
||||||
|
))
|
||||||
|
|
||||||
msg = '{} {}'.format(
|
msg = '{} {}'.format(
|
||||||
'Created' if obj_created else 'Modified',
|
'Created' if obj_created else 'Modified',
|
||||||
self.model._meta.verbose_name
|
self.model._meta.verbose_name
|
||||||
|
Loading…
Reference in New Issue
Block a user