From d7766b982898faad52cc89a8fb9a225d8b6fe47e Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 29 Oct 2018 13:36:41 -0400 Subject: [PATCH] Replace 'is_connected' boolean with Cable attachment --- netbox/circuits/forms.py | 6 ++-- netbox/dcim/api/serializers.py | 54 +++++++--------------------------- netbox/dcim/forms.py | 10 +++---- netbox/dcim/models.py | 12 ++------ netbox/dcim/tests/test_api.py | 10 +++---- 5 files changed, 26 insertions(+), 66 deletions(-) diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index b5883e6ec..2f10598f2 100644 --- a/netbox/circuits/forms.py +++ b/netbox/circuits/forms.py @@ -245,7 +245,7 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm label='Interface', widget=APISelect( api_url='/api/dcim/interfaces/?device_id={{device}}&type=physical', - disabled_indicator='is_connected' + disabled_indicator='cable' ) ) @@ -276,12 +276,12 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm super(CircuitTerminationForm, self).__init__(*args, **kwargs) - # Mark connected interfaces as disabled + # Mark occupied interfaces as disabled self.fields['interface'].choices = [] for iface in self.fields['interface'].queryset: self.fields['interface'].choices.append( (iface.id, { 'label': iface.name, - 'disabled': iface.is_connected and iface.pk != self.initial.get('interface'), + 'disabled': bool(iface.cable) and iface.pk != self.initial.get('interface'), }) ) diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 64d30d5dc..26ec68a84 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -559,14 +559,10 @@ class ConsoleServerPortSerializer(TaggitSerializer, ValidatedModelSerializer): class NestedConsoleServerPortSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail') device = NestedDeviceSerializer(read_only=True) - is_connected = serializers.SerializerMethodField(read_only=True) class Meta: model = ConsoleServerPort - fields = ['id', 'url', 'device', 'name', 'is_connected'] - - def get_is_connected(self, obj): - return hasattr(obj, 'connected_endpoint') and obj.connected_endpoint is not None + fields = ['id', 'url', 'device', 'name', 'cable'] # @@ -588,14 +584,10 @@ class ConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer): class NestedConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail') device = NestedDeviceSerializer(read_only=True) - is_connected = serializers.SerializerMethodField(read_only=True) class Meta: model = ConsolePort - fields = ['id', 'url', 'device', 'name', 'is_connected'] - - def get_is_connected(self, obj): - return obj.connected_endpoint is not None + fields = ['id', 'url', 'device', 'name', 'cable'] # @@ -616,14 +608,10 @@ class PowerOutletSerializer(TaggitSerializer, ValidatedModelSerializer): class NestedPowerOutletSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail') device = NestedDeviceSerializer(read_only=True) - is_connected = serializers.SerializerMethodField(read_only=True) class Meta: model = PowerOutlet - fields = ['id', 'url', 'device', 'name', 'is_connected'] - - def get_is_connected(self, obj): - return hasattr(obj, 'connected_endpoint') and obj.connected_endpoint is not None + fields = ['id', 'url', 'device', 'name', 'cable'] # @@ -645,43 +633,23 @@ class PowerPortSerializer(TaggitSerializer, ValidatedModelSerializer): class NestedPowerPortSerializer(TaggitSerializer, ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail') device = NestedDeviceSerializer(read_only=True) - is_connected = serializers.SerializerMethodField(read_only=True) class Meta: model = PowerPort - fields = ['id', 'url', 'device', 'name', 'is_connected'] - - def get_is_connected(self, obj): - return obj.connected_endpoint is not None + fields = ['id', 'url', 'device', 'name', 'cable'] # # Interfaces # -class IsConnectedMixin(object): - """ - Provide a method for setting is_connected on Interface serializers. - """ - def get_is_connected(self, obj): - """ - Return True if the interface has a connected interface or circuit. - """ - if obj.connected_endpoint: - return True - if hasattr(obj, 'circuit_termination') and obj.circuit_termination is not None: - return True - return False - - -class NestedInterfaceSerializer(IsConnectedMixin, WritableNestedSerializer): +class NestedInterfaceSerializer(WritableNestedSerializer): device = NestedDeviceSerializer(read_only=True) url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail') - is_connected = serializers.SerializerMethodField(read_only=True) class Meta: model = Interface - fields = ['id', 'url', 'device', 'name', 'is_connected'] + fields = ['id', 'url', 'device', 'name', 'cable'] class InterfaceNestedCircuitSerializer(serializers.ModelSerializer): @@ -711,12 +679,11 @@ class InterfaceVLANSerializer(WritableNestedSerializer): fields = ['id', 'url', 'vid', 'name', 'display_name'] -class InterfaceSerializer(TaggitSerializer, IsConnectedMixin, ValidatedModelSerializer): +class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer): device = NestedDeviceSerializer() form_factor = ChoiceField(choices=IFACE_FF_CHOICES, required=False) lag = NestedInterfaceSerializer(required=False, allow_null=True) connected_endpoint = NestedInterfaceSerializer(read_only=True) - is_connected = serializers.SerializerMethodField(read_only=True) circuit_termination = InterfaceCircuitTerminationSerializer(read_only=True) mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True) untagged_vlan = InterfaceVLANSerializer(required=False, allow_null=True) @@ -733,8 +700,7 @@ class InterfaceSerializer(TaggitSerializer, IsConnectedMixin, ValidatedModelSeri model = Interface fields = [ 'id', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description', - 'is_connected', 'connected_endpoint', 'circuit_termination', 'cable', 'mode', 'untagged_vlan', - 'tagged_vlans', 'tags', + 'connected_endpoint', 'circuit_termination', 'cable', 'mode', 'untagged_vlan', 'tagged_vlans', 'tags', ] def validate(self, data): @@ -778,7 +744,7 @@ class NestedRearPortSerializer(WritableNestedSerializer): class Meta: model = RearPort - fields = ['id', 'url', 'device', 'name'] + fields = ['id', 'url', 'device', 'name', 'cable'] # @@ -811,7 +777,7 @@ class NestedFrontPortSerializer(WritableNestedSerializer): class Meta: model = FrontPort - fields = ['id', 'url', 'device', 'name'] + fields = ['id', 'url', 'device', 'name', 'cable'] # diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 8db4ceb4f..3650cf0a1 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -1402,7 +1402,7 @@ class ConsolePortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelF label='Port', widget=APISelect( api_url='/api/dcim/console-server-ports/?device_id={{console_server}}', - disabled_indicator='is_connected', + disabled_indicator='cable', ) ) @@ -1493,7 +1493,7 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms. label='Port', widget=APISelect( api_url='/api/dcim/console-ports/?device_id={{device}}', - disabled_indicator='is_connected' + disabled_indicator='cable' ) ) connection_status = forms.BooleanField( @@ -1671,7 +1671,7 @@ class PowerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor label='Outlet', widget=APISelect( api_url='/api/dcim/power-outlets/?device_id={{pdu}}', - disabled_indicator='is_connected' + disabled_indicator='cable' ) ) @@ -1762,7 +1762,7 @@ class PowerOutletConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.Form): label='Port', widget=APISelect( api_url='/api/dcim/power-ports/?device_id={{device}}', - disabled_indicator='is_connected' + disabled_indicator='cable' ) ) connection_status = forms.BooleanField( @@ -2171,7 +2171,7 @@ class CableCreateForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): label='Name', widget=APISelect( api_url='/api/dcim/{{termination_b_type}}s/?device_id={{termination_b_device}}', - disabled_indicator='is_connected' + disabled_indicator='cable' ) ) diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index d1df21ca9..e8f00c830 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -1888,7 +1888,9 @@ class Interface(CableTermination, ComponentModel): }) # Virtual interfaces cannot be connected - if self.form_factor in NONCONNECTABLE_IFACE_TYPES and self.is_connected: + if self.form_factor in NONCONNECTABLE_IFACE_TYPES and ( + self.cable or getattr(self, 'circuit_termination', False) + ): raise ValidationError({ 'form_factor': "Virtual and wireless interfaces cannot be connected to another interface or circuit. " "Disconnect the interface or choose a suitable form factor." @@ -1977,14 +1979,6 @@ class Interface(CableTermination, ComponentModel): def is_lag(self): return self.form_factor == IFACE_FF_LAG - @property - def is_connected(self): - try: - return bool(self.circuit_termination) - except ObjectDoesNotExist: - pass - return bool(self.connected_endpoint) - # # Pass-through ports diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 389797a09..d63348751 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -1953,7 +1953,7 @@ class ConsolePortTest(APITestCase): self.assertEqual( sorted(response.data['results'][0]), - ['device', 'id', 'is_connected', 'name', 'url'] + ['cable', 'device', 'id', 'name', 'url'] ) def test_create_consoleport(self): @@ -2068,7 +2068,7 @@ class ConsoleServerPortTest(APITestCase): self.assertEqual( sorted(response.data['results'][0]), - ['device', 'id', 'is_connected', 'name', 'url'] + ['cable', 'device', 'id', 'name', 'url'] ) def test_create_consoleserverport(self): @@ -2179,7 +2179,7 @@ class PowerPortTest(APITestCase): self.assertEqual( sorted(response.data['results'][0]), - ['device', 'id', 'is_connected', 'name', 'url'] + ['cable', 'device', 'id', 'name', 'url'] ) def test_create_powerport(self): @@ -2294,7 +2294,7 @@ class PowerOutletTest(APITestCase): self.assertEqual( sorted(response.data['results'][0]), - ['device', 'id', 'is_connected', 'name', 'url'] + ['cable', 'device', 'id', 'name', 'url'] ) def test_create_poweroutlet(self): @@ -2431,7 +2431,7 @@ class InterfaceTest(APITestCase): self.assertEqual( sorted(response.data['results'][0]), - ['device', 'id', 'is_connected', 'name', 'url'] + ['cable', 'device', 'id', 'name', 'url'] ) def test_create_interface(self):