Skip to content

Commit addda05

Browse files
Fixes #20584: Ensure consistent validation between Interface & InterfaceTemplate (#20589)
1 parent c902a1c commit addda05

File tree

3 files changed

+45
-34
lines changed

3 files changed

+45
-34
lines changed

netbox/dcim/models/device_component_templates.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from dcim.choices import *
99
from dcim.constants import *
10+
from dcim.models.mixins import InterfaceValidationMixin
1011
from netbox.models import ChangeLoggedModel
1112
from utilities.fields import ColorField, NaturalOrderingField
1213
from utilities.mptt import TreeManager
@@ -405,7 +406,7 @@ def to_yaml(self):
405406
}
406407

407408

408-
class InterfaceTemplate(ModularComponentTemplateModel):
409+
class InterfaceTemplate(InterfaceValidationMixin, ModularComponentTemplateModel):
409410
"""
410411
A template for a physical data interface on a new Device.
411412
"""
@@ -469,8 +470,6 @@ def clean(self):
469470
super().clean()
470471

471472
if self.bridge:
472-
if self.pk and self.bridge_id == self.pk:
473-
raise ValidationError({'bridge': _("An interface cannot be bridged to itself.")})
474473
if self.device_type and self.device_type != self.bridge.device_type:
475474
raise ValidationError({
476475
'bridge': _(
@@ -484,11 +483,6 @@ def clean(self):
484483
).format(bridge=self.bridge)
485484
})
486485

487-
if self.rf_role and self.type not in WIRELESS_IFACE_TYPES:
488-
raise ValidationError({
489-
'rf_role': "Wireless role may be set only on wireless interfaces."
490-
})
491-
492486
def instantiate(self, **kwargs):
493487
return self.component_model(
494488
name=self.resolve_name(kwargs.get('module')),

netbox/dcim/models/device_components.py

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from dcim.choices import *
1212
from dcim.constants import *
1313
from dcim.fields import WWNField
14+
from dcim.models.mixins import InterfaceValidationMixin
1415
from netbox.choices import ColorChoices
1516
from netbox.models import OrganizationalModel, NetBoxModel
1617
from utilities.fields import ColorField, NaturalOrderingField
@@ -676,7 +677,14 @@ def mac_address(self):
676677
return self.primary_mac_address.mac_address
677678

678679

679-
class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEndpoint, TrackingModelMixin):
680+
class Interface(
681+
InterfaceValidationMixin,
682+
ModularComponentModel,
683+
BaseInterface,
684+
CabledObjectModel,
685+
PathEndpoint,
686+
TrackingModelMixin,
687+
):
680688
"""
681689
A network interface within a Device. A physical Interface can connect to exactly one other Interface.
682690
"""
@@ -893,10 +901,6 @@ def clean(self):
893901

894902
# Bridge validation
895903

896-
# An interface cannot be bridged to itself
897-
if self.pk and self.bridge_id == self.pk:
898-
raise ValidationError({'bridge': _("An interface cannot be bridged to itself.")})
899-
900904
# A bridged interface belongs to the same device or virtual chassis
901905
if self.bridge and self.bridge.device != self.device:
902906
if self.device.virtual_chassis is None:
@@ -942,29 +946,9 @@ def clean(self):
942946
)
943947
})
944948

945-
# PoE validation
946-
947-
# Only physical interfaces may have a PoE mode/type assigned
948-
if self.poe_mode and self.is_virtual:
949-
raise ValidationError({
950-
'poe_mode': _("Virtual interfaces cannot have a PoE mode.")
951-
})
952-
if self.poe_type and self.is_virtual:
953-
raise ValidationError({
954-
'poe_type': _("Virtual interfaces cannot have a PoE type.")
955-
})
956-
957-
# An interface with a PoE type set must also specify a mode
958-
if self.poe_type and not self.poe_mode:
959-
raise ValidationError({
960-
'poe_type': _("Must specify PoE mode when designating a PoE type.")
961-
})
962-
963949
# Wireless validation
964950

965-
# RF role & channel may only be set for wireless interfaces
966-
if self.rf_role and not self.is_wireless:
967-
raise ValidationError({'rf_role': _("Wireless role may be set only on wireless interfaces.")})
951+
# RF channel may only be set for wireless interfaces
968952
if self.rf_channel and not self.is_wireless:
969953
raise ValidationError({'rf_channel': _("Channel may be set only on wireless interfaces.")})
970954

netbox/dcim/models/mixins.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
from django.db import models
55
from django.utils.translation import gettext_lazy as _
66

7+
from dcim.constants import VIRTUAL_IFACE_TYPES, WIRELESS_IFACE_TYPES
8+
79
__all__ = (
810
'CachedScopeMixin',
11+
'InterfaceValidationMixin',
912
'RenderConfigMixin',
1013
)
1114

@@ -116,3 +119,33 @@ def cache_related_objects(self):
116119
self._site = self.scope.site
117120
self._location = self.scope
118121
cache_related_objects.alters_data = True
122+
123+
124+
class InterfaceValidationMixin:
125+
126+
def clean(self):
127+
super().clean()
128+
129+
# An interface cannot be bridged to itself
130+
if self.pk and self.bridge_id == self.pk:
131+
raise ValidationError({'bridge': _("An interface cannot be bridged to itself.")})
132+
133+
# Only physical interfaces may have a PoE mode/type assigned
134+
if self.poe_mode and self.type in VIRTUAL_IFACE_TYPES:
135+
raise ValidationError({
136+
'poe_mode': _("Virtual interfaces cannot have a PoE mode.")
137+
})
138+
if self.poe_type and self.type in VIRTUAL_IFACE_TYPES:
139+
raise ValidationError({
140+
'poe_type': _("Virtual interfaces cannot have a PoE type.")
141+
})
142+
143+
# An interface with a PoE type set must also specify a mode
144+
if self.poe_type and not self.poe_mode:
145+
raise ValidationError({
146+
'poe_type': _("Must specify PoE mode when designating a PoE type.")
147+
})
148+
149+
# RF role may be set only for wireless interfaces
150+
if self.rf_role and self.type not in WIRELESS_IFACE_TYPES:
151+
raise ValidationError({'rf_role': _("Wireless role may be set only on wireless interfaces.")})

0 commit comments

Comments
 (0)