Adds rf_role to interface template (#13199)

* adds rf_role to interface template #13170

* fixed migration file conflict

* Misc cleanup

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
Abhimanyu Saharan 2023-07-26 18:43:24 +05:30 committed by GitHub
parent 1bcfcad9db
commit 0f9fe96192
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 70 additions and 8 deletions

View File

@ -514,12 +514,18 @@ class InterfaceTemplateSerializer(ValidatedModelSerializer):
allow_blank=True, allow_blank=True,
allow_null=True allow_null=True
) )
rf_role = ChoiceField(
choices=WirelessRoleChoices,
required=False,
allow_blank=True,
allow_null=True
)
class Meta: class Meta:
model = InterfaceTemplate model = InterfaceTemplate
fields = [ fields = [
'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only',
'description', 'bridge', 'poe_mode', 'poe_type', 'created', 'last_updated', 'description', 'bridge', 'poe_mode', 'poe_type', 'rf_role', 'created', 'last_updated',
] ]

View File

@ -696,6 +696,9 @@ class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeCo
poe_type = django_filters.MultipleChoiceFilter( poe_type = django_filters.MultipleChoiceFilter(
choices=InterfacePoETypeChoices choices=InterfacePoETypeChoices
) )
rf_role = django_filters.MultipleChoiceFilter(
choices=WirelessRoleChoices
)
class Meta: class Meta:
model = InterfaceTemplate model = InterfaceTemplate

View File

@ -76,14 +76,14 @@ class PowerOutletBulkCreateForm(
class InterfaceBulkCreateForm( class InterfaceBulkCreateForm(
form_from_model(Interface, [ form_from_model(Interface, [
'type', 'enabled', 'speed', 'duplex', 'mtu', 'mgmt_only', 'mark_connected', 'poe_mode', 'poe_type', 'type', 'enabled', 'speed', 'duplex', 'mtu', 'mgmt_only', 'mark_connected', 'poe_mode', 'poe_type', 'rf_role'
]), ]),
DeviceBulkAddComponentForm DeviceBulkAddComponentForm
): ):
model = Interface model = Interface
field_order = ( field_order = (
'name', 'label', 'type', 'enabled', 'speed', 'duplex', 'mtu', 'mgmt_only', 'poe_mode', 'name', 'label', 'type', 'enabled', 'speed', 'duplex', 'mtu', 'mgmt_only', 'poe_mode',
'poe_type', 'mark_connected', 'description', 'tags', 'poe_type', 'mark_connected', 'rf_role', 'description', 'tags',
) )

View File

@ -15,6 +15,7 @@ from utilities.forms import BulkEditForm, add_blank_choice, form_from_model
from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField
from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions
from wireless.models import WirelessLAN, WirelessLANGroup from wireless.models import WirelessLAN, WirelessLANGroup
from wireless.choices import WirelessRoleChoices
__all__ = ( __all__ = (
'CableBulkEditForm', 'CableBulkEditForm',
@ -922,8 +923,14 @@ class InterfaceTemplateBulkEditForm(BulkEditForm):
initial='', initial='',
label=_('PoE type') label=_('PoE type')
) )
rf_role = forms.ChoiceField(
choices=add_blank_choice(WirelessRoleChoices),
required=False,
initial='',
label=_('Wireless role')
)
nullable_fields = ('label', 'description', 'poe_mode', 'poe_type') nullable_fields = ('label', 'description', 'poe_mode', 'poe_type', 'rf_role')
class FrontPortTemplateBulkEditForm(BulkEditForm): class FrontPortTemplateBulkEditForm(BulkEditForm):

View File

@ -826,13 +826,14 @@ class InterfaceTemplateForm(ModularComponentTemplateForm):
fieldsets = ( fieldsets = (
(None, ('device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'bridge')), (None, ('device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'bridge')),
('PoE', ('poe_mode', 'poe_type')) ('PoE', ('poe_mode', 'poe_type')),
('Wireless', ('rf_role',))
) )
class Meta: class Meta:
model = InterfaceTemplate model = InterfaceTemplate
fields = [ fields = [
'device_type', 'module_type', 'name', 'label', 'type', 'mgmt_only', 'enabled', 'description', 'poe_mode', 'poe_type', 'bridge', 'device_type', 'module_type', 'name', 'label', 'type', 'mgmt_only', 'enabled', 'description', 'poe_mode', 'poe_type', 'bridge', 'rf_role',
] ]

View File

@ -4,6 +4,7 @@ from django.utils.translation import gettext as _
from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices
from dcim.models import * from dcim.models import *
from utilities.forms import BootstrapMixin from utilities.forms import BootstrapMixin
from wireless.choices import WirelessRoleChoices
__all__ = ( __all__ = (
'ConsolePortTemplateImportForm', 'ConsolePortTemplateImportForm',
@ -96,11 +97,17 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm):
required=False, required=False,
label=_('PoE type') label=_('PoE type')
) )
rf_role = forms.ChoiceField(
choices=WirelessRoleChoices,
required=False,
label=_('Wireless role')
)
class Meta: class Meta:
model = InterfaceTemplate model = InterfaceTemplate
fields = [ fields = [
'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'poe_mode',
'poe_type', 'rf_role'
] ]

View File

@ -277,6 +277,9 @@ class InterfaceTemplateType(ComponentTemplateObjectType):
def resolve_poe_type(self, info): def resolve_poe_type(self, info):
return self.poe_type or None return self.poe_type or None
def resolve_rf_role(self, info):
return self.rf_role or None
class InventoryItemType(ComponentObjectType): class InventoryItemType(ComponentObjectType):
component = graphene.Field('dcim.graphql.gfk_mixins.InventoryItemComponentType') component = graphene.Field('dcim.graphql.gfk_mixins.InventoryItemComponentType')

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.2 on 2023-07-18 07:55
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0178_virtual_chassis_member_counter'),
]
operations = [
migrations.AddField(
model_name='interfacetemplate',
name='rf_role',
field=models.CharField(blank=True, max_length=30),
),
]

View File

@ -13,6 +13,7 @@ from utilities.fields import ColorField, NaturalOrderingField
from utilities.mptt import TreeManager from utilities.mptt import TreeManager
from utilities.ordering import naturalize_interface from utilities.ordering import naturalize_interface
from utilities.tracking import TrackingModelMixin from utilities.tracking import TrackingModelMixin
from wireless.choices import WirelessRoleChoices
from .device_components import ( from .device_components import (
ConsolePort, ConsoleServerPort, DeviceBay, FrontPort, Interface, InventoryItem, ModuleBay, PowerOutlet, PowerPort, ConsolePort, ConsoleServerPort, DeviceBay, FrontPort, Interface, InventoryItem, ModuleBay, PowerOutlet, PowerPort,
RearPort, RearPort,
@ -388,6 +389,12 @@ class InterfaceTemplate(ModularComponentTemplateModel):
blank=True, blank=True,
verbose_name='PoE type' verbose_name='PoE type'
) )
rf_role = models.CharField(
max_length=30,
choices=WirelessRoleChoices,
blank=True,
verbose_name='Wireless role'
)
component_model = Interface component_model = Interface
@ -406,6 +413,11 @@ class InterfaceTemplate(ModularComponentTemplateModel):
'bridge': f"Bridge interface ({self.bridge}) must belong to the same module type" 'bridge': f"Bridge interface ({self.bridge}) must belong to the same module type"
}) })
if self.rf_role and self.type not in WIRELESS_IFACE_TYPES:
raise ValidationError({
'rf_role': "Wireless role may be set only on wireless interfaces."
})
def instantiate(self, **kwargs): def instantiate(self, **kwargs):
return self.component_model( return self.component_model(
name=self.resolve_name(kwargs.get('module')), name=self.resolve_name(kwargs.get('module')),
@ -415,6 +427,7 @@ class InterfaceTemplate(ModularComponentTemplateModel):
mgmt_only=self.mgmt_only, mgmt_only=self.mgmt_only,
poe_mode=self.poe_mode, poe_mode=self.poe_mode,
poe_type=self.poe_type, poe_type=self.poe_type,
rf_role=self.rf_role,
**kwargs **kwargs
) )
instantiate.do_not_call_in_templates = True instantiate.do_not_call_in_templates = True
@ -430,6 +443,7 @@ class InterfaceTemplate(ModularComponentTemplateModel):
'bridge': self.bridge.name if self.bridge else None, 'bridge': self.bridge.name if self.bridge else None,
'poe_mode': self.poe_mode, 'poe_mode': self.poe_mode,
'poe_type': self.poe_type, 'poe_type': self.poe_type,
'rf_role': self.rf_role,
} }

View File

@ -219,7 +219,10 @@ class InterfaceTemplateTable(ComponentTemplateTable):
class Meta(ComponentTemplateTable.Meta): class Meta(ComponentTemplateTable.Meta):
model = models.InterfaceTemplate model = models.InterfaceTemplate
fields = ('pk', 'name', 'label', 'enabled', 'mgmt_only', 'type', 'description', 'bridge', 'poe_mode', 'poe_type', 'actions') fields = (
'pk', 'name', 'label', 'enabled', 'mgmt_only', 'type', 'description', 'bridge', 'poe_mode', 'poe_type',
'rf_role', 'actions',
)
empty_text = "None" empty_text = "None"