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

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>
Abhimanyu Saharan 2 лет назад
Родитель
Сommit
0f9fe96192

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

@@ -514,12 +514,18 @@ class InterfaceTemplateSerializer(ValidatedModelSerializer):
         allow_blank=True,
         allow_null=True
     )
+    rf_role = ChoiceField(
+        choices=WirelessRoleChoices,
+        required=False,
+        allow_blank=True,
+        allow_null=True
+    )
 
     class Meta:
         model = InterfaceTemplate
         fields = [
             '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',
         ]
 
 

+ 3 - 0
netbox/dcim/filtersets.py

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

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

@@ -76,14 +76,14 @@ class PowerOutletBulkCreateForm(
 
 class InterfaceBulkCreateForm(
     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
 ):
     model = Interface
     field_order = (
         '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',
     )
 
 

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

@@ -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.widgets import BulkEditNullBooleanSelect, NumberWithOptions
 from wireless.models import WirelessLAN, WirelessLANGroup
+from wireless.choices import WirelessRoleChoices
 
 __all__ = (
     'CableBulkEditForm',
@@ -922,8 +923,14 @@ class InterfaceTemplateBulkEditForm(BulkEditForm):
         initial='',
         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):

+ 3 - 2
netbox/dcim/forms/model_forms.py

@@ -826,13 +826,14 @@ class InterfaceTemplateForm(ModularComponentTemplateForm):
 
     fieldsets = (
         (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:
         model = InterfaceTemplate
         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',
         ]
 
 

+ 8 - 1
netbox/dcim/forms/object_import.py

@@ -4,6 +4,7 @@ from django.utils.translation import gettext as _
 from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices
 from dcim.models import *
 from utilities.forms import BootstrapMixin
+from wireless.choices import WirelessRoleChoices
 
 __all__ = (
     'ConsolePortTemplateImportForm',
@@ -96,11 +97,17 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm):
         required=False,
         label=_('PoE type')
     )
+    rf_role = forms.ChoiceField(
+        choices=WirelessRoleChoices,
+        required=False,
+        label=_('Wireless role')
+    )
 
     class Meta:
         model = InterfaceTemplate
         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'
         ]
 
 

+ 3 - 0
netbox/dcim/graphql/types.py

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

+ 18 - 0
netbox/dcim/migrations/0179_interfacetemplate_rf_role.py

@@ -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),
+        ),
+    ]

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

@@ -13,6 +13,7 @@ from utilities.fields import ColorField, NaturalOrderingField
 from utilities.mptt import TreeManager
 from utilities.ordering import naturalize_interface
 from utilities.tracking import TrackingModelMixin
+from wireless.choices import WirelessRoleChoices
 from .device_components import (
     ConsolePort, ConsoleServerPort, DeviceBay, FrontPort, Interface, InventoryItem, ModuleBay, PowerOutlet, PowerPort,
     RearPort,
@@ -388,6 +389,12 @@ class InterfaceTemplate(ModularComponentTemplateModel):
         blank=True,
         verbose_name='PoE type'
     )
+    rf_role = models.CharField(
+        max_length=30,
+        choices=WirelessRoleChoices,
+        blank=True,
+        verbose_name='Wireless role'
+    )
 
     component_model = Interface
 
@@ -406,6 +413,11 @@ class InterfaceTemplate(ModularComponentTemplateModel):
                     '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):
         return self.component_model(
             name=self.resolve_name(kwargs.get('module')),
@@ -415,6 +427,7 @@ class InterfaceTemplate(ModularComponentTemplateModel):
             mgmt_only=self.mgmt_only,
             poe_mode=self.poe_mode,
             poe_type=self.poe_type,
+            rf_role=self.rf_role,
             **kwargs
         )
     instantiate.do_not_call_in_templates = True
@@ -430,6 +443,7 @@ class InterfaceTemplate(ModularComponentTemplateModel):
             'bridge': self.bridge.name if self.bridge else None,
             'poe_mode': self.poe_mode,
             'poe_type': self.poe_type,
+            'rf_role': self.rf_role,
         }
 
 

+ 4 - 1
netbox/dcim/tables/devicetypes.py

@@ -219,7 +219,10 @@ class InterfaceTemplateTable(ComponentTemplateTable):
 
     class Meta(ComponentTemplateTable.Meta):
         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"