Просмотр исходного кода

#8272: Cleanup & add filter for bridge_id

jeremystretch 2 лет назад
Родитель
Сommit
0455654f71

+ 6 - 3
netbox/dcim/api/serializers.py

@@ -475,7 +475,10 @@ class InterfaceTemplateSerializer(ValidatedModelSerializer):
         default=None
         default=None
     )
     )
     type = ChoiceField(choices=InterfaceTypeChoices)
     type = ChoiceField(choices=InterfaceTypeChoices)
-    bridge = NestedInterfaceTemplateSerializer(required=False, allow_null=True)
+    bridge = NestedInterfaceTemplateSerializer(
+        required=False,
+        allow_null=True
+    )
     poe_mode = ChoiceField(
     poe_mode = ChoiceField(
         choices=InterfacePoEModeChoices,
         choices=InterfacePoEModeChoices,
         required=False,
         required=False,
@@ -490,8 +493,8 @@ class InterfaceTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = InterfaceTemplate
         model = InterfaceTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'bridge', 'enabled', 'mgmt_only', 'description',
-            'poe_mode', 'poe_type', 'created', 'last_updated',
+            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only',
+            'description', 'bridge', 'poe_mode', 'poe_type', 'created', 'last_updated',
         ]
         ]
 
 
 
 

+ 4 - 0
netbox/dcim/filtersets.py

@@ -685,6 +685,10 @@ class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeCo
         choices=InterfaceTypeChoices,
         choices=InterfaceTypeChoices,
         null_value=None
         null_value=None
     )
     )
+    bridge_id = django_filters.ModelMultipleChoiceFilter(
+        field_name='bridge',
+        queryset=InterfaceTemplate.objects.all()
+    )
     poe_mode = django_filters.MultipleChoiceFilter(
     poe_mode = django_filters.MultipleChoiceFilter(
         choices=InterfacePoEModeChoices
         choices=InterfacePoEModeChoices
     )
     )

+ 2 - 0
netbox/dcim/models/device_component_templates.py

@@ -377,6 +377,8 @@ class InterfaceTemplate(ModularComponentTemplateModel):
         super().clean()
         super().clean()
 
 
         if self.bridge:
         if self.bridge:
+            if self.pk and self.bridge_id == self.pk:
+                raise ValidationError({'bridge': "An interface cannot be bridged to itself."})
             if self.device_type and self.device_type != self.bridge.device_type:
             if self.device_type and self.device_type != self.bridge.device_type:
                 raise ValidationError({
                 raise ValidationError({
                     'bridge': f"Bridge interface ({self.bridge}) must belong to the same device type"
                     'bridge': f"Bridge interface ({self.bridge}) must belong to the same device type"

+ 34 - 5
netbox/dcim/tests/test_filtersets.py

@@ -1142,11 +1142,36 @@ class InterfaceTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
         )
         )
         DeviceType.objects.bulk_create(device_types)
         DeviceType.objects.bulk_create(device_types)
 
 
-        InterfaceTemplate.objects.bulk_create((
-            InterfaceTemplate(device_type=device_types[0], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED, enabled=True, mgmt_only=True, poe_mode=InterfacePoEModeChoices.MODE_PD, poe_type=InterfacePoETypeChoices.TYPE_1_8023AF),
-            InterfaceTemplate(device_type=device_types[1], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_GBIC, enabled=False, mgmt_only=False, poe_mode=InterfacePoEModeChoices.MODE_PSE, poe_type=InterfacePoETypeChoices.TYPE_2_8023AT),
-            InterfaceTemplate(device_type=device_types[2], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_SFP, mgmt_only=False),
-        ))
+        interface_templates = (
+            InterfaceTemplate(
+                device_type=device_types[0],
+                name='Interface 1',
+                type=InterfaceTypeChoices.TYPE_1GE_FIXED,
+                enabled=True,
+                mgmt_only=True,
+                poe_mode=InterfacePoEModeChoices.MODE_PD,
+                poe_type=InterfacePoETypeChoices.TYPE_1_8023AF
+            ),
+            InterfaceTemplate(
+                device_type=device_types[1],
+                name='Interface 2',
+                type=InterfaceTypeChoices.TYPE_1GE_GBIC,
+                enabled=False,
+                mgmt_only=False,
+                poe_mode=InterfacePoEModeChoices.MODE_PSE,
+                poe_type=InterfacePoETypeChoices.TYPE_2_8023AT
+            ),
+            InterfaceTemplate(
+                device_type=device_types[2],
+                name='Interface 3',
+                type=InterfaceTypeChoices.TYPE_1GE_SFP,
+                mgmt_only=False
+            ),
+        )
+        InterfaceTemplate.objects.bulk_create(interface_templates)
+        interface_templates[0].bridge = interface_templates[1]
+        interface_templates[1].bridge = interface_templates[0]
+        InterfaceTemplate.objects.bulk_update(interface_templates, ['bridge'])
 
 
     def test_name(self):
     def test_name(self):
         params = {'name': ['Interface 1', 'Interface 2']}
         params = {'name': ['Interface 1', 'Interface 2']}
@@ -1173,6 +1198,10 @@ class InterfaceTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
         params = {'mgmt_only': 'false'}
         params = {'mgmt_only': 'false'}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
 
 
+    def test_bridge(self):
+        params = {'bridge_id': [InterfaceTemplate.objects.filter(bridge__isnull=False).first().bridge_id]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
+
     def test_poe_mode(self):
     def test_poe_mode(self):
         params = {'poe_mode': [InterfacePoEModeChoices.MODE_PD, InterfacePoEModeChoices.MODE_PSE]}
         params = {'poe_mode': [InterfacePoEModeChoices.MODE_PD, InterfacePoEModeChoices.MODE_PSE]}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)