mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
73 lines
3.2 KiB
Python
73 lines
3.2 KiB
Python
|
from __future__ import unicode_literals
|
||
|
|
||
|
from django.db.models import QuerySet
|
||
|
from django.db.models.expressions import RawSQL
|
||
|
|
||
|
from .constants import IFACE_ORDERING_NAME, IFACE_ORDERING_POSITION, NONCONNECTABLE_IFACE_TYPES
|
||
|
|
||
|
|
||
|
class InterfaceQuerySet(QuerySet):
|
||
|
|
||
|
def order_naturally(self, method=IFACE_ORDERING_POSITION):
|
||
|
"""
|
||
|
Naturally order interfaces by their type and numeric position. The sort method must be one of the defined
|
||
|
IFACE_ORDERING_CHOICES (typically indicated by a parent Device's DeviceType).
|
||
|
|
||
|
To order interfaces naturally, the `name` field is split into six distinct components: leading text (type),
|
||
|
slot, subslot, position, channel, and virtual circuit:
|
||
|
|
||
|
{type}{slot}/{subslot}/{position}/{subposition}:{channel}.{vc}
|
||
|
|
||
|
Components absent from the interface name are ignored. For example, an interface named GigabitEthernet1/2/3
|
||
|
would be parsed as follows:
|
||
|
|
||
|
name = 'GigabitEthernet'
|
||
|
slot = 1
|
||
|
subslot = 2
|
||
|
position = 3
|
||
|
subposition = 0
|
||
|
channel = None
|
||
|
vc = 0
|
||
|
|
||
|
The original `name` field is taken as a whole to serve as a fallback in the event interfaces do not match any of
|
||
|
the prescribed fields.
|
||
|
"""
|
||
|
sql_col = '{}.name'.format(self.model._meta.db_table)
|
||
|
ordering = {
|
||
|
IFACE_ORDERING_POSITION: (
|
||
|
'_slot', '_subslot', '_position', '_subposition', '_channel', '_type', '_vc', '_id', 'name',
|
||
|
),
|
||
|
IFACE_ORDERING_NAME: (
|
||
|
'_type', '_slot', '_subslot', '_position', '_subposition', '_channel', '_vc', '_id', 'name',
|
||
|
),
|
||
|
}[method]
|
||
|
|
||
|
TYPE_RE = r"SUBSTRING({} FROM '^([^0-9]+)')"
|
||
|
ID_RE = r"CAST(SUBSTRING({} FROM '^(?:[^0-9]+)([0-9]+)$') AS integer)"
|
||
|
SLOT_RE = r"CAST(SUBSTRING({} FROM '^(?:[^0-9]+)([0-9]+)\/') AS integer)"
|
||
|
SUBSLOT_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^(?:[^0-9]+)(?:[0-9]+\/)([0-9]+)') AS integer), 0)"
|
||
|
POSITION_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^(?:[^0-9]+)(?:[0-9]+\/){{2}}([0-9]+)') AS integer), 0)"
|
||
|
SUBPOSITION_RE = r"COALESCE(CAST(SUBSTRING({} FROM '^(?:[^0-9]+)(?:[0-9]+\/){{3}}([0-9]+)') AS integer), 0)"
|
||
|
CHANNEL_RE = r"COALESCE(CAST(SUBSTRING({} FROM ':([0-9]+)(\.[0-9]+)?$') AS integer), 0)"
|
||
|
VC_RE = r"COALESCE(CAST(SUBSTRING({} FROM '\.([0-9]+)$') AS integer), 0)"
|
||
|
|
||
|
fields = {
|
||
|
'_type': RawSQL(TYPE_RE.format(sql_col), []),
|
||
|
'_id': RawSQL(ID_RE.format(sql_col), []),
|
||
|
'_slot': RawSQL(SLOT_RE.format(sql_col), []),
|
||
|
'_subslot': RawSQL(SUBSLOT_RE.format(sql_col), []),
|
||
|
'_position': RawSQL(POSITION_RE.format(sql_col), []),
|
||
|
'_subposition': RawSQL(SUBPOSITION_RE.format(sql_col), []),
|
||
|
'_channel': RawSQL(CHANNEL_RE.format(sql_col), []),
|
||
|
'_vc': RawSQL(VC_RE.format(sql_col), []),
|
||
|
}
|
||
|
|
||
|
return self.annotate(**fields).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)
|