Jeremy Stretch 6 лет назад
Родитель
Сommit
5f5081f719

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

@@ -257,7 +257,7 @@ class PowerOutletTemplateSerializer(ValidatedModelSerializer):
 
 
 class InterfaceTemplateSerializer(ValidatedModelSerializer):
 class InterfaceTemplateSerializer(ValidatedModelSerializer):
     device_type = NestedDeviceTypeSerializer()
     device_type = NestedDeviceTypeSerializer()
-    type = ChoiceField(choices=IFACE_TYPE_CHOICES, required=False)
+    type = ChoiceField(choices=InterfaceTypeChoices, required=False)
 
 
     class Meta:
     class Meta:
         model = InterfaceTemplate
         model = InterfaceTemplate
@@ -467,7 +467,7 @@ class PowerPortSerializer(TaggitSerializer, ConnectedEndpointSerializer):
 
 
 class InterfaceSerializer(TaggitSerializer, ConnectedEndpointSerializer):
 class InterfaceSerializer(TaggitSerializer, ConnectedEndpointSerializer):
     device = NestedDeviceSerializer()
     device = NestedDeviceSerializer()
-    type = ChoiceField(choices=IFACE_TYPE_CHOICES, required=False)
+    type = ChoiceField(choices=InterfaceTypeChoices, required=False)
     lag = NestedInterfaceSerializer(required=False, allow_null=True)
     lag = NestedInterfaceSerializer(required=False, allow_null=True)
     mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True)
     mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True)
     untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
     untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)

+ 5 - 5
netbox/dcim/choices.py

@@ -107,7 +107,7 @@ class DeviceFaceChoices(ChoiceSet):
 
 
 
 
 #
 #
-# Console port type values
+# ConsolePorts
 #
 #
 
 
 class ConsolePortTypeChoices(ChoiceSet):
 class ConsolePortTypeChoices(ChoiceSet):
@@ -148,7 +148,7 @@ class ConsolePortTypeChoices(ChoiceSet):
 
 
 
 
 #
 #
-# Power port types
+# PowerPorts
 #
 #
 
 
 class PowerPortTypeChoices(ChoiceSet):
 class PowerPortTypeChoices(ChoiceSet):
@@ -235,7 +235,7 @@ class PowerPortTypeChoices(ChoiceSet):
 
 
 
 
 #
 #
-# Power outlet types
+# PowerOutlets
 #
 #
 
 
 class PowerOutletTypeChoices(ChoiceSet):
 class PowerOutletTypeChoices(ChoiceSet):
@@ -322,7 +322,7 @@ class PowerOutletTypeChoices(ChoiceSet):
 
 
 
 
 #
 #
-# Interface type values
+# Interfaces
 #
 #
 
 
 class InterfaceTypeChoices(ChoiceSet):
 class InterfaceTypeChoices(ChoiceSet):
@@ -624,7 +624,7 @@ class InterfaceTypeChoices(ChoiceSet):
 
 
 
 
 #
 #
-# Port type values
+# FrontPorts/RearPorts
 #
 #
 
 
 class PortTypeChoices(ChoiceSet):
 class PortTypeChoices(ChoiceSet):

+ 11 - 220
netbox/dcim/constants.py

@@ -1,230 +1,21 @@
-#
-# Numeric interface types
-#
+from .choices import InterfaceTypeChoices
 
 
-# Virtual
-IFACE_TYPE_VIRTUAL = 0
-IFACE_TYPE_LAG = 200
-# Ethernet
-IFACE_TYPE_100ME_FIXED = 800
-IFACE_TYPE_1GE_FIXED = 1000
-IFACE_TYPE_1GE_GBIC = 1050
-IFACE_TYPE_1GE_SFP = 1100
-IFACE_TYPE_2GE_FIXED = 1120
-IFACE_TYPE_5GE_FIXED = 1130
-IFACE_TYPE_10GE_FIXED = 1150
-IFACE_TYPE_10GE_CX4 = 1170
-IFACE_TYPE_10GE_SFP_PLUS = 1200
-IFACE_TYPE_10GE_XFP = 1300
-IFACE_TYPE_10GE_XENPAK = 1310
-IFACE_TYPE_10GE_X2 = 1320
-IFACE_TYPE_25GE_SFP28 = 1350
-IFACE_TYPE_40GE_QSFP_PLUS = 1400
-IFACE_TYPE_50GE_QSFP28 = 1420
-IFACE_TYPE_100GE_CFP = 1500
-IFACE_TYPE_100GE_CFP2 = 1510
-IFACE_TYPE_100GE_CFP4 = 1520
-IFACE_TYPE_100GE_CPAK = 1550
-IFACE_TYPE_100GE_QSFP28 = 1600
-IFACE_TYPE_200GE_CFP2 = 1650
-IFACE_TYPE_200GE_QSFP56 = 1700
-IFACE_TYPE_400GE_QSFP_DD = 1750
-IFACE_TYPE_400GE_OSFP = 1800
-# Wireless
-IFACE_TYPE_80211A = 2600
-IFACE_TYPE_80211G = 2610
-IFACE_TYPE_80211N = 2620
-IFACE_TYPE_80211AC = 2630
-IFACE_TYPE_80211AD = 2640
-# Cellular
-IFACE_TYPE_GSM = 2810
-IFACE_TYPE_CDMA = 2820
-IFACE_TYPE_LTE = 2830
-# SONET
-IFACE_TYPE_SONET_OC3 = 6100
-IFACE_TYPE_SONET_OC12 = 6200
-IFACE_TYPE_SONET_OC48 = 6300
-IFACE_TYPE_SONET_OC192 = 6400
-IFACE_TYPE_SONET_OC768 = 6500
-IFACE_TYPE_SONET_OC1920 = 6600
-IFACE_TYPE_SONET_OC3840 = 6700
-# Fibrechannel
-IFACE_TYPE_1GFC_SFP = 3010
-IFACE_TYPE_2GFC_SFP = 3020
-IFACE_TYPE_4GFC_SFP = 3040
-IFACE_TYPE_8GFC_SFP_PLUS = 3080
-IFACE_TYPE_16GFC_SFP_PLUS = 3160
-IFACE_TYPE_32GFC_SFP28 = 3320
-IFACE_TYPE_128GFC_QSFP28 = 3400
-# InfiniBand
-IFACE_TYPE_INFINIBAND_SDR = 7010
-IFACE_TYPE_INFINIBAND_DDR = 7020
-IFACE_TYPE_INFINIBAND_QDR = 7030
-IFACE_TYPE_INFINIBAND_FDR10 = 7040
-IFACE_TYPE_INFINIBAND_FDR = 7050
-IFACE_TYPE_INFINIBAND_EDR = 7060
-IFACE_TYPE_INFINIBAND_HDR = 7070
-IFACE_TYPE_INFINIBAND_NDR = 7080
-IFACE_TYPE_INFINIBAND_XDR = 7090
-# Serial
-IFACE_TYPE_T1 = 4000
-IFACE_TYPE_E1 = 4010
-IFACE_TYPE_T3 = 4040
-IFACE_TYPE_E3 = 4050
-# Stacking
-IFACE_TYPE_STACKWISE = 5000
-IFACE_TYPE_STACKWISE_PLUS = 5050
-IFACE_TYPE_FLEXSTACK = 5100
-IFACE_TYPE_FLEXSTACK_PLUS = 5150
-IFACE_TYPE_JUNIPER_VCP = 5200
-IFACE_TYPE_SUMMITSTACK = 5300
-IFACE_TYPE_SUMMITSTACK128 = 5310
-IFACE_TYPE_SUMMITSTACK256 = 5320
-IFACE_TYPE_SUMMITSTACK512 = 5330
 
 
-# Other
-IFACE_TYPE_OTHER = 32767
-
-IFACE_TYPE_CHOICES = [
-    [
-        'Virtual interfaces',
-        [
-            [IFACE_TYPE_VIRTUAL, 'Virtual'],
-            [IFACE_TYPE_LAG, 'Link Aggregation Group (LAG)'],
-        ],
-    ],
-    [
-        'Ethernet (fixed)',
-        [
-            [IFACE_TYPE_100ME_FIXED, '100BASE-TX (10/100ME)'],
-            [IFACE_TYPE_1GE_FIXED, '1000BASE-T (1GE)'],
-            [IFACE_TYPE_2GE_FIXED, '2.5GBASE-T (2.5GE)'],
-            [IFACE_TYPE_5GE_FIXED, '5GBASE-T (5GE)'],
-            [IFACE_TYPE_10GE_FIXED, '10GBASE-T (10GE)'],
-            [IFACE_TYPE_10GE_CX4, '10GBASE-CX4 (10GE)'],
-        ]
-    ],
-    [
-        'Ethernet (modular)',
-        [
-            [IFACE_TYPE_1GE_GBIC, 'GBIC (1GE)'],
-            [IFACE_TYPE_1GE_SFP, 'SFP (1GE)'],
-            [IFACE_TYPE_10GE_SFP_PLUS, 'SFP+ (10GE)'],
-            [IFACE_TYPE_10GE_XFP, 'XFP (10GE)'],
-            [IFACE_TYPE_10GE_XENPAK, 'XENPAK (10GE)'],
-            [IFACE_TYPE_10GE_X2, 'X2 (10GE)'],
-            [IFACE_TYPE_25GE_SFP28, 'SFP28 (25GE)'],
-            [IFACE_TYPE_40GE_QSFP_PLUS, 'QSFP+ (40GE)'],
-            [IFACE_TYPE_50GE_QSFP28, 'QSFP28 (50GE)'],
-            [IFACE_TYPE_100GE_CFP, 'CFP (100GE)'],
-            [IFACE_TYPE_100GE_CFP2, 'CFP2 (100GE)'],
-            [IFACE_TYPE_200GE_CFP2, 'CFP2 (200GE)'],
-            [IFACE_TYPE_100GE_CFP4, 'CFP4 (100GE)'],
-            [IFACE_TYPE_100GE_CPAK, 'Cisco CPAK (100GE)'],
-            [IFACE_TYPE_100GE_QSFP28, 'QSFP28 (100GE)'],
-            [IFACE_TYPE_200GE_QSFP56, 'QSFP56 (200GE)'],
-            [IFACE_TYPE_400GE_QSFP_DD, 'QSFP-DD (400GE)'],
-            [IFACE_TYPE_400GE_OSFP, 'OSFP (400GE)'],
-        ]
-    ],
-    [
-        'Wireless',
-        [
-            [IFACE_TYPE_80211A, 'IEEE 802.11a'],
-            [IFACE_TYPE_80211G, 'IEEE 802.11b/g'],
-            [IFACE_TYPE_80211N, 'IEEE 802.11n'],
-            [IFACE_TYPE_80211AC, 'IEEE 802.11ac'],
-            [IFACE_TYPE_80211AD, 'IEEE 802.11ad'],
-        ]
-    ],
-    [
-        'Cellular',
-        [
-            [IFACE_TYPE_GSM, 'GSM'],
-            [IFACE_TYPE_CDMA, 'CDMA'],
-            [IFACE_TYPE_LTE, 'LTE'],
-        ]
-    ],
-    [
-        'SONET',
-        [
-            [IFACE_TYPE_SONET_OC3, 'OC-3/STM-1'],
-            [IFACE_TYPE_SONET_OC12, 'OC-12/STM-4'],
-            [IFACE_TYPE_SONET_OC48, 'OC-48/STM-16'],
-            [IFACE_TYPE_SONET_OC192, 'OC-192/STM-64'],
-            [IFACE_TYPE_SONET_OC768, 'OC-768/STM-256'],
-            [IFACE_TYPE_SONET_OC1920, 'OC-1920/STM-640'],
-            [IFACE_TYPE_SONET_OC3840, 'OC-3840/STM-1234'],
-        ]
-    ],
-    [
-        'FibreChannel',
-        [
-            [IFACE_TYPE_1GFC_SFP, 'SFP (1GFC)'],
-            [IFACE_TYPE_2GFC_SFP, 'SFP (2GFC)'],
-            [IFACE_TYPE_4GFC_SFP, 'SFP (4GFC)'],
-            [IFACE_TYPE_8GFC_SFP_PLUS, 'SFP+ (8GFC)'],
-            [IFACE_TYPE_16GFC_SFP_PLUS, 'SFP+ (16GFC)'],
-            [IFACE_TYPE_32GFC_SFP28, 'SFP28 (32GFC)'],
-            [IFACE_TYPE_128GFC_QSFP28, 'QSFP28 (128GFC)'],
-        ]
-    ],
-    [
-        'InfiniBand',
-        [
-            [IFACE_TYPE_INFINIBAND_SDR, 'SDR (2 Gbps)'],
-            [IFACE_TYPE_INFINIBAND_DDR, 'DDR (4 Gbps)'],
-            [IFACE_TYPE_INFINIBAND_QDR, 'QDR (8 Gbps)'],
-            [IFACE_TYPE_INFINIBAND_FDR10, 'FDR10 (10 Gbps)'],
-            [IFACE_TYPE_INFINIBAND_FDR, 'FDR (13.5 Gbps)'],
-            [IFACE_TYPE_INFINIBAND_EDR, 'EDR (25 Gbps)'],
-            [IFACE_TYPE_INFINIBAND_HDR, 'HDR (50 Gbps)'],
-            [IFACE_TYPE_INFINIBAND_NDR, 'NDR (100 Gbps)'],
-            [IFACE_TYPE_INFINIBAND_XDR, 'XDR (250 Gbps)'],
-        ]
-    ],
-    [
-        'Serial',
-        [
-            [IFACE_TYPE_T1, 'T1 (1.544 Mbps)'],
-            [IFACE_TYPE_E1, 'E1 (2.048 Mbps)'],
-            [IFACE_TYPE_T3, 'T3 (45 Mbps)'],
-            [IFACE_TYPE_E3, 'E3 (34 Mbps)'],
-        ]
-    ],
-    [
-        'Stacking',
-        [
-            [IFACE_TYPE_STACKWISE, 'Cisco StackWise'],
-            [IFACE_TYPE_STACKWISE_PLUS, 'Cisco StackWise Plus'],
-            [IFACE_TYPE_FLEXSTACK, 'Cisco FlexStack'],
-            [IFACE_TYPE_FLEXSTACK_PLUS, 'Cisco FlexStack Plus'],
-            [IFACE_TYPE_JUNIPER_VCP, 'Juniper VCP'],
-            [IFACE_TYPE_SUMMITSTACK, 'Extreme SummitStack'],
-            [IFACE_TYPE_SUMMITSTACK128, 'Extreme SummitStack-128'],
-            [IFACE_TYPE_SUMMITSTACK256, 'Extreme SummitStack-256'],
-            [IFACE_TYPE_SUMMITSTACK512, 'Extreme SummitStack-512'],
-        ]
-    ],
-    [
-        'Other',
-        [
-            [IFACE_TYPE_OTHER, 'Other'],
-        ]
-    ],
-]
+#
+# Interface type groups
+#
 
 
 VIRTUAL_IFACE_TYPES = [
 VIRTUAL_IFACE_TYPES = [
-    IFACE_TYPE_VIRTUAL,
-    IFACE_TYPE_LAG,
+    InterfaceTypeChoices.TYPE_VIRTUAL,
+    InterfaceTypeChoices.TYPE_LAG,
 ]
 ]
 
 
 WIRELESS_IFACE_TYPES = [
 WIRELESS_IFACE_TYPES = [
-    IFACE_TYPE_80211A,
-    IFACE_TYPE_80211G,
-    IFACE_TYPE_80211N,
-    IFACE_TYPE_80211AC,
-    IFACE_TYPE_80211AD,
+    InterfaceTypeChoices.TYPE_80211A,
+    InterfaceTypeChoices.TYPE_80211G,
+    InterfaceTypeChoices.TYPE_80211N,
+    InterfaceTypeChoices.TYPE_80211AC,
+    InterfaceTypeChoices.TYPE_80211AD,
 ]
 ]
 
 
 NONCONNECTABLE_IFACE_TYPES = VIRTUAL_IFACE_TYPES + WIRELESS_IFACE_TYPES
 NONCONNECTABLE_IFACE_TYPES = VIRTUAL_IFACE_TYPES + WIRELESS_IFACE_TYPES

+ 1 - 1
netbox/dcim/filters.py

@@ -748,7 +748,7 @@ class InterfaceFilter(django_filters.FilterSet):
         label='Assigned VID'
         label='Assigned VID'
     )
     )
     type = django_filters.MultipleChoiceFilter(
     type = django_filters.MultipleChoiceFilter(
-        choices=IFACE_TYPE_CHOICES,
+        choices=InterfaceTypeChoices,
         null_value=None
         null_value=None
     )
     )
 
 

+ 12 - 14
netbox/dcim/forms.py

@@ -1076,7 +1076,7 @@ class InterfaceTemplateCreateForm(ComponentForm):
         label='Name'
         label='Name'
     )
     )
     type = forms.ChoiceField(
     type = forms.ChoiceField(
-        choices=IFACE_TYPE_CHOICES,
+        choices=InterfaceTypeChoices,
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
     mgmt_only = forms.BooleanField(
     mgmt_only = forms.BooleanField(
@@ -1091,7 +1091,7 @@ class InterfaceTemplateBulkEditForm(BootstrapMixin, BulkEditForm):
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
     )
     )
     type = forms.ChoiceField(
     type = forms.ChoiceField(
-        choices=add_blank_choice(IFACE_TYPE_CHOICES),
+        choices=add_blank_choice(InterfaceTypeChoices),
         required=False,
         required=False,
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
@@ -1311,11 +1311,6 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm):
             'device_type', 'name', 'type', 'mgmt_only',
             'device_type', 'name', 'type', 'mgmt_only',
         ]
         ]
 
 
-    def clean_type(self):
-        # Convert slug value to field integer value
-        slug = self.cleaned_data['type']
-        return InterfaceTypeChoices.slug_to_id(slug)
-
 
 
 class FrontPortTemplateImportForm(ComponentTemplateImportForm):
 class FrontPortTemplateImportForm(ComponentTemplateImportForm):
     type = forms.ChoiceField(
     type = forms.ChoiceField(
@@ -2031,7 +2026,7 @@ class DeviceBulkAddComponentForm(BootstrapMixin, forms.Form):
 
 
 class DeviceBulkAddInterfaceForm(DeviceBulkAddComponentForm):
 class DeviceBulkAddInterfaceForm(DeviceBulkAddComponentForm):
     type = forms.ChoiceField(
     type = forms.ChoiceField(
-        choices=IFACE_TYPE_CHOICES,
+        choices=InterfaceTypeChoices,
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
     enabled = forms.BooleanField(
     enabled = forms.BooleanField(
@@ -2377,12 +2372,14 @@ class InterfaceForm(InterfaceCommonForm, BootstrapMixin, forms.ModelForm):
         if self.is_bound:
         if self.is_bound:
             device = Device.objects.get(pk=self.data['device'])
             device = Device.objects.get(pk=self.data['device'])
             self.fields['lag'].queryset = Interface.objects.filter(
             self.fields['lag'].queryset = Interface.objects.filter(
-                device__in=[device, device.get_vc_master()], type=IFACE_TYPE_LAG
+                device__in=[device, device.get_vc_master()],
+                type=InterfaceTypeChoices.TYPE_LAG
             )
             )
         else:
         else:
             device = self.instance.device
             device = self.instance.device
             self.fields['lag'].queryset = Interface.objects.filter(
             self.fields['lag'].queryset = Interface.objects.filter(
-                device__in=[self.instance.device, self.instance.device.get_vc_master()], type=IFACE_TYPE_LAG
+                device__in=[self.instance.device, self.instance.device.get_vc_master()],
+                type=InterfaceTypeChoices.TYPE_LAG
             )
             )
 
 
         # Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site
         # Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site
@@ -2421,7 +2418,7 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form):
         label='Name'
         label='Name'
     )
     )
     type = forms.ChoiceField(
     type = forms.ChoiceField(
-        choices=IFACE_TYPE_CHOICES,
+        choices=InterfaceTypeChoices,
         widget=StaticSelect2(),
         widget=StaticSelect2(),
     )
     )
     enabled = forms.BooleanField(
     enabled = forms.BooleanField(
@@ -2490,7 +2487,8 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form):
         # Limit LAG choices to interfaces belonging to this device (or its VC master)
         # Limit LAG choices to interfaces belonging to this device (or its VC master)
         if self.parent is not None:
         if self.parent is not None:
             self.fields['lag'].queryset = Interface.objects.filter(
             self.fields['lag'].queryset = Interface.objects.filter(
-                device__in=[self.parent, self.parent.get_vc_master()], type=IFACE_TYPE_LAG
+                device__in=[self.parent, self.parent.get_vc_master()],
+                type=InterfaceTypeChoices.TYPE_LAG
             )
             )
         else:
         else:
             self.fields['lag'].queryset = Interface.objects.none()
             self.fields['lag'].queryset = Interface.objects.none()
@@ -2532,7 +2530,7 @@ class InterfaceBulkEditForm(InterfaceCommonForm, BootstrapMixin, AddRemoveTagsFo
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
     )
     )
     type = forms.ChoiceField(
     type = forms.ChoiceField(
-        choices=add_blank_choice(IFACE_TYPE_CHOICES),
+        choices=add_blank_choice(InterfaceTypeChoices),
         required=False,
         required=False,
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
@@ -2602,7 +2600,7 @@ class InterfaceBulkEditForm(InterfaceCommonForm, BootstrapMixin, AddRemoveTagsFo
         if device is not None:
         if device is not None:
             self.fields['lag'].queryset = Interface.objects.filter(
             self.fields['lag'].queryset = Interface.objects.filter(
                 device__in=[device, device.get_vc_master()],
                 device__in=[device, device.get_vc_master()],
-                type=IFACE_TYPE_LAG
+                type=InterfaceTypeChoices.TYPE_LAG
             )
             )
         else:
         else:
             self.fields['lag'].choices = []
             self.fields['lag'].choices = []

+ 114 - 0
netbox/dcim/migrations/0082_interface_type_to_slug.py

@@ -0,0 +1,114 @@
+from django.db import migrations, models
+
+
+INTERFACE_TYPE_CHOICES = (
+    (0, 'virtual'),
+    (200, 'lag'),
+    (800, '100base-tx'),
+    (1000, '1000base-t'),
+    (1050, '1000base-x-gbic'),
+    (1100, '1000base-x-sfp'),
+    (1120, '2.5gbase-t'),
+    (1130, '5gbase-t'),
+    (1150, '10gbase-t'),
+    (1170, '10gbase-cx4'),
+    (1200, '10gbase-x-sfpp'),
+    (1300, '10gbase-x-xfp'),
+    (1310, '10gbase-x-xenpak'),
+    (1320, '10gbase-x-x2'),
+    (1350, '25gbase-x-sfp28'),
+    (1400, '40gbase-x-qsfpp'),
+    (1420, '50gbase-x-sfp28'),
+    (1500, '100gbase-x-cfp'),
+    (1510, '100gbase-x-cfp2'),
+    (1520, '100gbase-x-cfp4'),
+    (1550, '100gbase-x-cpak'),
+    (1600, '100gbase-x-qsfp28'),
+    (1650, '200gbase-x-cfp2'),
+    (1700, '200gbase-x-qsfp56'),
+    (1750, '400gbase-x-qsfpdd'),
+    (1800, '400gbase-x-osfp'),
+    (2600, 'ieee802.11a'),
+    (2610, 'ieee802.11g'),
+    (2620, 'ieee802.11n'),
+    (2630, 'ieee802.11ac'),
+    (2640, 'ieee802.11ad'),
+    (2810, 'gsm'),
+    (2820, 'cdma'),
+    (2830, 'lte'),
+    (6100, 'sonet-oc3'),
+    (6200, 'sonet-oc12'),
+    (6300, 'sonet-oc48'),
+    (6400, 'sonet-oc192'),
+    (6500, 'sonet-oc768'),
+    (6600, 'sonet-oc1920'),
+    (6700, 'sonet-oc3840'),
+    (3010, '1gfc-sfp'),
+    (3020, '2gfc-sfp'),
+    (3040, '4gfc-sfp'),
+    (3080, '8gfc-sfpp'),
+    (3160, '16gfc-sfpp'),
+    (3320, '32gfc-sfp28'),
+    (3400, '128gfc-sfp28'),
+    (7010, 'inifiband-sdr'),
+    (7020, 'inifiband-ddr'),
+    (7030, 'inifiband-qdr'),
+    (7040, 'inifiband-fdr10'),
+    (7050, 'inifiband-fdr'),
+    (7060, 'inifiband-edr'),
+    (7070, 'inifiband-hdr'),
+    (7080, 'inifiband-ndr'),
+    (7090, 'inifiband-xdr'),
+    (4000, 't1'),
+    (4010, 'e1'),
+    (4040, 't3'),
+    (4050, 'e3'),
+    (5000, 'cisco-stackwise'),
+    (5050, 'cisco-stackwise-plus'),
+    (5100, 'cisco-flexstack'),
+    (5150, 'cisco-flexstack-plus'),
+    (5200, 'juniper-vcp'),
+    (5300, 'extreme-summitstack'),
+    (5310, 'extreme-summitstack-128'),
+    (5320, 'extreme-summitstack-256'),
+    (5330, 'extreme-summitstack-512'),
+)
+
+
+def interfacetemplate_type_to_slug(apps, schema_editor):
+    InterfaceTemplate = apps.get_model('dcim', 'InterfaceTemplate')
+    for id, slug in INTERFACE_TYPE_CHOICES:
+        InterfaceTemplate.objects.filter(type=id).update(type=slug)
+
+
+def interface_type_to_slug(apps, schema_editor):
+    Interface = apps.get_model('dcim', 'Interface')
+    for id, slug in INTERFACE_TYPE_CHOICES:
+        Interface.objects.filter(type=id).update(type=slug)
+
+
+class Migration(migrations.Migration):
+    atomic = False
+
+    dependencies = [
+        ('dcim', '0081_devicetype_subdevicerole_to_slug'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='interfacetemplate',
+            name='type',
+            field=models.CharField(max_length=50),
+        ),
+        migrations.RunPython(
+            code=interfacetemplate_type_to_slug
+        ),
+        migrations.AlterField(
+            model_name='interface',
+            name='type',
+            field=models.CharField(max_length=50),
+        ),
+        migrations.RunPython(
+            code=interface_type_to_slug
+        ),
+    ]

+ 9 - 9
netbox/dcim/models.py

@@ -1206,9 +1206,9 @@ class InterfaceTemplate(ComponentTemplateModel):
     name = models.CharField(
     name = models.CharField(
         max_length=64
         max_length=64
     )
     )
-    type = models.PositiveSmallIntegerField(
-        choices=IFACE_TYPE_CHOICES,
-        default=IFACE_TYPE_10GE_SFP_PLUS
+    type = models.CharField(
+        max_length=50,
+        choices=InterfaceTypeChoices
     )
     )
     mgmt_only = models.BooleanField(
     mgmt_only = models.BooleanField(
         default=False,
         default=False,
@@ -2238,9 +2238,9 @@ class Interface(CableTermination, ComponentModel):
         blank=True,
         blank=True,
         verbose_name='Parent LAG'
         verbose_name='Parent LAG'
     )
     )
-    type = models.PositiveSmallIntegerField(
-        choices=IFACE_TYPE_CHOICES,
-        default=IFACE_TYPE_10GE_SFP_PLUS
+    type = models.CharField(
+        max_length=50,
+        choices=InterfaceTypeChoices
     )
     )
     enabled = models.BooleanField(
     enabled = models.BooleanField(
         default=True
         default=True
@@ -2323,7 +2323,7 @@ class Interface(CableTermination, ComponentModel):
             raise ValidationError("An interface must belong to either a device or a virtual machine.")
             raise ValidationError("An interface must belong to either a device or a virtual machine.")
 
 
         # VM interfaces must be virtual
         # VM interfaces must be virtual
-        if self.virtual_machine and self.type is not IFACE_TYPE_VIRTUAL:
+        if self.virtual_machine and self.type is not InterfaceTypeChoices.TYPE_VIRTUAL:
             raise ValidationError({
             raise ValidationError({
                 'type': "Virtual machines can only have virtual interfaces."
                 'type': "Virtual machines can only have virtual interfaces."
             })
             })
@@ -2352,7 +2352,7 @@ class Interface(CableTermination, ComponentModel):
             })
             })
 
 
         # Only a LAG can have LAG members
         # Only a LAG can have LAG members
-        if self.type != IFACE_TYPE_LAG and self.member_interfaces.exists():
+        if self.type != InterfaceTypeChoices.TYPE_LAG and self.member_interfaces.exists():
             raise ValidationError({
             raise ValidationError({
                 'type': "Cannot change interface type; it has LAG members ({}).".format(
                 'type': "Cannot change interface type; it has LAG members ({}).".format(
                     ", ".join([iface.name for iface in self.member_interfaces.all()])
                     ", ".join([iface.name for iface in self.member_interfaces.all()])
@@ -2435,7 +2435,7 @@ class Interface(CableTermination, ComponentModel):
 
 
     @property
     @property
     def is_lag(self):
     def is_lag(self):
-        return self.type == IFACE_TYPE_LAG
+        return self.type == InterfaceTypeChoices.TYPE_LAG
 
 
     @property
     @property
     def count_ipaddresses(self):
     def count_ipaddresses(self):

+ 11 - 11
netbox/dcim/tests/test_api.py

@@ -2554,7 +2554,7 @@ class InterfaceTest(APITestCase):
     def test_update_interface(self):
     def test_update_interface(self):
 
 
         lag_interface = Interface.objects.create(
         lag_interface = Interface.objects.create(
-            device=self.device, name='Test LAG Interface', type=IFACE_TYPE_LAG
+            device=self.device, name='Test LAG Interface', type=InterfaceTypeChoices.TYPE_LAG
         )
         )
 
 
         data = {
         data = {
@@ -2842,7 +2842,7 @@ class CableTest(APITestCase):
         )
         )
         for device in [self.device1, self.device2]:
         for device in [self.device1, self.device2]:
             for i in range(0, 10):
             for i in range(0, 10):
-                Interface(device=device, type=IFACE_TYPE_1GE_FIXED, name='eth{}'.format(i)).save()
+                Interface(device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED, name='eth{}'.format(i)).save()
 
 
         self.cable1 = Cable(
         self.cable1 = Cable(
             termination_a=self.device1.interfaces.get(name='eth0'),
             termination_a=self.device1.interfaces.get(name='eth0'),
@@ -3411,23 +3411,23 @@ class VirtualChassisTest(APITestCase):
             device_type=device_type, device_role=device_role, name='StackSwitch9', site=site
             device_type=device_type, device_role=device_role, name='StackSwitch9', site=site
         )
         )
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device1, name='1/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device1, name='1/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device2, name='2/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device2, name='2/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device3, name='3/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device3, name='3/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device4, name='1/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device4, name='1/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device5, name='2/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device5, name='2/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device6, name='3/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device6, name='3/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device7, name='1/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device7, name='1/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device8, name='2/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device8, name='2/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         for i in range(0, 13):
         for i in range(0, 13):
-            Interface.objects.create(device=self.device9, name='3/{}'.format(i), type=IFACE_TYPE_1GE_FIXED)
+            Interface.objects.create(device=self.device9, name='3/{}'.format(i), type=InterfaceTypeChoices.TYPE_1GE_FIXED)
 
 
         # Create two VirtualChassis with three members each
         # Create two VirtualChassis with three members each
         self.vc1 = VirtualChassis.objects.create(master=self.device1, domain='test-domain-1')
         self.vc1 = VirtualChassis.objects.create(master=self.device1, domain='test-domain-1')

+ 4 - 4
netbox/dcim/tests/test_models.py

@@ -193,7 +193,7 @@ class DeviceTestCase(TestCase):
         InterfaceTemplate(
         InterfaceTemplate(
             device_type=self.device_type,
             device_type=self.device_type,
             name='Interface 1',
             name='Interface 1',
-            type=IFACE_TYPE_1GE_FIXED,
+            type=InterfaceTypeChoices.TYPE_1GE_FIXED,
             mgmt_only=True
             mgmt_only=True
         ).save()
         ).save()
 
 
@@ -257,7 +257,7 @@ class DeviceTestCase(TestCase):
         Interface.objects.get(
         Interface.objects.get(
             device=d,
             device=d,
             name='Interface 1',
             name='Interface 1',
-            type=IFACE_TYPE_1GE_FIXED,
+            type=InterfaceTypeChoices.TYPE_1GE_FIXED,
             mgmt_only=True
             mgmt_only=True
         )
         )
 
 
@@ -379,7 +379,7 @@ class CableTestCase(TestCase):
         """
         """
         A cable cannot terminate to a virtual interface
         A cable cannot terminate to a virtual interface
         """
         """
-        virtual_interface = Interface(device=self.device1, name="V1", type=IFACE_TYPE_VIRTUAL)
+        virtual_interface = Interface(device=self.device1, name="V1", type=InterfaceTypeChoices.TYPE_VIRTUAL)
         cable = Cable(termination_a=self.interface2, termination_b=virtual_interface)
         cable = Cable(termination_a=self.interface2, termination_b=virtual_interface)
         with self.assertRaises(ValidationError):
         with self.assertRaises(ValidationError):
             cable.clean()
             cable.clean()
@@ -388,7 +388,7 @@ class CableTestCase(TestCase):
         """
         """
         A cable cannot terminate to a wireless interface
         A cable cannot terminate to a wireless interface
         """
         """
-        wireless_interface = Interface(device=self.device1, name="W1", type=IFACE_TYPE_80211A)
+        wireless_interface = Interface(device=self.device1, name="W1", type=InterfaceTypeChoices.TYPE_80211A)
         cable = Cable(termination_a=self.interface2, termination_b=wireless_interface)
         cable = Cable(termination_a=self.interface2, termination_b=wireless_interface)
         with self.assertRaises(ValidationError):
         with self.assertRaises(ValidationError):
             cable.clean()
             cable.clean()

+ 7 - 7
netbox/dcim/tests/test_views.py

@@ -348,7 +348,7 @@ device-bays:
         self.assertEqual(dt.interface_templates.count(), 3)
         self.assertEqual(dt.interface_templates.count(), 3)
         iface1 = InterfaceTemplate.objects.first()
         iface1 = InterfaceTemplate.objects.first()
         self.assertEqual(iface1.name, 'Interface 1')
         self.assertEqual(iface1.name, 'Interface 1')
-        self.assertEqual(iface1.type, IFACE_TYPE_1GE_FIXED)
+        self.assertEqual(iface1.type, InterfaceTypeChoices.TYPE_1GE_FIXED)
         self.assertTrue(iface1.mgmt_only)
         self.assertTrue(iface1.mgmt_only)
 
 
         self.assertEqual(dt.rearport_templates.count(), 3)
         self.assertEqual(dt.rearport_templates.count(), 3)
@@ -514,17 +514,17 @@ class CableTestCase(TestCase):
         device2 = Device(name='Device 2', site=site, device_type=devicetype, device_role=devicerole)
         device2 = Device(name='Device 2', site=site, device_type=devicetype, device_role=devicerole)
         device2.save()
         device2.save()
 
 
-        iface1 = Interface(device=device1, name='Interface 1', type=IFACE_TYPE_1GE_FIXED)
+        iface1 = Interface(device=device1, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         iface1.save()
         iface1.save()
-        iface2 = Interface(device=device1, name='Interface 2', type=IFACE_TYPE_1GE_FIXED)
+        iface2 = Interface(device=device1, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         iface2.save()
         iface2.save()
-        iface3 = Interface(device=device1, name='Interface 3', type=IFACE_TYPE_1GE_FIXED)
+        iface3 = Interface(device=device1, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         iface3.save()
         iface3.save()
-        iface4 = Interface(device=device2, name='Interface 1', type=IFACE_TYPE_1GE_FIXED)
+        iface4 = Interface(device=device2, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         iface4.save()
         iface4.save()
-        iface5 = Interface(device=device2, name='Interface 2', type=IFACE_TYPE_1GE_FIXED)
+        iface5 = Interface(device=device2, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         iface5.save()
         iface5.save()
-        iface6 = Interface(device=device2, name='Interface 3', type=IFACE_TYPE_1GE_FIXED)
+        iface6 = Interface(device=device2, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
         iface6.save()
         iface6.save()
 
 
         Cable(termination_a=iface1, termination_b=iface4, type=CABLE_TYPE_CAT6).save()
         Cable(termination_a=iface1, termination_b=iface4, type=CABLE_TYPE_CAT6).save()

+ 3 - 2
netbox/virtualization/api/serializers.py

@@ -3,7 +3,8 @@ from rest_framework import serializers
 from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
 from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
 
 
 from dcim.api.nested_serializers import NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer
 from dcim.api.nested_serializers import NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer
-from dcim.constants import IFACE_TYPE_CHOICES, IFACE_TYPE_VIRTUAL, IFACE_MODE_CHOICES
+from dcim.choices import InterfaceTypeChoices
+from dcim.constants import IFACE_MODE_CHOICES
 from dcim.models import Interface
 from dcim.models import Interface
 from extras.api.customfields import CustomFieldModelSerializer
 from extras.api.customfields import CustomFieldModelSerializer
 from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer
 from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer
@@ -98,7 +99,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
 
 
 class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer):
 class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer):
     virtual_machine = NestedVirtualMachineSerializer()
     virtual_machine = NestedVirtualMachineSerializer()
-    type = ChoiceField(choices=IFACE_TYPE_CHOICES, default=IFACE_TYPE_VIRTUAL, required=False)
+    type = ChoiceField(choices=InterfaceTypeChoices, default=InterfaceTypeChoices.TYPE_VIRTUAL, required=False)
     mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True)
     mode = ChoiceField(choices=IFACE_MODE_CHOICES, required=False, allow_null=True)
     untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
     untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
     tagged_vlans = SerializedPKRelatedField(
     tagged_vlans = SerializedPKRelatedField(

+ 5 - 4
netbox/virtualization/forms.py

@@ -2,7 +2,8 @@ from django import forms
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from taggit.forms import TagField
 from taggit.forms import TagField
 
 
-from dcim.constants import IFACE_TYPE_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL, IFACE_MODE_CHOICES
+from dcim.choices import InterfaceTypeChoices
+from dcim.constants import IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL, IFACE_MODE_CHOICES
 from dcim.forms import INTERFACE_MODE_HELP_TEXT
 from dcim.forms import INTERFACE_MODE_HELP_TEXT
 from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, Site
 from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, Site
 from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
 from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
@@ -19,7 +20,7 @@ from .constants import *
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 
 
 VIFACE_TYPE_CHOICES = (
 VIFACE_TYPE_CHOICES = (
-    (IFACE_TYPE_VIRTUAL, 'Virtual'),
+    (InterfaceTypeChoices.TYPE_VIRTUAL, 'Virtual'),
 )
 )
 
 
 
 
@@ -733,7 +734,7 @@ class InterfaceCreateForm(ComponentForm):
     )
     )
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=VIFACE_TYPE_CHOICES,
         choices=VIFACE_TYPE_CHOICES,
-        initial=IFACE_TYPE_VIRTUAL,
+        initial=InterfaceTypeChoices.TYPE_VIRTUAL,
         widget=forms.HiddenInput()
         widget=forms.HiddenInput()
     )
     )
     enabled = forms.BooleanField(
     enabled = forms.BooleanField(
@@ -918,7 +919,7 @@ class VirtualMachineBulkAddComponentForm(BootstrapMixin, forms.Form):
 class VirtualMachineBulkAddInterfaceForm(VirtualMachineBulkAddComponentForm):
 class VirtualMachineBulkAddInterfaceForm(VirtualMachineBulkAddComponentForm):
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=VIFACE_TYPE_CHOICES,
         choices=VIFACE_TYPE_CHOICES,
-        initial=IFACE_TYPE_VIRTUAL,
+        initial=InterfaceTypeChoices.TYPE_VIRTUAL,
         widget=forms.HiddenInput()
         widget=forms.HiddenInput()
     )
     )
     enabled = forms.BooleanField(
     enabled = forms.BooleanField(

+ 5 - 4
netbox/virtualization/tests/test_api.py

@@ -2,7 +2,8 @@ from django.urls import reverse
 from netaddr import IPNetwork
 from netaddr import IPNetwork
 from rest_framework import status
 from rest_framework import status
 
 
-from dcim.constants import IFACE_TYPE_VIRTUAL, IFACE_MODE_TAGGED
+from dcim.choices import InterfaceTypeChoices
+from dcim.constants import IFACE_MODE_TAGGED
 from dcim.models import Interface
 from dcim.models import Interface
 from ipam.models import IPAddress, VLAN
 from ipam.models import IPAddress, VLAN
 from utilities.testing import APITestCase
 from utilities.testing import APITestCase
@@ -489,17 +490,17 @@ class InterfaceTest(APITestCase):
         self.interface1 = Interface.objects.create(
         self.interface1 = Interface.objects.create(
             virtual_machine=self.virtualmachine,
             virtual_machine=self.virtualmachine,
             name='Test Interface 1',
             name='Test Interface 1',
-            type=IFACE_TYPE_VIRTUAL
+            type=InterfaceTypeChoices.TYPE_VIRTUAL
         )
         )
         self.interface2 = Interface.objects.create(
         self.interface2 = Interface.objects.create(
             virtual_machine=self.virtualmachine,
             virtual_machine=self.virtualmachine,
             name='Test Interface 2',
             name='Test Interface 2',
-            type=IFACE_TYPE_VIRTUAL
+            type=InterfaceTypeChoices.TYPE_VIRTUAL
         )
         )
         self.interface3 = Interface.objects.create(
         self.interface3 = Interface.objects.create(
             virtual_machine=self.virtualmachine,
             virtual_machine=self.virtualmachine,
             name='Test Interface 3',
             name='Test Interface 3',
-            type=IFACE_TYPE_VIRTUAL
+            type=InterfaceTypeChoices.TYPE_VIRTUAL
         )
         )
 
 
         self.vlan1 = VLAN.objects.create(name="Test VLAN 1", vid=1)
         self.vlan1 = VLAN.objects.create(name="Test VLAN 1", vid=1)