1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Fixes #9778: Fix exception during cable deletion after deleting a connected termination

This commit is contained in:
jeremystretch
2022-08-03 12:46:16 -04:00
parent b9678c7c0e
commit 367bf25618
6 changed files with 26 additions and 16 deletions

View File

@ -104,6 +104,7 @@ Custom field UI visibility has no impact on API operation.
* [#9730](https://github.com/netbox-community/netbox/issues/9730) - Fix validation error when creating a new cable via UI form
* [#9733](https://github.com/netbox-community/netbox/issues/9733) - Handle split paths during trace when fanning out to front ports with differing cables
* [#9765](https://github.com/netbox-community/netbox/issues/9765) - Report correct segment count under cable trace UI view
* [#9778](https://github.com/netbox-community/netbox/issues/9778) - Fix exception during cable deletion after deleting a connected termination
* [#9788](https://github.com/netbox-community/netbox/issues/9788) - Ensure denormalized fields on CableTermination are kept in sync with related objects
* [#9789](https://github.com/netbox-community/netbox/issues/9789) - Fix rendering of cable traces ending at provider networks
* [#9794](https://github.com/netbox-community/netbox/issues/9794) - Fix link to connect a rear port to a circuit termination

View File

@ -431,11 +431,7 @@ class CablePath(models.Model):
"""
Return the list of originating objects.
"""
if hasattr(self, '_path_objects'):
return self.path_objects[0]
return [
path_node_to_object(node) for node in self.path[0]
]
return self.path_objects[0]
@property
def destinations(self):
@ -444,11 +440,7 @@ class CablePath(models.Model):
"""
if not self.is_complete:
return []
if hasattr(self, '_path_objects'):
return self.path_objects[-1]
return [
path_node_to_object(node) for node in self.path[-1]
]
return self.path_objects[-1]
@property
def segment_count(self):
@ -463,6 +455,9 @@ class CablePath(models.Model):
"""
from circuits.models import CircuitTermination
if not terminations:
return None
# Ensure all originating terminations are attached to the same link
if len(terminations) > 1:
assert all(t.link == terminations[0].link for t in terminations[1:])
@ -529,6 +524,9 @@ class CablePath(models.Model):
])
# Step 6: Determine the "next hop" terminations, if applicable
if not remote_terminations:
break
if isinstance(remote_terminations[0], FrontPort):
# Follow FrontPorts to their corresponding RearPorts
rear_ports = RearPort.objects.filter(
@ -640,7 +638,11 @@ class CablePath(models.Model):
nodes = []
for node in step:
ct_id, object_id = decompile_path_node(node)
nodes.append(prefetched[ct_id][object_id])
try:
nodes.append(prefetched[ct_id][object_id])
except KeyError:
# Ignore stale (deleted) object IDs
pass
path.append(nodes)
return path

View File

@ -116,7 +116,10 @@ def retrace_cable_paths(instance, **kwargs):
@receiver(post_delete, sender=CableTermination)
def nullify_connected_endpoints(instance, **kwargs):
"""
Disassociate the Cable from the termination object.
Disassociate the Cable from the termination object, and retrace any affected CablePaths.
"""
model = instance.termination_type.model_class()
model.objects.filter(pk=instance.termination_id).update(cable=None, cable_end='')
for cablepath in CablePath.objects.filter(_nodes__contains=instance.cable):
cablepath.retrace()

View File

@ -362,8 +362,11 @@ class CableTraceSVG:
terminations = self.draw_terminations(far_ends)
for term in terminations:
self.draw_fanout(term, cable)
else:
elif far_ends:
self.draw_terminations(far_ends)
else:
# Link is not connected to anything
break
# Far end parent
parent_objects = set(end.parent_object for end in far_ends)

View File

@ -24,11 +24,12 @@ def object_to_path_node(obj):
def path_node_to_object(repr):
"""
Given the string representation of a path node, return the corresponding instance.
Given the string representation of a path node, return the corresponding instance. If the object no longer
exists, return None.
"""
ct_id, object_id = decompile_path_node(repr)
ct = ContentType.objects.get_for_id(ct_id)
return ct.model_class().objects.get(pk=object_id)
return ct.model_class().objects.filter(pk=object_id).first()
def create_cablepath(terminations):

View File

@ -219,7 +219,7 @@
<tr>
<th scope="row">Path Status</th>
<td>
{% if object.path.is_active %}
{% if object.path.is_complete and object.path.is_active %}
<span class="badge bg-success">Reachable</span>
{% else %}
<span class="badge bg-danger">Not Reachable</span>