瀏覽代碼

Replace 'is_connected' boolean with Cable attachment

Jeremy Stretch 7 年之前
父節點
當前提交
d7766b9828
共有 5 個文件被更改,包括 26 次插入66 次删除
  1. 3 3
      netbox/circuits/forms.py
  2. 10 44
      netbox/dcim/api/serializers.py
  3. 5 5
      netbox/dcim/forms.py
  4. 3 9
      netbox/dcim/models.py
  5. 5 5
      netbox/dcim/tests/test_api.py

+ 3 - 3
netbox/circuits/forms.py

@@ -245,7 +245,7 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm
         label='Interface',
         label='Interface',
         widget=APISelect(
         widget=APISelect(
             api_url='/api/dcim/interfaces/?device_id={{device}}&type=physical',
             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)
         super(CircuitTerminationForm, self).__init__(*args, **kwargs)
 
 
-        # Mark connected interfaces as disabled
+        # Mark occupied interfaces as disabled
         self.fields['interface'].choices = []
         self.fields['interface'].choices = []
         for iface in self.fields['interface'].queryset:
         for iface in self.fields['interface'].queryset:
             self.fields['interface'].choices.append(
             self.fields['interface'].choices.append(
                 (iface.id, {
                 (iface.id, {
                     'label': iface.name,
                     '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'),
                 })
                 })
             )
             )

+ 10 - 44
netbox/dcim/api/serializers.py

@@ -559,14 +559,10 @@ class ConsoleServerPortSerializer(TaggitSerializer, ValidatedModelSerializer):
 class NestedConsoleServerPortSerializer(WritableNestedSerializer):
 class NestedConsoleServerPortSerializer(WritableNestedSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
-    is_connected = serializers.SerializerMethodField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = ConsoleServerPort
         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):
 class NestedConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail')
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
-    is_connected = serializers.SerializerMethodField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = ConsolePort
         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):
 class NestedPowerOutletSerializer(WritableNestedSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
-    is_connected = serializers.SerializerMethodField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = PowerOutlet
         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):
 class NestedPowerPortSerializer(TaggitSerializer, ValidatedModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail')
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
-    is_connected = serializers.SerializerMethodField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = PowerPort
         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
 # 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)
     device = NestedDeviceSerializer(read_only=True)
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
     url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
-    is_connected = serializers.SerializerMethodField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = Interface
         model = Interface
-        fields = ['id', 'url', 'device', 'name', 'is_connected']
+        fields = ['id', 'url', 'device', 'name', 'cable']
 
 
 
 
 class InterfaceNestedCircuitSerializer(serializers.ModelSerializer):
 class InterfaceNestedCircuitSerializer(serializers.ModelSerializer):
@@ -711,12 +679,11 @@ class InterfaceVLANSerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'vid', 'name', 'display_name']
         fields = ['id', 'url', 'vid', 'name', 'display_name']
 
 
 
 
-class InterfaceSerializer(TaggitSerializer, IsConnectedMixin, ValidatedModelSerializer):
+class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer):
     device = NestedDeviceSerializer()
     device = NestedDeviceSerializer()
     form_factor = ChoiceField(choices=IFACE_FF_CHOICES, required=False)
     form_factor = ChoiceField(choices=IFACE_FF_CHOICES, required=False)
     lag = NestedInterfaceSerializer(required=False, allow_null=True)
     lag = NestedInterfaceSerializer(required=False, allow_null=True)
     connected_endpoint = NestedInterfaceSerializer(read_only=True)
     connected_endpoint = NestedInterfaceSerializer(read_only=True)
-    is_connected = serializers.SerializerMethodField(read_only=True)
     circuit_termination = InterfaceCircuitTerminationSerializer(read_only=True)
     circuit_termination = InterfaceCircuitTerminationSerializer(read_only=True)
     mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True)
     mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True)
     untagged_vlan = InterfaceVLANSerializer(required=False, allow_null=True)
     untagged_vlan = InterfaceVLANSerializer(required=False, allow_null=True)
@@ -733,8 +700,7 @@ class InterfaceSerializer(TaggitSerializer, IsConnectedMixin, ValidatedModelSeri
         model = Interface
         model = Interface
         fields = [
         fields = [
             'id', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description',
             '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):
     def validate(self, data):
@@ -778,7 +744,7 @@ class NestedRearPortSerializer(WritableNestedSerializer):
 
 
     class Meta:
     class Meta:
         model = RearPort
         model = RearPort
-        fields = ['id', 'url', 'device', 'name']
+        fields = ['id', 'url', 'device', 'name', 'cable']
 
 
 
 
 #
 #
@@ -811,7 +777,7 @@ class NestedFrontPortSerializer(WritableNestedSerializer):
 
 
     class Meta:
     class Meta:
         model = FrontPort
         model = FrontPort
-        fields = ['id', 'url', 'device', 'name']
+        fields = ['id', 'url', 'device', 'name', 'cable']
 
 
 
 
 #
 #

+ 5 - 5
netbox/dcim/forms.py

@@ -1402,7 +1402,7 @@ class ConsolePortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelF
         label='Port',
         label='Port',
         widget=APISelect(
         widget=APISelect(
             api_url='/api/dcim/console-server-ports/?device_id={{console_server}}',
             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',
         label='Port',
         widget=APISelect(
         widget=APISelect(
             api_url='/api/dcim/console-ports/?device_id={{device}}',
             api_url='/api/dcim/console-ports/?device_id={{device}}',
-            disabled_indicator='is_connected'
+            disabled_indicator='cable'
         )
         )
     )
     )
     connection_status = forms.BooleanField(
     connection_status = forms.BooleanField(
@@ -1671,7 +1671,7 @@ class PowerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor
         label='Outlet',
         label='Outlet',
         widget=APISelect(
         widget=APISelect(
             api_url='/api/dcim/power-outlets/?device_id={{pdu}}',
             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',
         label='Port',
         widget=APISelect(
         widget=APISelect(
             api_url='/api/dcim/power-ports/?device_id={{device}}',
             api_url='/api/dcim/power-ports/?device_id={{device}}',
-            disabled_indicator='is_connected'
+            disabled_indicator='cable'
         )
         )
     )
     )
     connection_status = forms.BooleanField(
     connection_status = forms.BooleanField(
@@ -2171,7 +2171,7 @@ class CableCreateForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm):
         label='Name',
         label='Name',
         widget=APISelect(
         widget=APISelect(
             api_url='/api/dcim/{{termination_b_type}}s/?device_id={{termination_b_device}}',
             api_url='/api/dcim/{{termination_b_type}}s/?device_id={{termination_b_device}}',
-            disabled_indicator='is_connected'
+            disabled_indicator='cable'
         )
         )
     )
     )
 
 

+ 3 - 9
netbox/dcim/models.py

@@ -1888,7 +1888,9 @@ class Interface(CableTermination, ComponentModel):
             })
             })
 
 
         # Virtual interfaces cannot be connected
         # 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({
             raise ValidationError({
                 'form_factor': "Virtual and wireless interfaces cannot be connected to another interface or circuit. "
                 'form_factor': "Virtual and wireless interfaces cannot be connected to another interface or circuit. "
                                "Disconnect the interface or choose a suitable form factor."
                                "Disconnect the interface or choose a suitable form factor."
@@ -1977,14 +1979,6 @@ class Interface(CableTermination, ComponentModel):
     def is_lag(self):
     def is_lag(self):
         return self.form_factor == IFACE_FF_LAG
         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
 # Pass-through ports

+ 5 - 5
netbox/dcim/tests/test_api.py

@@ -1953,7 +1953,7 @@ class ConsolePortTest(APITestCase):
 
 
         self.assertEqual(
         self.assertEqual(
             sorted(response.data['results'][0]),
             sorted(response.data['results'][0]),
-            ['device', 'id', 'is_connected', 'name', 'url']
+            ['cable', 'device', 'id', 'name', 'url']
         )
         )
 
 
     def test_create_consoleport(self):
     def test_create_consoleport(self):
@@ -2068,7 +2068,7 @@ class ConsoleServerPortTest(APITestCase):
 
 
         self.assertEqual(
         self.assertEqual(
             sorted(response.data['results'][0]),
             sorted(response.data['results'][0]),
-            ['device', 'id', 'is_connected', 'name', 'url']
+            ['cable', 'device', 'id', 'name', 'url']
         )
         )
 
 
     def test_create_consoleserverport(self):
     def test_create_consoleserverport(self):
@@ -2179,7 +2179,7 @@ class PowerPortTest(APITestCase):
 
 
         self.assertEqual(
         self.assertEqual(
             sorted(response.data['results'][0]),
             sorted(response.data['results'][0]),
-            ['device', 'id', 'is_connected', 'name', 'url']
+            ['cable', 'device', 'id', 'name', 'url']
         )
         )
 
 
     def test_create_powerport(self):
     def test_create_powerport(self):
@@ -2294,7 +2294,7 @@ class PowerOutletTest(APITestCase):
 
 
         self.assertEqual(
         self.assertEqual(
             sorted(response.data['results'][0]),
             sorted(response.data['results'][0]),
-            ['device', 'id', 'is_connected', 'name', 'url']
+            ['cable', 'device', 'id', 'name', 'url']
         )
         )
 
 
     def test_create_poweroutlet(self):
     def test_create_poweroutlet(self):
@@ -2431,7 +2431,7 @@ class InterfaceTest(APITestCase):
 
 
         self.assertEqual(
         self.assertEqual(
             sorted(response.data['results'][0]),
             sorted(response.data['results'][0]),
-            ['device', 'id', 'is_connected', 'name', 'url']
+            ['cable', 'device', 'id', 'name', 'url']
         )
         )
 
 
     def test_create_interface(self):
     def test_create_interface(self):