From 8c3a29438489e2091d3164937c50ee55bf68391f Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 19 Nov 2018 15:26:06 -0500 Subject: [PATCH] Standardized behavior and display of connection_status --- netbox/circuits/api/serializers.py | 8 ++-- netbox/dcim/api/serializers.py | 53 ++++++++++++++------------- netbox/dcim/migrations/0066_cables.py | 28 ++++++++++++-- netbox/dcim/models.py | 8 ++++ 4 files changed, 63 insertions(+), 34 deletions(-) diff --git a/netbox/circuits/api/serializers.py b/netbox/circuits/api/serializers.py index 6ac2587c6..d32e298de 100644 --- a/netbox/circuits/api/serializers.py +++ b/netbox/circuits/api/serializers.py @@ -2,7 +2,8 @@ from taggit_serializer.serializers import TaggitSerializer, TagListSerializerFie from circuits.constants import CIRCUIT_STATUS_CHOICES from circuits.models import Provider, Circuit, CircuitTermination, CircuitType -from dcim.api.nested_serializers import NestedCableSerializer, NestedInterfaceSerializer, NestedSiteSerializer +from dcim.api.nested_serializers import NestedCableSerializer, NestedSiteSerializer +from dcim.api.serializers import ConnectedEndpointSerializer from extras.api.customfields import CustomFieldModelSerializer from tenancy.api.nested_serializers import NestedTenantSerializer from utilities.api import ChoiceField, ValidatedModelSerializer @@ -50,15 +51,14 @@ class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer): ] -class CircuitTerminationSerializer(ValidatedModelSerializer): +class CircuitTerminationSerializer(ConnectedEndpointSerializer): circuit = NestedCircuitSerializer() site = NestedSiteSerializer() - connected_endpoint = NestedInterfaceSerializer(read_only=True) cable = NestedCableSerializer(read_only=True) class Meta: model = CircuitTermination fields = [ 'id', 'circuit', 'term_side', 'site', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', - 'description', 'connected_endpoint', 'cable', + 'description', 'connected_endpoint', 'connection_status', 'cable', ] diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 23d870864..75a869490 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -22,6 +22,24 @@ from virtualization.api.nested_serializers import NestedClusterSerializer from .nested_serializers import * +class ConnectedEndpointSerializer(ValidatedModelSerializer): + connected_endpoint = serializers.SerializerMethodField(read_only=True) + connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True) + + def get_connected_endpoint(self, obj): + """ + Return the appropriate serializer for the type of connected object. + """ + if getattr(obj, 'connected_endpoint', None) is None: + return None + + serializer = get_serializer_for_model(obj.connected_endpoint, prefix='Nested') + context = {'request': self.context['request']} + data = serializer(obj.connected_endpoint, context=context).data + + return data + + # # Regions/sites # @@ -306,20 +324,18 @@ class DeviceWithConfigContextSerializer(DeviceSerializer): return obj.get_config_context() -class ConsoleServerPortSerializer(TaggitSerializer, ValidatedModelSerializer): +class ConsoleServerPortSerializer(TaggitSerializer, ConnectedEndpointSerializer): device = NestedDeviceSerializer() cable = NestedCableSerializer(read_only=True) tags = TagListSerializerField(required=False) class Meta: model = ConsoleServerPort - fields = ['id', 'device', 'name', 'connected_endpoint', 'cable', 'tags'] - read_only_fields = ['connected_endpoint'] + fields = ['id', 'device', 'name', 'connected_endpoint', 'connection_status', 'cable', 'tags'] -class ConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer): +class ConsolePortSerializer(TaggitSerializer, ConnectedEndpointSerializer): device = NestedDeviceSerializer() - connected_endpoint = NestedConsoleServerPortSerializer(read_only=True) cable = NestedCableSerializer(read_only=True) tags = TagListSerializerField(required=False) @@ -328,20 +344,18 @@ class ConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer): fields = ['id', 'device', 'name', 'connected_endpoint', 'connection_status', 'cable', 'tags'] -class PowerOutletSerializer(TaggitSerializer, ValidatedModelSerializer): +class PowerOutletSerializer(TaggitSerializer, ConnectedEndpointSerializer): device = NestedDeviceSerializer() cable = NestedCableSerializer(read_only=True) tags = TagListSerializerField(required=False) class Meta: model = PowerOutlet - fields = ['id', 'device', 'name', 'connected_endpoint', 'cable', 'tags'] - read_only_fields = ['connected_endpoint'] + fields = ['id', 'device', 'name', 'connected_endpoint', 'connection_status', 'cable', 'tags'] -class PowerPortSerializer(TaggitSerializer, ValidatedModelSerializer): +class PowerPortSerializer(TaggitSerializer, ConnectedEndpointSerializer): device = NestedDeviceSerializer() - connected_endpoint = NestedPowerOutletSerializer(read_only=True) cable = NestedCableSerializer(read_only=True) tags = TagListSerializerField(required=False) @@ -350,11 +364,10 @@ class PowerPortSerializer(TaggitSerializer, ValidatedModelSerializer): fields = ['id', 'device', 'name', 'connected_endpoint', 'connection_status', 'cable', 'tags'] -class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer): +class InterfaceSerializer(TaggitSerializer, ConnectedEndpointSerializer): device = NestedDeviceSerializer() form_factor = ChoiceField(choices=IFACE_FF_CHOICES, required=False) lag = NestedInterfaceSerializer(required=False, allow_null=True) - connected_endpoint = serializers.SerializerMethodField(read_only=True) mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True) untagged_vlan = NestedVLANSerializer(required=False, allow_null=True) tagged_vlans = SerializedPKRelatedField( @@ -370,7 +383,8 @@ class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer): model = Interface fields = [ 'id', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description', - 'connected_endpoint', 'cable', 'mode', 'untagged_vlan', 'tagged_vlans', 'tags', 'count_ipaddresses', + 'connected_endpoint', 'connection_status', 'cable', 'mode', 'untagged_vlan', 'tagged_vlans', 'tags', + 'count_ipaddresses', ] # TODO: This validation should be handled by Interface.clean() @@ -393,19 +407,6 @@ class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer): return super(InterfaceSerializer, self).validate(data) - def get_connected_endpoint(self, obj): - """ - Return the appropriate serializer for the type of connected object. - """ - if obj.connected_endpoint is None: - return None - - serializer = get_serializer_for_model(obj.connected_endpoint, prefix='Nested') - context = {'request': self.context['request']} - data = serializer(obj.connected_endpoint, context=context).data - - return data - class RearPortSerializer(ValidatedModelSerializer): device = NestedDeviceSerializer() diff --git a/netbox/dcim/migrations/0066_cables.py b/netbox/dcim/migrations/0066_cables.py index 4fe5cd5d1..af023ee60 100644 --- a/netbox/dcim/migrations/0066_cables.py +++ b/netbox/dcim/migrations/0066_cables.py @@ -34,8 +34,13 @@ def console_connections_to_cables(apps, schema_editor): ) # Cache the Cable on its two termination points - ConsolePort.objects.filter(pk=consoleport.id).update(cable=cable) - ConsoleServerPort.objects.filter(pk=consoleport.connected_endpoint_id).update(cable=cable) + ConsolePort.objects.filter(pk=consoleport.id).update( + cable=cable + ) + ConsoleServerPort.objects.filter(pk=consoleport.connected_endpoint_id).update( + connection_status=consoleport.connection_status, + cable=cable + ) cable_count = Cable.objects.filter(termination_a_type=consoleport_type).count() if 'test' not in sys.argv: @@ -70,8 +75,13 @@ def power_connections_to_cables(apps, schema_editor): ) # Cache the Cable on its two termination points - PowerPort.objects.filter(pk=powerport.id).update(cable=cable) - PowerOutlet.objects.filter(pk=powerport.connected_endpoint_id).update(cable=cable) + PowerPort.objects.filter(pk=powerport.id).update( + cable=cable + ) + PowerOutlet.objects.filter(pk=powerport.connected_endpoint_id).update( + connection_status=powerport.connection_status, + cable=cable + ) cable_count = Cable.objects.filter(termination_a_type=powerport_type).count() if 'test' not in sys.argv: @@ -194,6 +204,11 @@ class Migration(migrations.Migration): name='cable', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.Cable'), ), + migrations.AddField( + model_name='consoleserverport', + name='connection_status', + field=models.NullBooleanField(), + ), # Alter power port models migrations.RenameField( @@ -231,6 +246,11 @@ class Migration(migrations.Migration): name='cable', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.Cable'), ), + migrations.AddField( + model_name='poweroutlet', + name='connection_status', + field=models.NullBooleanField(), + ), # Alter the Interface model migrations.AddField( diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index dcf5f93e4..59f706cb5 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -1745,6 +1745,10 @@ class ConsoleServerPort(CableTermination, ComponentModel): name = models.CharField( max_length=50 ) + connection_status = models.NullBooleanField( + choices=CONNECTION_STATUS_CHOICES, + blank=True + ) objects = DeviceComponentManager() tags = TaggableManager() @@ -1833,6 +1837,10 @@ class PowerOutlet(CableTermination, ComponentModel): name = models.CharField( max_length=50 ) + connection_status = models.NullBooleanField( + choices=CONNECTION_STATUS_CHOICES, + blank=True + ) objects = DeviceComponentManager() tags = TaggableManager()