mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 09:28:38 -06:00
Introduced CableTermination abstract model to ptovide Cable access from termination points
This commit is contained in:
parent
266429101b
commit
f134a6ec63
@ -16,7 +16,6 @@ from taggit.managers import TaggableManager
|
|||||||
from timezone_field import TimeZoneField
|
from timezone_field import TimeZoneField
|
||||||
|
|
||||||
from circuits.models import Circuit
|
from circuits.models import Circuit
|
||||||
from extras.constants import OBJECTCHANGE_ACTION_DELETE, OBJECTCHANGE_ACTION_UPDATE
|
|
||||||
from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange
|
from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange
|
||||||
from utilities.fields import ColorField, NullableCharField
|
from utilities.fields import ColorField, NullableCharField
|
||||||
from utilities.managers import NaturalOrderByManager
|
from utilities.managers import NaturalOrderByManager
|
||||||
@ -24,7 +23,7 @@ from utilities.models import ChangeLoggedModel
|
|||||||
from utilities.utils import serialize_object
|
from utilities.utils import serialize_object
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .fields import ASNField, MACAddressField
|
from .fields import ASNField, MACAddressField
|
||||||
from .querysets import InterfaceQuerySet
|
from .querysets import CableQuerySet, InterfaceQuerySet
|
||||||
|
|
||||||
|
|
||||||
class ComponentTemplateModel(models.Model):
|
class ComponentTemplateModel(models.Model):
|
||||||
@ -66,6 +65,22 @@ class ComponentModel(models.Model):
|
|||||||
).save()
|
).save()
|
||||||
|
|
||||||
|
|
||||||
|
class CableTermination(models.Model):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def get_connected_cable(self):
|
||||||
|
"""
|
||||||
|
Return the connected cable if one exists; else None. Assign the far end of the connection on the Cable instance.
|
||||||
|
"""
|
||||||
|
cable = Cable.objects.get_for_termination(self)
|
||||||
|
if cable is None:
|
||||||
|
return None
|
||||||
|
cable.far_end = cable.termination_b if cable.termination_a == self else cable.termination_a
|
||||||
|
return cable
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Regions
|
# Regions
|
||||||
#
|
#
|
||||||
@ -1603,7 +1618,7 @@ class Device(ChangeLoggedModel, ConfigContextModel, CustomFieldModel):
|
|||||||
# Console ports
|
# Console ports
|
||||||
#
|
#
|
||||||
|
|
||||||
class ConsolePort(ComponentModel):
|
class ConsolePort(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A physical console port within a Device. ConsolePorts connect to ConsoleServerPorts.
|
A physical console port within a Device. ConsolePorts connect to ConsoleServerPorts.
|
||||||
"""
|
"""
|
||||||
@ -1665,7 +1680,7 @@ class ConsoleServerPortManager(models.Manager):
|
|||||||
}).order_by('device', 'name_padded')
|
}).order_by('device', 'name_padded')
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPort(ComponentModel):
|
class ConsoleServerPort(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A physical port within a Device (typically a designated console server) which provides access to ConsolePorts.
|
A physical port within a Device (typically a designated console server) which provides access to ConsolePorts.
|
||||||
"""
|
"""
|
||||||
@ -1706,7 +1721,7 @@ class ConsoleServerPort(ComponentModel):
|
|||||||
# Power ports
|
# Power ports
|
||||||
#
|
#
|
||||||
|
|
||||||
class PowerPort(ComponentModel):
|
class PowerPort(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A physical power supply (intake) port within a Device. PowerPorts connect to PowerOutlets.
|
A physical power supply (intake) port within a Device. PowerPorts connect to PowerOutlets.
|
||||||
"""
|
"""
|
||||||
@ -1768,7 +1783,7 @@ class PowerOutletManager(models.Manager):
|
|||||||
}).order_by('device', 'name_padded')
|
}).order_by('device', 'name_padded')
|
||||||
|
|
||||||
|
|
||||||
class PowerOutlet(ComponentModel):
|
class PowerOutlet(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A physical power outlet (output) within a Device which provides power to a PowerPort.
|
A physical power outlet (output) within a Device which provides power to a PowerPort.
|
||||||
"""
|
"""
|
||||||
@ -1809,7 +1824,7 @@ class PowerOutlet(ComponentModel):
|
|||||||
# Interfaces
|
# Interfaces
|
||||||
#
|
#
|
||||||
|
|
||||||
class Interface(ComponentModel):
|
class Interface(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A network interface within a Device or VirtualMachine. A physical Interface can connect to exactly one other
|
A network interface within a Device or VirtualMachine. A physical Interface can connect to exactly one other
|
||||||
Interface.
|
Interface.
|
||||||
@ -2035,7 +2050,7 @@ class Interface(ComponentModel):
|
|||||||
# Pass-through ports
|
# Pass-through ports
|
||||||
#
|
#
|
||||||
|
|
||||||
class FrontPort(ComponentModel):
|
class FrontPort(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A pass-through port on the front of a Device.
|
A pass-through port on the front of a Device.
|
||||||
"""
|
"""
|
||||||
@ -2089,7 +2104,7 @@ class FrontPort(ComponentModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RearPort(ComponentModel):
|
class RearPort(CableTermination, ComponentModel):
|
||||||
"""
|
"""
|
||||||
A pass-through port on the rear of a Device.
|
A pass-through port on the rear of a Device.
|
||||||
"""
|
"""
|
||||||
@ -2352,12 +2367,19 @@ class Cable(ChangeLoggedModel):
|
|||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = CableQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = (
|
unique_together = (
|
||||||
('termination_a_type', 'termination_a_id'),
|
('termination_a_type', 'termination_a_id'),
|
||||||
('termination_b_type', 'termination_b_id'),
|
('termination_b_type', 'termination_b_id'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.label:
|
||||||
|
return '{} (#{})'.format(self.label, self.pk)
|
||||||
|
return '#{}'.format(self.pk)
|
||||||
|
|
||||||
def get_path_endpoints(self):
|
def get_path_endpoints(self):
|
||||||
"""
|
"""
|
||||||
Traverse both ends of a cable path and return its connected endpoints. Note that one or both endpoints may be
|
Traverse both ends of a cable path and return its connected endpoints. Note that one or both endpoints may be
|
||||||
@ -2387,20 +2409,13 @@ class Cable(ChangeLoggedModel):
|
|||||||
return termination
|
return termination
|
||||||
|
|
||||||
# Find the cable (if any) attached to the peer port
|
# Find the cable (if any) attached to the peer port
|
||||||
port_type = ContentType.objects.get_for_model(peer_port)
|
next_cable, far_end = peer_port.get_connection()
|
||||||
next_cable = Cable.objects.filter(
|
|
||||||
Q(termination_a_type=port_type, termination_a_id=peer_port.pk) |
|
|
||||||
Q(termination_b_type=port_type, termination_b_id=peer_port.pk)
|
|
||||||
).first()
|
|
||||||
|
|
||||||
# If no cable exists, return None
|
# If no cable exists, return None
|
||||||
if next_cable is None:
|
if next_cable is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Return the far side termination of the cable
|
# Return the far side termination of the cable
|
||||||
if next_cable.termination_a == peer_port:
|
return trace_cable(far_end, position)
|
||||||
return trace_cable(next_cable.termination_b, position)
|
|
||||||
else:
|
|
||||||
return trace_cable(next_cable.termination_a, position)
|
|
||||||
|
|
||||||
return trace_cable(self.termination_a), trace_cable(self.termination_b)
|
return trace_cable(self.termination_a), trace_cable(self.termination_b)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from django.db.models import QuerySet
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.db.models import Q, QuerySet
|
||||||
from django.db.models.expressions import RawSQL
|
from django.db.models.expressions import RawSQL
|
||||||
|
|
||||||
from .constants import IFACE_ORDERING_NAME, IFACE_ORDERING_POSITION, NONCONNECTABLE_IFACE_TYPES
|
from .constants import IFACE_ORDERING_NAME, IFACE_ORDERING_POSITION, NONCONNECTABLE_IFACE_TYPES
|
||||||
@ -68,3 +69,16 @@ class InterfaceQuerySet(QuerySet):
|
|||||||
wireless).
|
wireless).
|
||||||
"""
|
"""
|
||||||
return self.exclude(form_factor__in=NONCONNECTABLE_IFACE_TYPES)
|
return self.exclude(form_factor__in=NONCONNECTABLE_IFACE_TYPES)
|
||||||
|
|
||||||
|
|
||||||
|
class CableQuerySet(QuerySet):
|
||||||
|
|
||||||
|
def get_for_termination(self, termination):
|
||||||
|
"""
|
||||||
|
Return the Cable (or None) connected to a given termination point.
|
||||||
|
"""
|
||||||
|
content_type = ContentType.objects.get_for_model(termination)
|
||||||
|
return self.filter(
|
||||||
|
Q(termination_a_type=content_type, termination_a_id=termination.pk) |
|
||||||
|
Q(termination_b_type=content_type, termination_b_id=termination.pk)
|
||||||
|
).first()
|
||||||
|
@ -706,6 +706,7 @@
|
|||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Rear Port</th>
|
<th>Rear Port</th>
|
||||||
<th>Position</th>
|
<th>Position</th>
|
||||||
|
<th>Connected Cable</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -758,6 +759,7 @@
|
|||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Positions</th>
|
<th>Positions</th>
|
||||||
|
<th>Connected Cable</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -10,6 +10,15 @@
|
|||||||
<td>{{ frontport.get_type_display }}</td>
|
<td>{{ frontport.get_type_display }}</td>
|
||||||
<td>{{ frontport.rear_port }}</td>
|
<td>{{ frontport.rear_port }}</td>
|
||||||
<td>{{ frontport.rear_port_position }}</td>
|
<td>{{ frontport.rear_port_position }}</td>
|
||||||
|
{% with cable=frontport.get_connected_cable %}
|
||||||
|
<td>
|
||||||
|
{% if cable %}
|
||||||
|
<a href="#">{{ cable }}</a> to <a href="{{ cable.far_end.device.get_absolute_url }}">{{ cable.far_end.device }}</a> <a href="{{ cable.far_end.get_absolute_url }}">{{ cable.far_end }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">Not connected</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endwith %}
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if perms.dcim.change_frontport %}
|
{% if perms.dcim.change_frontport %}
|
||||||
<a href="{% url 'dcim:frontport_edit' pk=frontport.pk %}?return_url={{ device.get_absolute_url }}" title="Edit port" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:frontport_edit' pk=frontport.pk %}?return_url={{ device.get_absolute_url }}" title="Edit port" class="btn btn-info btn-xs">
|
||||||
|
@ -9,6 +9,15 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>{{ rearport.get_type_display }}</td>
|
<td>{{ rearport.get_type_display }}</td>
|
||||||
<td>{{ rearport.positions }}</td>
|
<td>{{ rearport.positions }}</td>
|
||||||
|
{% with cable=rearport.get_connected_cable %}
|
||||||
|
<td>
|
||||||
|
{% if cable %}
|
||||||
|
<a href="#">{{ cable }}</a> to <a href="{{ cable.far_end.device.get_absolute_url }}">{{ cable.far_end.device }}</a> <a href="{{ cable.far_end.get_absolute_url }}">{{ cable.far_end }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">Not connected</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endwith %}
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% if perms.dcim.change_rearport %}
|
{% if perms.dcim.change_rearport %}
|
||||||
<a href="{% url 'dcim:rearport_edit' pk=rearport.pk %}?return_url={{ device.get_absolute_url }}" title="Edit port" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:rearport_edit' pk=rearport.pk %}?return_url={{ device.get_absolute_url }}" title="Edit port" class="btn btn-info btn-xs">
|
||||||
|
Loading…
Reference in New Issue
Block a user