mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
#7853 - Initial work on Speed/Duplex.
TODO: Documentation, Tests, Form order
This commit is contained in:
@ -721,6 +721,7 @@ class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
|
|||||||
bridge = NestedInterfaceSerializer(required=False, allow_null=True)
|
bridge = NestedInterfaceSerializer(required=False, allow_null=True)
|
||||||
lag = NestedInterfaceSerializer(required=False, allow_null=True)
|
lag = NestedInterfaceSerializer(required=False, allow_null=True)
|
||||||
mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
|
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_role = ChoiceField(choices=WirelessRoleChoices, required=False, allow_null=True)
|
||||||
rf_channel = ChoiceField(choices=WirelessChannelChoices, required=False)
|
rf_channel = ChoiceField(choices=WirelessChannelChoices, required=False)
|
||||||
untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
|
untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
|
||||||
@ -746,7 +747,7 @@ class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
|
|||||||
model = Interface
|
model = Interface
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge', 'lag',
|
'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',
|
'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',
|
'cable', 'wireless_link', 'link_peer', 'link_peer_type', 'wireless_lans', 'vrf', 'connected_endpoint',
|
||||||
'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields', 'created',
|
'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields', 'created',
|
||||||
|
@ -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):
|
class InterfaceModeChoices(ChoiceSet):
|
||||||
|
|
||||||
MODE_ACCESS = 'access'
|
MODE_ACCESS = 'access'
|
||||||
|
@ -1196,6 +1196,8 @@ class InterfaceFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableT
|
|||||||
queryset=Interface.objects.all(),
|
queryset=Interface.objects.all(),
|
||||||
label='LAG interface (ID)',
|
label='LAG interface (ID)',
|
||||||
)
|
)
|
||||||
|
speed = MultiValueNumberFilter()
|
||||||
|
duplex = django_filters.CharFilter()
|
||||||
mac_address = MultiValueMACAddressFilter()
|
mac_address = MultiValueMACAddressFilter()
|
||||||
wwn = MultiValueWWNFilter()
|
wwn = MultiValueWWNFilter()
|
||||||
tag = TagFilter()
|
tag = TagFilter()
|
||||||
|
@ -72,12 +72,12 @@ class PowerOutletBulkCreateForm(
|
|||||||
|
|
||||||
|
|
||||||
class InterfaceBulkCreateForm(
|
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
|
DeviceBulkAddComponentForm
|
||||||
):
|
):
|
||||||
model = Interface
|
model = Interface
|
||||||
field_order = (
|
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',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ from ipam.models import ASN, VLAN, VRF
|
|||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
add_blank_choice, BulkEditForm, BulkEditNullBooleanSelect, ColorField, CommentField, DynamicModelChoiceField,
|
add_blank_choice, BulkEditForm, BulkEditNullBooleanSelect, ColorField, CommentField, DynamicModelChoiceField,
|
||||||
DynamicModelMultipleChoiceField, form_from_model, SmallTextarea, StaticSelect,
|
DynamicModelMultipleChoiceField, form_from_model, SmallTextarea, StaticSelect, SelectSpeedWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -1028,7 +1028,7 @@ class PowerOutletBulkEditForm(
|
|||||||
|
|
||||||
class InterfaceBulkEditForm(
|
class InterfaceBulkEditForm(
|
||||||
form_from_model(Interface, [
|
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',
|
'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
|
||||||
]),
|
]),
|
||||||
AddRemoveTagsForm,
|
AddRemoveTagsForm,
|
||||||
@ -1064,6 +1064,11 @@ class InterfaceBulkEditForm(
|
|||||||
},
|
},
|
||||||
label='LAG'
|
label='LAG'
|
||||||
)
|
)
|
||||||
|
speed = forms.IntegerField(
|
||||||
|
required=False,
|
||||||
|
widget=SelectSpeedWidget(attrs={'readonly': None}),
|
||||||
|
label='Speed'
|
||||||
|
)
|
||||||
mgmt_only = forms.NullBooleanField(
|
mgmt_only = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
widget=BulkEditNullBooleanSelect,
|
widget=BulkEditNullBooleanSelect,
|
||||||
@ -1089,7 +1094,7 @@ class InterfaceBulkEditForm(
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
nullable_fields = [
|
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',
|
'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'untagged_vlan', 'tagged_vlans', 'vrf',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -618,6 +618,10 @@ class InterfaceCSVForm(CustomFieldModelCSVForm):
|
|||||||
choices=InterfaceTypeChoices,
|
choices=InterfaceTypeChoices,
|
||||||
help_text='Physical medium'
|
help_text='Physical medium'
|
||||||
)
|
)
|
||||||
|
duplex = CSVChoiceField(
|
||||||
|
choices=InterfaceDuplexChoices,
|
||||||
|
help_text='Duplex'
|
||||||
|
)
|
||||||
mode = CSVChoiceField(
|
mode = CSVChoiceField(
|
||||||
choices=InterfaceModeChoices,
|
choices=InterfaceModeChoices,
|
||||||
required=False,
|
required=False,
|
||||||
@ -638,7 +642,7 @@ class InterfaceCSVForm(CustomFieldModelCSVForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Interface
|
model = Interface
|
||||||
fields = (
|
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',
|
'wwn', 'mtu', 'mgmt_only', 'description', 'mode', 'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency',
|
||||||
'rf_channel_width', 'tx_power',
|
'rf_channel_width', 'tx_power',
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,7 @@ from ipam.models import ASN, VRF
|
|||||||
from tenancy.forms import TenancyFilterForm
|
from tenancy.forms import TenancyFilterForm
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
APISelectMultiple, add_blank_choice, ColorField, DynamicModelMultipleChoiceField, FilterForm, StaticSelect,
|
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 *
|
from wireless.choices import *
|
||||||
|
|
||||||
@ -920,7 +920,7 @@ class InterfaceFilterForm(DeviceComponentFilterForm):
|
|||||||
model = Interface
|
model = Interface
|
||||||
field_groups = [
|
field_groups = [
|
||||||
['q', 'tag'],
|
['q', 'tag'],
|
||||||
['name', 'label', 'kind', 'type', 'enabled', 'mgmt_only'],
|
['name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only'],
|
||||||
['vrf_id', 'mac_address', 'wwn'],
|
['vrf_id', 'mac_address', 'wwn'],
|
||||||
['rf_role', 'rf_channel', 'rf_channel_width', 'tx_power'],
|
['rf_role', 'rf_channel', 'rf_channel_width', 'tx_power'],
|
||||||
['region_id', 'site_group_id', 'site_id', 'location_id', 'virtual_chassis_id', 'device_id'],
|
['region_id', 'site_group_id', 'site_id', 'location_id', 'virtual_chassis_id', 'device_id'],
|
||||||
@ -935,6 +935,16 @@ class InterfaceFilterForm(DeviceComponentFilterForm):
|
|||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelectMultiple()
|
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(
|
enabled = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelect(
|
widget=StaticSelect(
|
||||||
|
@ -14,7 +14,7 @@ from tenancy.forms import TenancyForm
|
|||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
APISelect, add_blank_choice, BootstrapMixin, ClearableFileInput, CommentField, ContentTypeChoiceField,
|
APISelect, add_blank_choice, BootstrapMixin, ClearableFileInput, CommentField, ContentTypeChoiceField,
|
||||||
DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, NumericArrayField, SelectWithPK, SmallTextarea,
|
DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, NumericArrayField, SelectWithPK, SmallTextarea,
|
||||||
SlugField, StaticSelect,
|
SlugField, StaticSelect, SelectSpeedWidget,
|
||||||
)
|
)
|
||||||
from virtualization.models import Cluster, ClusterGroup
|
from virtualization.models import Cluster, ClusterGroup
|
||||||
from wireless.models import WirelessLAN, WirelessLANGroup
|
from wireless.models import WirelessLAN, WirelessLANGroup
|
||||||
@ -1274,12 +1274,12 @@ class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Interface
|
model = Interface
|
||||||
fields = [
|
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',
|
'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',
|
'rf_channel_width', 'tx_power', 'wireless_lans', 'untagged_vlan', 'tagged_vlans', 'vrf', 'tags',
|
||||||
]
|
]
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Interface', ('device', 'name', 'type', 'label', 'description', 'tags')),
|
('Interface', ('device', 'name', 'type', 'speed', 'duplex', 'label', 'description', 'tags')),
|
||||||
('Addressing', ('vrf', 'mac_address', 'wwn')),
|
('Addressing', ('vrf', 'mac_address', 'wwn')),
|
||||||
('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')),
|
('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')),
|
||||||
('Related Interfaces', ('parent', 'bridge', 'lag')),
|
('Related Interfaces', ('parent', 'bridge', 'lag')),
|
||||||
@ -1295,6 +1295,7 @@ class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm):
|
|||||||
'mode': StaticSelect(),
|
'mode': StaticSelect(),
|
||||||
'rf_role': StaticSelect(),
|
'rf_role': StaticSelect(),
|
||||||
'rf_channel': StaticSelect(),
|
'rf_channel': StaticSelect(),
|
||||||
|
'speed': SelectSpeedWidget(attrs={'readonly': None}),
|
||||||
}
|
}
|
||||||
labels = {
|
labels = {
|
||||||
'mode': '802.1Q Mode',
|
'mode': '802.1Q Mode',
|
||||||
|
23
netbox/dcim/migrations/0150_interface_speed_duplex.py
Normal file
23
netbox/dcim/migrations/0150_interface_speed_duplex.py
Normal file
@ -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),
|
||||||
|
),
|
||||||
|
]
|
@ -551,6 +551,18 @@ class Interface(ModularComponentModel, BaseInterface, LinkTermination, PathEndpo
|
|||||||
verbose_name='Management only',
|
verbose_name='Management only',
|
||||||
help_text='This interface is used only for out-of-band management'
|
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(
|
wwn = WWNField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
@ -46,6 +46,14 @@
|
|||||||
<th scope="row">Type</th>
|
<th scope="row">Type</th>
|
||||||
<td>{{ object.get_type_display }}</td>
|
<td>{{ object.get_type_display }}</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<th scope="row">Enabled</th>
|
<th scope="row">Enabled</th>
|
||||||
<td>{% checkmark object.enabled %}</td>
|
<td>{% checkmark object.enabled %}</td>
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% render_field form.name %}
|
{% render_field form.name %}
|
||||||
{% render_field form.type %}
|
{% render_field form.type %}
|
||||||
|
{% render_field form.speed %}
|
||||||
|
{% render_field form.duplex %}
|
||||||
{% render_field form.label %}
|
{% render_field form.label %}
|
||||||
{% render_field form.description %}
|
{% render_field form.description %}
|
||||||
{% render_field form.tags %}
|
{% render_field form.tags %}
|
||||||
|
Reference in New Issue
Block a user