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

Closes #3648: Mark cable termination models as connected without attaching a cable

This commit is contained in:
Jeremy Stretch
2021-03-01 21:34:42 -05:00
parent 6ed2e7b636
commit 8dd7123923
26 changed files with 281 additions and 108 deletions

View File

@@ -51,4 +51,4 @@ class NestedCircuitTerminationSerializer(WritableNestedSerializer):
class Meta:
model = CircuitTermination
fields = ['id', 'url', 'circuit', 'term_side', 'cable']
fields = ['id', 'url', 'circuit', 'term_side', 'cable', '_occupied']

View File

@@ -82,6 +82,6 @@ class CircuitTerminationSerializer(CableTerminationSerializer, ConnectedEndpoint
model = CircuitTermination
fields = [
'id', 'url', 'circuit', 'term_side', 'site', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info',
'description', 'cable', 'cable_peer', 'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type',
'connected_endpoint_reachable'
'description', 'mark_connected', 'cable', 'cable_peer', 'cable_peer_type', 'connected_endpoint',
'connected_endpoint_type', 'connected_endpoint_reachable', '_occupied',
]

View File

@@ -330,7 +330,8 @@ class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
class Meta:
model = CircuitTermination
fields = [
'term_side', 'region', 'site', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description',
'term_side', 'region', 'site', 'mark_connected', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info',
'description',
]
help_texts = {
'port_speed': "Physical circuit speed",

View File

@@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('circuits', '0025_standardize_models'),
]
operations = [
migrations.AddField(
model_name='circuittermination',
name='mark_connected',
field=models.BooleanField(default=False),
),
]

View File

@@ -129,7 +129,7 @@ class CircuitTest(APIViewTestCases.APIViewTestCase):
class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
model = CircuitTermination
brief_fields = ['cable', 'circuit', 'id', 'term_side', 'url']
brief_fields = ['_occupied', 'cable', 'circuit', 'id', 'term_side', 'url']
@classmethod
def setUpTestData(cls):

View File

@@ -230,7 +230,7 @@ class NestedConsoleServerPortSerializer(WritableNestedSerializer):
class Meta:
model = models.ConsoleServerPort
fields = ['id', 'url', 'device', 'name', 'cable']
fields = ['id', 'url', 'device', 'name', 'cable', '_occupied']
class NestedConsolePortSerializer(WritableNestedSerializer):
@@ -239,7 +239,7 @@ class NestedConsolePortSerializer(WritableNestedSerializer):
class Meta:
model = models.ConsolePort
fields = ['id', 'url', 'device', 'name', 'cable']
fields = ['id', 'url', 'device', 'name', 'cable', '_occupied']
class NestedPowerOutletSerializer(WritableNestedSerializer):
@@ -248,7 +248,7 @@ class NestedPowerOutletSerializer(WritableNestedSerializer):
class Meta:
model = models.PowerOutlet
fields = ['id', 'url', 'device', 'name', 'cable']
fields = ['id', 'url', 'device', 'name', 'cable', '_occupied']
class NestedPowerPortSerializer(WritableNestedSerializer):
@@ -257,7 +257,7 @@ class NestedPowerPortSerializer(WritableNestedSerializer):
class Meta:
model = models.PowerPort
fields = ['id', 'url', 'device', 'name', 'cable']
fields = ['id', 'url', 'device', 'name', 'cable', '_occupied']
class NestedInterfaceSerializer(WritableNestedSerializer):
@@ -266,7 +266,7 @@ class NestedInterfaceSerializer(WritableNestedSerializer):
class Meta:
model = models.Interface
fields = ['id', 'url', 'device', 'name', 'cable']
fields = ['id', 'url', 'device', 'name', 'cable', '_occupied']
class NestedRearPortSerializer(WritableNestedSerializer):
@@ -275,7 +275,7 @@ class NestedRearPortSerializer(WritableNestedSerializer):
class Meta:
model = models.RearPort
fields = ['id', 'url', 'device', 'name', 'cable']
fields = ['id', 'url', 'device', 'name', 'cable', '_occupied']
class NestedFrontPortSerializer(WritableNestedSerializer):
@@ -284,7 +284,7 @@ class NestedFrontPortSerializer(WritableNestedSerializer):
class Meta:
model = models.FrontPort
fields = ['id', 'url', 'device', 'name', 'cable']
fields = ['id', 'url', 'device', 'name', 'cable', '_occupied']
class NestedDeviceBaySerializer(WritableNestedSerializer):
@@ -350,4 +350,4 @@ class NestedPowerFeedSerializer(WritableNestedSerializer):
class Meta:
model = models.PowerFeed
fields = ['id', 'url', 'name', 'cable']
fields = ['id', 'url', 'name', 'cable', '_occupied']

View File

@@ -509,9 +509,9 @@ class ConsoleServerPortSerializer(TaggedObjectSerializer, CableTerminationSerial
class Meta:
model = ConsoleServerPort
fields = [
'id', 'url', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'cable_peer_type',
'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields',
'created', 'last_updated',
'id', 'url', 'device', 'name', 'label', 'type', 'description', 'mark_connected', 'cable', 'cable_peer',
'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags',
'custom_fields', 'created', 'last_updated', '_occupied',
]
@@ -528,9 +528,9 @@ class ConsolePortSerializer(TaggedObjectSerializer, CableTerminationSerializer,
class Meta:
model = ConsolePort
fields = [
'id', 'url', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'cable_peer_type',
'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields',
'created', 'last_updated',
'id', 'url', 'device', 'name', 'label', 'type', 'description', 'mark_connected', 'cable', 'cable_peer',
'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags',
'custom_fields', 'created', 'last_updated', '_occupied',
]
@@ -557,9 +557,9 @@ class PowerOutletSerializer(TaggedObjectSerializer, CableTerminationSerializer,
class Meta:
model = PowerOutlet
fields = [
'id', 'url', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable',
'cable_peer', 'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type',
'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated',
'id', 'url', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'mark_connected',
'cable', 'cable_peer', 'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type',
'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
]
@@ -576,9 +576,9 @@ class PowerPortSerializer(TaggedObjectSerializer, CableTerminationSerializer, Co
class Meta:
model = PowerPort
fields = [
'id', 'url', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable',
'cable_peer', 'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type',
'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated',
'id', 'url', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description',
'mark_connected', 'cable', 'cable_peer', 'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type',
'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
]
@@ -602,9 +602,9 @@ class InterfaceSerializer(TaggedObjectSerializer, CableTerminationSerializer, Co
model = Interface
fields = [
'id', 'url', 'device', 'name', 'label', 'type', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only',
'description', 'mode', 'untagged_vlan', 'tagged_vlans', 'cable', 'cable_peer', 'cable_peer_type',
'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields',
'created', 'last_updated', 'count_ipaddresses',
'description', 'mode', 'untagged_vlan', 'tagged_vlans', 'mark_connected', 'cable', 'cable_peer',
'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags',
'custom_fields', 'created', 'last_updated', 'count_ipaddresses', '_occupied',
]
def validate(self, data):
@@ -630,8 +630,8 @@ class RearPortSerializer(TaggedObjectSerializer, CableTerminationSerializer, Cus
class Meta:
model = RearPort
fields = [
'id', 'url', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer',
'cable_peer_type', 'tags', 'custom_fields', 'created', 'last_updated',
'id', 'url', 'device', 'name', 'label', 'type', 'positions', 'description', 'mark_connected', 'cable',
'cable_peer', 'cable_peer_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
]
@@ -656,8 +656,9 @@ class FrontPortSerializer(TaggedObjectSerializer, CableTerminationSerializer, Cu
class Meta:
model = FrontPort
fields = [
'id', 'url', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable',
'cable_peer', 'cable_peer_type', 'tags', 'custom_fields', 'created', 'last_updated',
'id', 'url', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description',
'mark_connected', 'cable', 'cable_peer', 'cable_peer_type', 'tags', 'custom_fields', 'created',
'last_updated', '_occupied',
]
@@ -892,7 +893,7 @@ class PowerFeedSerializer(
model = PowerFeed
fields = [
'id', 'url', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage',
'max_utilization', 'comments', 'cable', 'cable_peer', 'cable_peer_type', 'connected_endpoint',
'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields', 'created',
'last_updated',
'max_utilization', 'comments', 'mark_connected', 'cable', 'cable_peer', 'cable_peer_type',
'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields',
'created', 'last_updated', '_occupied',
]

View File

@@ -2324,7 +2324,7 @@ class ConsolePortForm(BootstrapMixin, CustomFieldModelForm):
class Meta:
model = ConsolePort
fields = [
'device', 'name', 'label', 'type', 'description', 'tags',
'device', 'name', 'label', 'type', 'mark_connected', 'description', 'tags',
]
widgets = {
'device': forms.HiddenInput(),
@@ -2338,19 +2338,19 @@ class ConsolePortCreateForm(ComponentCreateForm):
required=False,
widget=StaticSelect2()
)
field_order = ('device', 'name_pattern', 'label_pattern', 'type', 'description', 'tags')
field_order = ('device', 'name_pattern', 'label_pattern', 'type', 'mark_connected', 'description', 'tags')
class ConsolePortBulkCreateForm(
form_from_model(ConsolePort, ['type']),
form_from_model(ConsolePort, ['type', 'mark_connected']),
DeviceBulkAddComponentForm
):
model = ConsolePort
field_order = ('name_pattern', 'label_pattern', 'type', 'description', 'tags')
field_order = ('name_pattern', 'label_pattern', 'type', 'mark_connected', 'description', 'tags')
class ConsolePortBulkEditForm(
form_from_model(ConsolePort, ['label', 'type', 'description']),
form_from_model(ConsolePort, ['label', 'type', 'mark_connected', 'description']),
BootstrapMixin,
AddRemoveTagsForm,
CustomFieldBulkEditForm
@@ -2772,8 +2772,8 @@ class InterfaceForm(BootstrapMixin, InterfaceCommonForm, CustomFieldModelForm):
class Meta:
model = Interface
fields = [
'device', 'name', 'label', 'type', 'enabled', 'lag', 'mac_address', 'mtu', 'mgmt_only', 'description',
'mode', 'untagged_vlan', 'tagged_vlans', 'tags',
'device', 'name', 'label', 'type', 'enabled', 'lag', 'mac_address', 'mtu', 'mgmt_only', 'mark_connected',
'description', 'mode', 'untagged_vlan', 'tagged_vlans', 'tags',
]
widgets = {
'device': forms.HiddenInput(),
@@ -3625,7 +3625,7 @@ class ConnectCableToConsolePortForm(ConnectCableToDeviceForm):
termination_b_id = DynamicModelChoiceField(
queryset=ConsolePort.objects.all(),
label='Name',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'device_id': '$termination_b_device'
}
@@ -3636,7 +3636,7 @@ class ConnectCableToConsoleServerPortForm(ConnectCableToDeviceForm):
termination_b_id = DynamicModelChoiceField(
queryset=ConsoleServerPort.objects.all(),
label='Name',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'device_id': '$termination_b_device'
}
@@ -3647,7 +3647,7 @@ class ConnectCableToPowerPortForm(ConnectCableToDeviceForm):
termination_b_id = DynamicModelChoiceField(
queryset=PowerPort.objects.all(),
label='Name',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'device_id': '$termination_b_device'
}
@@ -3658,7 +3658,7 @@ class ConnectCableToPowerOutletForm(ConnectCableToDeviceForm):
termination_b_id = DynamicModelChoiceField(
queryset=PowerOutlet.objects.all(),
label='Name',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'device_id': '$termination_b_device'
}
@@ -3669,7 +3669,7 @@ class ConnectCableToInterfaceForm(ConnectCableToDeviceForm):
termination_b_id = DynamicModelChoiceField(
queryset=Interface.objects.all(),
label='Name',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'device_id': '$termination_b_device',
'kind': 'physical',
@@ -3681,7 +3681,7 @@ class ConnectCableToFrontPortForm(ConnectCableToDeviceForm):
termination_b_id = DynamicModelChoiceField(
queryset=FrontPort.objects.all(),
label='Name',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'device_id': '$termination_b_device'
}
@@ -3692,7 +3692,7 @@ class ConnectCableToRearPortForm(ConnectCableToDeviceForm):
termination_b_id = DynamicModelChoiceField(
queryset=RearPort.objects.all(),
label='Name',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'device_id': '$termination_b_device'
}
@@ -3731,7 +3731,7 @@ class ConnectCableToCircuitTerminationForm(BootstrapMixin, CustomFieldModelForm)
queryset=CircuitTermination.objects.all(),
label='Side',
display_field='term_side',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'circuit_id': '$termination_b_circuit'
}
@@ -3788,7 +3788,7 @@ class ConnectCableToPowerFeedForm(BootstrapMixin, CustomFieldModelForm):
termination_b_id = DynamicModelChoiceField(
queryset=PowerFeed.objects.all(),
label='Name',
disabled_indicator='cable',
disabled_indicator='_occupied',
query_params={
'power_panel_id': '$termination_b_powerpanel'
}
@@ -4538,12 +4538,12 @@ class PowerFeedForm(BootstrapMixin, CustomFieldModelForm):
class Meta:
model = PowerFeed
fields = [
'region', 'site', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage',
'max_utilization', 'comments', 'tags',
'region', 'site', 'power_panel', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase',
'voltage', 'amperage', 'max_utilization', 'comments', 'tags',
]
fieldsets = (
('Power Panel', ('region', 'site', 'power_panel')),
('Power Feed', ('rack', 'name', 'status', 'type', 'tags')),
('Power Feed', ('rack', 'name', 'status', 'type', 'mark_connected', 'tags')),
('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')),
)
widgets = {

View File

@@ -0,0 +1,51 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0123_standardize_models'),
]
operations = [
migrations.AddField(
model_name='consoleport',
name='mark_connected',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='consoleserverport',
name='mark_connected',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='frontport',
name='mark_connected',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='interface',
name='mark_connected',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='powerfeed',
name='mark_connected',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='poweroutlet',
name='mark_connected',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='powerport',
name='mark_connected',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='rearport',
name='mark_connected',
field=models.BooleanField(default=False),
),
]

View File

@@ -126,6 +126,10 @@ class CableTermination(models.Model):
ct_field='_cable_peer_type',
fk_field='_cable_peer_id'
)
mark_connected = models.BooleanField(
default=False,
help_text="Treat as if a cable is connected"
)
# Generic relations to Cable. These ensure that an attached Cable is deleted if the terminated object is deleted.
_cabled_as_a = GenericRelation(
@@ -142,9 +146,19 @@ class CableTermination(models.Model):
class Meta:
abstract = True
def clean(self):
super().clean()
if self.mark_connected and self.cable_id:
raise ValidationError("Cannot set mark_connected with a cable connected.")
def get_cable_peer(self):
return self._cable_peer
@property
def _occupied(self):
return bool(self.mark_connected or self.cable_id)
class PathEndpoint(models.Model):
"""
@@ -212,7 +226,7 @@ class ConsolePort(CableTermination, PathEndpoint, ComponentModel):
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'description']
csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'description']
class Meta:
ordering = ('device', '_name')
@@ -227,6 +241,7 @@ class ConsolePort(CableTermination, PathEndpoint, ComponentModel):
self.name,
self.label,
self.type,
self.mark_connected,
self.description,
)
@@ -248,7 +263,7 @@ class ConsoleServerPort(CableTermination, PathEndpoint, ComponentModel):
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'description']
csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'description']
class Meta:
ordering = ('device', '_name')
@@ -263,6 +278,7 @@ class ConsoleServerPort(CableTermination, PathEndpoint, ComponentModel):
self.name,
self.label,
self.type,
self.mark_connected,
self.description,
)
@@ -296,7 +312,9 @@ class PowerPort(CableTermination, PathEndpoint, ComponentModel):
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description']
csv_headers = [
'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description',
]
class Meta:
ordering = ('device', '_name')
@@ -311,6 +329,7 @@ class PowerPort(CableTermination, PathEndpoint, ComponentModel):
self.name,
self.label,
self.get_type_display(),
self.mark_connected,
self.maximum_draw,
self.allocated_draw,
self.description,
@@ -406,7 +425,7 @@ class PowerOutlet(CableTermination, PathEndpoint, ComponentModel):
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description']
csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'power_port', 'feed_leg', 'description']
class Meta:
ordering = ('device', '_name')
@@ -421,6 +440,7 @@ class PowerOutlet(CableTermination, PathEndpoint, ComponentModel):
self.name,
self.label,
self.get_type_display(),
self.mark_connected,
self.power_port.name if self.power_port else None,
self.get_feed_leg_display(),
self.description,
@@ -532,7 +552,8 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
tags = TaggableManager(through=TaggedItem)
csv_headers = [
'device', 'name', 'label', 'lag', 'type', 'enabled', 'mac_address', 'mtu', 'mgmt_only', 'description', 'mode',
'device', 'name', 'label', 'lag', 'type', 'enabled', 'mark_connected', 'mac_address', 'mtu', 'mgmt_only',
'description', 'mode',
]
class Meta:
@@ -550,6 +571,7 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
self.lag.name if self.lag else None,
self.get_type_display(),
self.enabled,
self.mark_connected,
self.mac_address,
self.mtu,
self.mgmt_only,
@@ -648,7 +670,9 @@ class FrontPort(CableTermination, ComponentModel):
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description']
csv_headers = [
'device', 'name', 'label', 'type', 'mark_connected', 'rear_port', 'rear_port_position', 'description',
]
class Meta:
ordering = ('device', '_name')
@@ -666,6 +690,7 @@ class FrontPort(CableTermination, ComponentModel):
self.name,
self.label,
self.get_type_display(),
self.mark_connected,
self.rear_port.name,
self.rear_port_position,
self.description,
@@ -706,7 +731,7 @@ class RearPort(CableTermination, ComponentModel):
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'positions', 'description']
csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'positions', 'description']
class Meta:
ordering = ('device', '_name')
@@ -732,6 +757,7 @@ class RearPort(CableTermination, ComponentModel):
self.name,
self.label,
self.get_type_display(),
self.mark_connected,
self.positions,
self.description,
)

View File

@@ -138,12 +138,12 @@ class PowerFeed(PrimaryModel, PathEndpoint, CableTermination):
objects = RestrictedQuerySet.as_manager()
csv_headers = [
'site', 'power_panel', 'rack_group', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage',
'amperage', 'max_utilization', 'comments',
'site', 'power_panel', 'rack_group', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase',
'voltage', 'amperage', 'max_utilization', 'comments',
]
clone_fields = [
'power_panel', 'rack', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization',
'available_power',
'power_panel', 'rack', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage',
'max_utilization', 'available_power',
]
class Meta:
@@ -165,6 +165,7 @@ class PowerFeed(PrimaryModel, PathEndpoint, CableTermination):
self.name,
self.get_status_display(),
self.get_type_display(),
self.mark_connected,
self.get_supply_display(),
self.get_phase_display(),
self.voltage,

View File

@@ -213,6 +213,7 @@ class DeviceComponentTable(BaseTable):
cable = tables.Column(
linkify=True
)
mark_connected = BooleanColumn()
class Meta(BaseTable.Meta):
order_by = ('device', 'name')
@@ -228,6 +229,7 @@ class CableTerminationTable(BaseTable):
orderable=False,
verbose_name='Cable Peer'
)
mark_connected = BooleanColumn()
class PathEndpointTable(CableTerminationTable):
@@ -247,7 +249,8 @@ class ConsolePortTable(DeviceComponentTable, PathEndpointTable):
class Meta(DeviceComponentTable.Meta):
model = ConsolePort
fields = (
'pk', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags',
'pk', 'device', 'name', 'label', 'type', 'description', 'mark_connected', 'cable', 'cable_peer',
'connection', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
@@ -266,7 +269,8 @@ class DeviceConsolePortTable(ConsolePortTable):
class Meta(DeviceComponentTable.Meta):
model = ConsolePort
fields = (
'pk', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags', 'actions'
'pk', 'name', 'label', 'type', 'description', 'mark_connected', 'cable', 'cable_peer', 'connection',
'tags', 'actions'
)
default_columns = ('pk', 'name', 'label', 'type', 'description', 'cable', 'connection', 'actions')
row_attrs = {
@@ -281,7 +285,10 @@ class ConsoleServerPortTable(DeviceComponentTable, PathEndpointTable):
class Meta(DeviceComponentTable.Meta):
model = ConsoleServerPort
fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags')
fields = (
'pk', 'device', 'name', 'label', 'type', 'description', 'mark_connected', 'cable', 'cable_peer',
'connection', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
@@ -300,7 +307,8 @@ class DeviceConsoleServerPortTable(ConsoleServerPortTable):
class Meta(DeviceComponentTable.Meta):
model = ConsoleServerPort
fields = (
'pk', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags', 'actions'
'pk', 'name', 'label', 'type', 'description', 'mark_connected', 'cable', 'cable_peer', 'connection', 'tags',
'actions',
)
default_columns = ('pk', 'name', 'label', 'type', 'description', 'cable', 'connection', 'actions')
row_attrs = {
@@ -316,8 +324,8 @@ class PowerPortTable(DeviceComponentTable, PathEndpointTable):
class Meta(DeviceComponentTable.Meta):
model = PowerPort
fields = (
'pk', 'device', 'name', 'label', 'type', 'description', 'maximum_draw', 'allocated_draw', 'cable',
'cable_peer', 'connection', 'tags',
'pk', 'device', 'name', 'label', 'type', 'description', 'mark_connected', 'maximum_draw', 'allocated_draw',
'cable', 'cable_peer', 'connection', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description')
@@ -337,8 +345,8 @@ class DevicePowerPortTable(PowerPortTable):
class Meta(DeviceComponentTable.Meta):
model = PowerPort
fields = (
'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable', 'cable_peer',
'connection', 'tags', 'actions',
'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'mark_connected', 'cable',
'cable_peer', 'connection', 'tags', 'actions',
)
default_columns = (
'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable', 'connection',
@@ -360,8 +368,8 @@ class PowerOutletTable(DeviceComponentTable, PathEndpointTable):
class Meta(DeviceComponentTable.Meta):
model = PowerOutlet
fields = (
'pk', 'device', 'name', 'label', 'type', 'description', 'power_port', 'feed_leg', 'cable', 'cable_peer',
'connection', 'tags',
'pk', 'device', 'name', 'label', 'type', 'description', 'power_port', 'feed_leg', 'mark_connected', 'cable',
'cable_peer', 'connection', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description')
@@ -380,8 +388,8 @@ class DevicePowerOutletTable(PowerOutletTable):
class Meta(DeviceComponentTable.Meta):
model = PowerOutlet
fields = (
'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable', 'cable_peer', 'connection',
'tags', 'actions',
'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'mark_connected', 'cable',
'cable_peer', 'connection', 'tags', 'actions',
)
default_columns = (
'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable', 'connection', 'actions',
@@ -416,7 +424,8 @@ class InterfaceTable(DeviceComponentTable, BaseInterfaceTable, PathEndpointTable
model = Interface
fields = (
'pk', 'device', 'name', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'mac_address',
'description', 'cable', 'cable_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans',
'description', 'mark_connected', 'cable', 'cable_peer', 'connection', 'tags', 'ip_addresses',
'untagged_vlan', 'tagged_vlans',
)
default_columns = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description')
@@ -442,7 +451,8 @@ class DeviceInterfaceTable(InterfaceTable):
model = Interface
fields = (
'pk', 'name', 'label', 'enabled', 'type', 'lag', 'mgmt_only', 'mtu', 'mode', 'mac_address', 'description',
'cable', 'cable_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans', 'actions',
'mark_connected', 'cable', 'cable_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan',
'tagged_vlans', 'actions',
)
default_columns = (
'pk', 'name', 'label', 'enabled', 'type', 'lag', 'mtu', 'mode', 'description', 'ip_addresses', 'cable',
@@ -468,8 +478,8 @@ class FrontPortTable(DeviceComponentTable, CableTerminationTable):
class Meta(DeviceComponentTable.Meta):
model = FrontPort
fields = (
'pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable',
'cable_peer', 'tags',
'pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'mark_connected',
'cable', 'cable_peer', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description')
@@ -489,8 +499,8 @@ class DeviceFrontPortTable(FrontPortTable):
class Meta(DeviceComponentTable.Meta):
model = FrontPort
fields = (
'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'cable_peer',
'tags', 'actions',
'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'mark_connected', 'cable',
'cable_peer', 'tags', 'actions',
)
default_columns = (
'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'cable_peer',
@@ -508,7 +518,10 @@ class RearPortTable(DeviceComponentTable, CableTerminationTable):
class Meta(DeviceComponentTable.Meta):
model = RearPort
fields = ('pk', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'tags')
fields = (
'pk', 'device', 'name', 'label', 'type', 'positions', 'description', 'mark_connected', 'cable',
'cable_peer', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
@@ -527,7 +540,8 @@ class DeviceRearPortTable(RearPortTable):
class Meta(DeviceComponentTable.Meta):
model = RearPort
fields = (
'pk', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'tags', 'actions',
'pk', 'name', 'label', 'type', 'positions', 'description', 'mark_connected', 'cable', 'cable_peer', 'tags',
'actions',
)
default_columns = (
'pk', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'actions',

View File

@@ -68,7 +68,7 @@ class PowerFeedTable(CableTerminationTable):
model = PowerFeed
fields = (
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase',
'max_utilization', 'cable', 'cable_peer', 'connection', 'available_power', 'tags',
'max_utilization', 'mark_connected', 'cable', 'cable_peer', 'connection', 'available_power', 'tags',
)
default_columns = (
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase', 'cable',

View File

@@ -979,7 +979,7 @@ class DeviceTest(APIViewTestCases.APIViewTestCase):
class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
model = ConsolePort
brief_fields = ['cable', 'device', 'id', 'name', 'url']
brief_fields = ['_occupied', 'cable', 'device', 'id', 'name', 'url']
bulk_update_data = {
'description': 'New description',
}
@@ -1018,7 +1018,7 @@ class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa
class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
model = ConsoleServerPort
brief_fields = ['cable', 'device', 'id', 'name', 'url']
brief_fields = ['_occupied', 'cable', 'device', 'id', 'name', 'url']
bulk_update_data = {
'description': 'New description',
}
@@ -1057,7 +1057,7 @@ class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIView
class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
model = PowerPort
brief_fields = ['cable', 'device', 'id', 'name', 'url']
brief_fields = ['_occupied', 'cable', 'device', 'id', 'name', 'url']
bulk_update_data = {
'description': 'New description',
}
@@ -1096,7 +1096,7 @@ class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
model = PowerOutlet
brief_fields = ['cable', 'device', 'id', 'name', 'url']
brief_fields = ['_occupied', 'cable', 'device', 'id', 'name', 'url']
bulk_update_data = {
'description': 'New description',
}
@@ -1135,7 +1135,7 @@ class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa
class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
model = Interface
brief_fields = ['cable', 'device', 'id', 'name', 'url']
brief_fields = ['_occupied', 'cable', 'device', 'id', 'name', 'url']
bulk_update_data = {
'description': 'New description',
}
@@ -1193,7 +1193,7 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
class FrontPortTest(APIViewTestCases.APIViewTestCase):
model = FrontPort
brief_fields = ['cable', 'device', 'id', 'name', 'url']
brief_fields = ['_occupied', 'cable', 'device', 'id', 'name', 'url']
bulk_update_data = {
'description': 'New description',
}
@@ -1251,7 +1251,7 @@ class FrontPortTest(APIViewTestCases.APIViewTestCase):
class RearPortTest(APIViewTestCases.APIViewTestCase):
model = RearPort
brief_fields = ['cable', 'device', 'id', 'name', 'url']
brief_fields = ['_occupied', 'cable', 'device', 'id', 'name', 'url']
bulk_update_data = {
'description': 'New description',
}
@@ -1628,7 +1628,7 @@ class PowerPanelTest(APIViewTestCases.APIViewTestCase):
class PowerFeedTest(APIViewTestCases.APIViewTestCase):
model = PowerFeed
brief_fields = ['cable', 'id', 'name', 'url']
brief_fields = ['_occupied', 'cable', 'id', 'name', 'url']
bulk_update_data = {
'status': 'planned',
}

View File

@@ -28,6 +28,7 @@
</div>
{% render_field form.region %}
{% render_field form.site %}
{% render_field form.mark_connected %}
</div>
</div>
<div class="panel panel-default">

View File

@@ -38,7 +38,10 @@
<tr>
<td>Termination</td>
<td>
{% if termination.cable %}
{% if termination.mark_connected %}
<span class="text-success"><i class="mdi mdi-check-bold"></i></span>
<span class="text-muted">Marked as connected</span>
{% elif termination.cable %}
{% if perms.dcim.delete_cable %}
<div class="pull-right">
<a href="{% url 'dcim:cable_delete' pk=termination.cable.pk %}?return_url={{ termination.circuit.get_absolute_url }}" title="Remove cable" class="btn btn-danger btn-xs">

View File

@@ -43,7 +43,11 @@
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if object.cable %}
{% if object.mark_connected %}
<div class="panel-body text-muted">
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
</div>
{% elif object.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>

View File

@@ -43,7 +43,11 @@
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if object.cable %}
{% if object.mark_connected %}
<div class="panel-body text-muted">
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
</div>
{% elif object.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>

View File

@@ -53,7 +53,11 @@
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if object.cable %}
{% if object.mark_connected %}
<div class="panel-body text-muted">
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
</div>
{% elif object.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>

View File

@@ -76,7 +76,11 @@
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if object.cable %}
{% if object.mark_connected %}
<div class="panel-body text-muted">
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
</div>
{% elif object.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>

View File

@@ -23,6 +23,7 @@
{% render_field form.mac_address %}
{% render_field form.mtu %}
{% render_field form.mgmt_only %}
{% render_field form.mark_connected %}
{% render_field form.description %}
{% render_field form.tags %}
</div>
@@ -35,12 +36,14 @@
{% render_field form.tagged_vlans %}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
{% if form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
</div>
</div>
</div>
{% endif %}
{% endblock %}
{% block buttons %}

View File

@@ -159,7 +159,11 @@
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if object.cable %}
{% if object.mark_connected %}
<div class="panel-body text-muted">
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
</div>
{% elif object.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>

View File

@@ -51,7 +51,11 @@
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if object.cable %}
{% if object.mark_connected %}
<div class="panel-body text-muted">
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
</div>
{% elif object.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>

View File

@@ -51,7 +51,11 @@
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if object.cable %}
{% if object.mark_connected %}
<div class="panel-body text-muted">
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
</div>
{% elif object.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>

View File

@@ -47,7 +47,11 @@
<div class="panel-heading">
<strong>Connection</strong>
</div>
{% if object.cable %}
{% if object.mark_connected %}
<div class="panel-body text-muted">
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
</div>
{% elif object.cable %}
<table class="table table-hover panel-body attr-table">
<tr>
<td>Cable</td>