Browse Source

Closes #1218: Added IEEE 802.11 wireless interface types

Jeremy Stretch 7 years ago
parent
commit
68ebe85a98

+ 2 - 2
netbox/circuits/forms.py

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 from django import forms
 from django.db.models import Count
 
-from dcim.models import Site, Device, Interface, Rack, VIRTUAL_IFACE_TYPES
+from dcim.models import Site, Device, Interface, Rack
 from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
 from tenancy.forms import TenancyForm
 from tenancy.models import Tenant
@@ -210,7 +210,7 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm
         )
     )
     interface = ChainedModelChoiceField(
-        queryset=Interface.objects.exclude(form_factor__in=VIRTUAL_IFACE_TYPES).select_related(
+        queryset=Interface.objects.connectable().select_related(
             'circuit_termination', 'connected_as_a', 'connected_as_b'
         ),
         chains=(

+ 26 - 1
netbox/dcim/constants.py

@@ -66,6 +66,12 @@ IFACE_FF_25GE_SFP28 = 1350
 IFACE_FF_40GE_QSFP_PLUS = 1400
 IFACE_FF_100GE_CFP = 1500
 IFACE_FF_100GE_QSFP28 = 1600
+# Wireless
+IFACE_FF_80211A = 2600
+IFACE_FF_80211G = 2610
+IFACE_FF_80211N = 2620
+IFACE_FF_80211AC = 2630
+IFACE_FF_80211AD = 2640
 # Fibrechannel
 IFACE_FF_1GFC_SFP = 3010
 IFACE_FF_2GFC_SFP = 3020
@@ -118,6 +124,16 @@ IFACE_FF_CHOICES = [
         ]
     ],
     [
+        'Wireless',
+        [
+            [IFACE_FF_80211A, 'IEEE 802.11a'],
+            [IFACE_FF_80211G, 'IEEE 802.11b/g'],
+            [IFACE_FF_80211N, 'IEEE 802.11n'],
+            [IFACE_FF_80211AC, 'IEEE 802.11ac'],
+            [IFACE_FF_80211AD, 'IEEE 802.11ad'],
+        ]
+    ],
+    [
         'FibreChannel',
         [
             [IFACE_FF_1GFC_SFP, 'SFP (1GFC)'],
@@ -134,7 +150,6 @@ IFACE_FF_CHOICES = [
             [IFACE_FF_E1, 'E1 (2.048 Mbps)'],
             [IFACE_FF_T3, 'T3 (45 Mbps)'],
             [IFACE_FF_E3, 'E3 (34 Mbps)'],
-            [IFACE_FF_E3, 'E3 (34 Mbps)'],
         ]
     ],
     [
@@ -160,6 +175,16 @@ VIRTUAL_IFACE_TYPES = [
     IFACE_FF_LAG,
 ]
 
+WIRELESS_IFACE_TYPES = [
+    IFACE_FF_80211A,
+    IFACE_FF_80211G,
+    IFACE_FF_80211N,
+    IFACE_FF_80211AC,
+    IFACE_FF_80211AD,
+]
+
+NONCONNECTABLE_IFACE_TYPES = VIRTUAL_IFACE_TYPES + WIRELESS_IFACE_TYPES
+
 # Device statuses
 STATUS_OFFLINE = 0
 STATUS_ACTIVE = 1

+ 9 - 9
netbox/dcim/filters.py

@@ -11,8 +11,9 @@ from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
 from .models import (
     ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
     DeviceBayTemplate, DeviceRole, DeviceType, STATUS_CHOICES, IFACE_FF_LAG, Interface, InterfaceConnection,
-    InterfaceTemplate, Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort,
-    PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, Region, Site, VIRTUAL_IFACE_TYPES,
+    InterfaceTemplate, Manufacturer, InventoryItem, NONCONNECTABLE_IFACE_TYPES, Platform, PowerOutlet,
+    PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, Region, Site,
+    VIRTUAL_IFACE_TYPES, WIRELESS_IFACE_TYPES,
 )
 
 
@@ -513,13 +514,12 @@ class InterfaceFilter(django_filters.FilterSet):
 
     def filter_type(self, queryset, name, value):
         value = value.strip().lower()
-        if value == 'physical':
-            return queryset.exclude(form_factor__in=VIRTUAL_IFACE_TYPES)
-        elif value == 'virtual':
-            return queryset.filter(form_factor__in=VIRTUAL_IFACE_TYPES)
-        elif value == 'lag':
-            return queryset.filter(form_factor=IFACE_FF_LAG)
-        return queryset
+        return {
+            'physical': queryset.exclude(form_factor__in=NONCONNECTABLE_IFACE_TYPES),
+            'virtual': queryset.filter(form_factor__in=VIRTUAL_IFACE_TYPES),
+            'wireless': queryset.filter(form_factor__in=WIRELESS_IFACE_TYPES),
+            'lag': queryset.filter(form_factor=IFACE_FF_LAG),
+        }.get(value, queryset.none())
 
     def _mac_address(self, queryset, name, value):
         value = value.strip()

+ 3 - 5
netbox/dcim/forms.py

@@ -24,7 +24,7 @@ from .models import (
     IFACE_FF_CHOICES, IFACE_FF_LAG, IFACE_ORDERING_CHOICES, InterfaceConnection, InterfaceTemplate, Manufacturer,
     InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, RACK_FACE_CHOICES,
     RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, Rack, RackGroup, RackReservation, RackRole, RACK_WIDTH_19IN, RACK_WIDTH_23IN,
-    Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT, VIRTUAL_IFACE_TYPES,
+    Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT,
 )
 
 
@@ -1574,7 +1574,7 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor
         )
     )
     interface_b = ChainedModelChoiceField(
-        queryset=Interface.objects.exclude(form_factor__in=VIRTUAL_IFACE_TYPES).select_related(
+        queryset=Interface.objects.connectable().select_related(
             'circuit_termination', 'connected_as_a', 'connected_as_b'
         ),
         chains=(
@@ -1596,9 +1596,7 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor
         super(InterfaceConnectionForm, self).__init__(*args, **kwargs)
 
         # Initialize interface A choices
-        device_a_interfaces = Interface.objects.order_naturally().filter(device=device_a).exclude(
-            form_factor__in=VIRTUAL_IFACE_TYPES
-        ).select_related(
+        device_a_interfaces = Interface.objects.connectable().order_naturally().filter(device=device_a).select_related(
             'circuit_termination', 'connected_as_a', 'connected_as_b'
         )
         self.fields['interface_a'].choices = [

File diff suppressed because it is too large
+ 25 - 0
netbox/dcim/migrations/0038_wireless_interfaces.py


+ 15 - 4
netbox/dcim/models.py

@@ -661,6 +661,13 @@ class InterfaceQuerySet(models.QuerySet):
             '_vc': "COALESCE(CAST(SUBSTRING({} FROM '\.([0-9]+)$') AS integer), 0)".format(sql_col),
         }).order_by(*ordering)
 
+    def connectable(self):
+        """
+        Return only physical interfaces which are capable of being connected to other interfaces (i.e. not virtual or
+        wireless).
+        """
+        return self.exclude(form_factor__in=NONCONNECTABLE_IFACE_TYPES)
+
 
 @python_2_unicode_compatible
 class InterfaceTemplate(models.Model):
@@ -1134,10 +1141,10 @@ class Interface(models.Model):
     def clean(self):
 
         # Virtual interfaces cannot be connected
-        if self.form_factor in VIRTUAL_IFACE_TYPES and self.is_connected:
+        if self.form_factor in NONCONNECTABLE_IFACE_TYPES and self.is_connected:
             raise ValidationError({
-                'form_factor': "Virtual interfaces cannot be connected to another interface or circuit. Disconnect the "
-                               "interface or choose a physical form factor."
+                'form_factor': "Virtual and wireless interfaces cannot be connected to another interface or circuit. "
+                               "Disconnect the interface or choose a suitable form factor."
             })
 
         # An interface's LAG must belong to the same device
@@ -1149,7 +1156,7 @@ class Interface(models.Model):
             })
 
         # A virtual interface cannot have a parent LAG
-        if self.form_factor in VIRTUAL_IFACE_TYPES and self.lag is not None:
+        if self.form_factor in NONCONNECTABLE_IFACE_TYPES and self.lag is not None:
             raise ValidationError({
                 'lag': "{} interfaces cannot have a parent LAG interface.".format(self.get_form_factor_display())
             })
@@ -1167,6 +1174,10 @@ class Interface(models.Model):
         return self.form_factor in VIRTUAL_IFACE_TYPES
 
     @property
+    def is_wireless(self):
+        return self.form_factor in WIRELESS_IFACE_TYPES
+
+    @property
     def is_lag(self):
         return self.form_factor == IFACE_FF_LAG
 

+ 3 - 1
netbox/templates/dcim/inc/interface.html

@@ -5,7 +5,7 @@
         </td>
     {% endif %}
     <td>
-        <i class="fa fa-fw fa-{% if iface.mgmt_only %}wrench{% else %}exchange{% endif %}"></i>
+        <i class="fa fa-fw fa-{% if iface.mgmt_only %}wrench{% elif iface.is_virtual %}square{% elif iface.is_wireless %}wifi{% else %}exchange{% endif %}"></i>
         <span title="{{ iface.get_form_factor_display }}">{{ iface.name }}</span>
         {% if iface.lag %}
             <span class="label label-primary">{{ iface.lag.name }}</span>
@@ -22,6 +22,8 @@
         </td>
     {% elif iface.is_virtual %}
         <td colspan="2" class="text-muted">Virtual interface</td>
+    {% elif iface.is_wireless %}
+        <td colspan="2" class="text-muted">Wireless interface</td>
     {% elif iface.connection %}
         {% with iface.connected_interface as connected_iface %}
             <td>