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

#7853 - Initial work on Speed/Duplex.

TODO: Documentation, Tests, Form order
Daniel Sheppard 4 лет назад
Родитель
Сommit
0f58faaddb

+ 2 - 1
netbox/dcim/api/serializers.py

@@ -721,6 +721,7 @@ class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
     bridge = NestedInterfaceSerializer(required=False, allow_null=True)
     lag = NestedInterfaceSerializer(required=False, allow_null=True)
     mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
+    duplex = ChoiceField(choices=InterfaceDuplexChoices, allow_blank=True, required=False)
     rf_role = ChoiceField(choices=WirelessRoleChoices, required=False, allow_null=True)
     rf_channel = ChoiceField(choices=WirelessChannelChoices, required=False)
     untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
@@ -746,7 +747,7 @@ class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
         model = Interface
         fields = [
             'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge', 'lag',
-            'mtu', 'mac_address', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel',
+            'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel',
             'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'untagged_vlan', 'tagged_vlans', 'mark_connected',
             'cable', 'wireless_link', 'link_peer', 'link_peer_type', 'wireless_lans', 'vrf', 'connected_endpoint',
             'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields', 'created',

+ 13 - 0
netbox/dcim/choices.py

@@ -943,6 +943,19 @@ class InterfaceTypeChoices(ChoiceSet):
     )
 
 
+class InterfaceDuplexChoices(ChoiceSet):
+
+    DUPLEX_HALF = 'half'
+    DUPLEX_FULL = 'full'
+    DUPLEX_AUTO = 'auto'
+
+    CHOICES = (
+        (DUPLEX_HALF, 'Half'),
+        (DUPLEX_FULL, 'Full'),
+        (DUPLEX_AUTO, 'Auto'),
+    )
+
+
 class InterfaceModeChoices(ChoiceSet):
 
     MODE_ACCESS = 'access'

+ 2 - 0
netbox/dcim/filtersets.py

@@ -1196,6 +1196,8 @@ class InterfaceFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableT
         queryset=Interface.objects.all(),
         label='LAG interface (ID)',
     )
+    speed = MultiValueNumberFilter()
+    duplex = django_filters.CharFilter()
     mac_address = MultiValueMACAddressFilter()
     wwn = MultiValueWWNFilter()
     tag = TagFilter()

+ 2 - 2
netbox/dcim/forms/bulk_create.py

@@ -72,12 +72,12 @@ class PowerOutletBulkCreateForm(
 
 
 class InterfaceBulkCreateForm(
-    form_from_model(Interface, ['type', 'enabled', 'mtu', 'mgmt_only', 'mark_connected']),
+    form_from_model(Interface, ['type', 'enabled', 'speed', 'duplex', 'mtu', 'mgmt_only', 'mark_connected']),
     DeviceBulkAddComponentForm
 ):
     model = Interface
     field_order = (
-        'name_pattern', 'label_pattern', 'type', 'enabled', 'mtu', 'mgmt_only', 'mark_connected', 'description', 'tags',
+        'name_pattern', 'label_pattern', 'type', 'enabled', 'speed', 'duplex', 'mtu', 'mgmt_only', 'mark_connected', 'description', 'tags',
     )
 
 

+ 8 - 3
netbox/dcim/forms/bulk_edit.py

@@ -11,7 +11,7 @@ from ipam.models import ASN, VLAN, VRF
 from tenancy.models import Tenant
 from utilities.forms import (
     add_blank_choice, BulkEditForm, BulkEditNullBooleanSelect, ColorField, CommentField, DynamicModelChoiceField,
-    DynamicModelMultipleChoiceField, form_from_model, SmallTextarea, StaticSelect,
+    DynamicModelMultipleChoiceField, form_from_model, SmallTextarea, StaticSelect, SelectSpeedWidget,
 )
 
 __all__ = (
@@ -1028,7 +1028,7 @@ class PowerOutletBulkEditForm(
 
 class InterfaceBulkEditForm(
     form_from_model(Interface, [
-        'label', 'type', 'parent', 'bridge', 'lag', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'mark_connected',
+        'label', 'type', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'mark_connected',
         'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
     ]),
     AddRemoveTagsForm,
@@ -1064,6 +1064,11 @@ class InterfaceBulkEditForm(
         },
         label='LAG'
     )
+    speed = forms.IntegerField(
+        required=False,
+        widget=SelectSpeedWidget(attrs={'readonly': None}),
+        label='Speed'
+    )
     mgmt_only = forms.NullBooleanField(
         required=False,
         widget=BulkEditNullBooleanSelect,
@@ -1089,7 +1094,7 @@ class InterfaceBulkEditForm(
 
     class Meta:
         nullable_fields = [
-            'label', 'parent', 'bridge', 'lag', 'mac_address', 'wwn', 'mtu', 'description', 'mode', 'rf_channel',
+            'label', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'description', 'mode', 'rf_channel',
             'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'untagged_vlan', 'tagged_vlans', 'vrf',
         ]
 

+ 5 - 1
netbox/dcim/forms/bulk_import.py

@@ -618,6 +618,10 @@ class InterfaceCSVForm(CustomFieldModelCSVForm):
         choices=InterfaceTypeChoices,
         help_text='Physical medium'
     )
+    duplex = CSVChoiceField(
+        choices=InterfaceDuplexChoices,
+        help_text='Duplex'
+    )
     mode = CSVChoiceField(
         choices=InterfaceModeChoices,
         required=False,
@@ -638,7 +642,7 @@ class InterfaceCSVForm(CustomFieldModelCSVForm):
     class Meta:
         model = Interface
         fields = (
-            'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'enabled', 'mark_connected', 'mac_address',
+            'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled', 'mark_connected', 'mac_address',
             'wwn', 'mtu', 'mgmt_only', 'description', 'mode', 'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency',
             'rf_channel_width', 'tx_power',
         )

+ 12 - 2
netbox/dcim/forms/filtersets.py

@@ -10,7 +10,7 @@ from ipam.models import ASN, VRF
 from tenancy.forms import TenancyFilterForm
 from utilities.forms import (
     APISelectMultiple, add_blank_choice, ColorField, DynamicModelMultipleChoiceField, FilterForm, StaticSelect,
-    StaticSelectMultiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
+    StaticSelectMultiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES, SelectSpeedWidget,
 )
 from wireless.choices import *
 
@@ -920,7 +920,7 @@ class InterfaceFilterForm(DeviceComponentFilterForm):
     model = Interface
     field_groups = [
         ['q', 'tag'],
-        ['name', 'label', 'kind', 'type', 'enabled', 'mgmt_only'],
+        ['name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only'],
         ['vrf_id', 'mac_address', 'wwn'],
         ['rf_role', 'rf_channel', 'rf_channel_width', 'tx_power'],
         ['region_id', 'site_group_id', 'site_id', 'location_id', 'virtual_chassis_id', 'device_id'],
@@ -935,6 +935,16 @@ class InterfaceFilterForm(DeviceComponentFilterForm):
         required=False,
         widget=StaticSelectMultiple()
     )
+    speed = forms.IntegerField(
+        required=False,
+        label='Select Speed',
+        widget=SelectSpeedWidget(attrs={'readonly': None})
+    )
+    duplex = forms.ChoiceField(
+        choices=InterfaceDuplexChoices,
+        required=False,
+        label='Select Duplex'
+    )
     enabled = forms.NullBooleanField(
         required=False,
         widget=StaticSelect(

+ 4 - 3
netbox/dcim/forms/models.py

@@ -14,7 +14,7 @@ from tenancy.forms import TenancyForm
 from utilities.forms import (
     APISelect, add_blank_choice, BootstrapMixin, ClearableFileInput, CommentField, ContentTypeChoiceField,
     DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, NumericArrayField, SelectWithPK, SmallTextarea,
-    SlugField, StaticSelect,
+    SlugField, StaticSelect, SelectSpeedWidget,
 )
 from virtualization.models import Cluster, ClusterGroup
 from wireless.models import WirelessLAN, WirelessLANGroup
@@ -1274,12 +1274,12 @@ class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm):
     class Meta:
         model = Interface
         fields = [
-            'device', 'name', 'label', 'type', 'enabled', 'parent', 'bridge', 'lag', 'mac_address', 'wwn', 'mtu',
+            'device', 'name', 'label', 'type', 'speed', 'duplex', 'enabled', 'parent', 'bridge', 'lag', 'mac_address', 'wwn', 'mtu',
             'mgmt_only', 'mark_connected', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency',
             'rf_channel_width', 'tx_power', 'wireless_lans', 'untagged_vlan', 'tagged_vlans', 'vrf', 'tags',
         ]
         fieldsets = (
-            ('Interface', ('device', 'name', 'type', 'label', 'description', 'tags')),
+            ('Interface', ('device', 'name', 'type', 'speed', 'duplex', 'label', 'description', 'tags')),
             ('Addressing', ('vrf', 'mac_address', 'wwn')),
             ('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')),
             ('Related Interfaces', ('parent', 'bridge', 'lag')),
@@ -1295,6 +1295,7 @@ class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm):
             'mode': StaticSelect(),
             'rf_role': StaticSelect(),
             'rf_channel': StaticSelect(),
+            'speed': SelectSpeedWidget(attrs={'readonly': None}),
         }
         labels = {
             'mode': '802.1Q Mode',

+ 23 - 0
netbox/dcim/migrations/0150_interface_speed_duplex.py

@@ -0,0 +1,23 @@
+# Generated by Django 3.2.10 on 2022-01-08 18:23
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dcim', '0149_interface_vrf'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='interface',
+            name='duplex',
+            field=models.CharField(blank=True, max_length=50, null=True),
+        ),
+        migrations.AddField(
+            model_name='interface',
+            name='speed',
+            field=models.PositiveIntegerField(blank=True, null=True),
+        ),
+    ]

+ 12 - 0
netbox/dcim/models/device_components.py

@@ -551,6 +551,18 @@ class Interface(ModularComponentModel, BaseInterface, LinkTermination, PathEndpo
         verbose_name='Management only',
         help_text='This interface is used only for out-of-band management'
     )
+    speed = models.PositiveIntegerField(
+        verbose_name='Speed',
+        blank=True,
+        null=True
+    )
+    duplex = models.CharField(
+        verbose_name='Duplex',
+        max_length=50,
+        blank=True,
+        null=True,
+        choices=InterfaceDuplexChoices
+    )
     wwn = WWNField(
         null=True,
         blank=True,

+ 8 - 0
netbox/templates/dcim/interface.html

@@ -46,6 +46,14 @@
                             <th scope="row">Type</th>
                             <td>{{ object.get_type_display }}</td>
                         </tr>
+                        <tr>
+                            <th scope="row">Speed</th>
+                            <td>{{ object.speed|humanize_speed|placeholder }}</td>
+                        </tr>
+                        <tr>
+                            <th scope="row">Duplex</th>
+                            <td>{{ object.get_duplex_display }}</td>
+                        </tr>
                         <tr>
                             <th scope="row">Enabled</th>
                             <td>{% checkmark object.enabled %}</td>

+ 2 - 0
netbox/templates/dcim/interface_edit.html

@@ -16,6 +16,8 @@
         {% endif %}
         {% render_field form.name %}
         {% render_field form.type %}
+        {% render_field form.speed %}
+        {% render_field form.duplex %}
         {% render_field form.label %}
         {% render_field form.description %}
         {% render_field form.tags %}