Create MACAddress model and migrations to convert existing .mac_address fields to standalone objects

This commit is contained in:
Brian Tiemann 2024-10-27 21:22:54 -04:00
parent ef1fdf0a01
commit 44b627064c
8 changed files with 44 additions and 11 deletions

View File

@ -1099,7 +1099,7 @@ class DeviceFilterSet(
label=_('Is full depth'), label=_('Is full depth'),
) )
mac_address = MultiValueMACAddressFilter( mac_address = MultiValueMACAddressFilter(
field_name='interfaces__mac_address', field_name='interfaces___mac_address',
label=_('MAC address'), label=_('MAC address'),
) )
serial = MultiValueCharFilter( serial = MultiValueCharFilter(
@ -1689,7 +1689,7 @@ class InterfaceFilterSet(
duplex = django_filters.MultipleChoiceFilter( duplex = django_filters.MultipleChoiceFilter(
choices=InterfaceDuplexChoices choices=InterfaceDuplexChoices
) )
mac_address = MultiValueMACAddressFilter() # mac_address = MultiValueMACAddressFilter()
wwn = MultiValueWWNFilter() wwn = MultiValueWWNFilter()
poe_mode = django_filters.MultipleChoiceFilter( poe_mode = django_filters.MultipleChoiceFilter(
choices=InterfacePoEModeChoices choices=InterfacePoEModeChoices

View File

@ -1392,7 +1392,7 @@ class PowerOutletBulkEditForm(
class InterfaceBulkEditForm( class InterfaceBulkEditForm(
ComponentBulkEditForm, ComponentBulkEditForm,
form_from_model(Interface, [ form_from_model(Interface, [
'label', 'type', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'label', 'type', 'parent', 'bridge', 'lag', 'speed', 'duplex', '_mac_address', 'wwn', 'mtu', 'mgmt_only',
'mark_connected', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'mark_connected', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width',
'tx_power', 'wireless_lans' 'tx_power', 'wireless_lans'
]) ])

View File

@ -906,7 +906,7 @@ class InterfaceImportForm(NetBoxModelImportForm):
model = Interface model = Interface
fields = ( fields = (
'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled', 'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled',
'mark_connected', 'mac_address', 'wwn', 'vdcs', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode', 'mark_connected', '_mac_address', 'wwn', 'vdcs', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode',
'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'tags' 'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'tags'
) )

View File

@ -377,7 +377,7 @@ class FrontPortTemplateType(ModularComponentTemplateType):
filters=InterfaceFilter filters=InterfaceFilter
) )
class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin): class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin):
mac_address: str | None _mac_address: str | None
wwn: str | None wwn: str | None
parent: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None parent: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None
bridge: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None bridge: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None

View File

@ -12,7 +12,7 @@ from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.fields import MACAddressField, WWNField from dcim.fields import MACAddressField, WWNField
from netbox.choices import ColorChoices from netbox.choices import ColorChoices
from netbox.models import OrganizationalModel, NetBoxModel from netbox.models import OrganizationalModel, NetBoxModel, PrimaryModel
from utilities.fields import ColorField, NaturalOrderingField from utilities.fields import ColorField, NaturalOrderingField
from utilities.mptt import TreeManager from utilities.mptt import TreeManager
from utilities.ordering import naturalize_interface from utilities.ordering import naturalize_interface
@ -31,6 +31,7 @@ __all__ = (
'Interface', 'Interface',
'InventoryItem', 'InventoryItem',
'InventoryItemRole', 'InventoryItemRole',
'MACAddress',
'ModuleBay', 'ModuleBay',
'PathEndpoint', 'PathEndpoint',
'PowerOutlet', 'PowerOutlet',
@ -509,7 +510,7 @@ class BaseInterface(models.Model):
verbose_name=_('enabled'), verbose_name=_('enabled'),
default=True default=True
) )
mac_address = MACAddressField( _mac_address = MACAddressField(
null=True, null=True,
blank=True, blank=True,
verbose_name=_('MAC address') verbose_name=_('MAC address')
@ -575,6 +576,12 @@ class BaseInterface(models.Model):
def count_fhrp_groups(self): def count_fhrp_groups(self):
return self.fhrp_group_assignments.count() return self.fhrp_group_assignments.count()
@property
def mac_address(self):
if macaddress := self.macaddress_set.first():
return macaddress.mac_address
return None
class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEndpoint, TrackingModelMixin): class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEndpoint, TrackingModelMixin):
""" """
@ -1323,3 +1330,29 @@ class InventoryItem(MPTTModel, ComponentModel, TrackingModelMixin):
def get_status_color(self): def get_status_color(self):
return InventoryItemStatusChoices.colors.get(self.status) return InventoryItemStatusChoices.colors.get(self.status)
class MACAddress(PrimaryModel):
mac_address = MACAddressField(
null=True,
blank=True,
verbose_name=_('MAC address')
)
interface = models.ForeignKey(
to='dcim.Interface',
on_delete=models.PROTECT,
null=True,
blank=True,
verbose_name=_('Interface')
)
vm_interface = models.ForeignKey(
to='virtualization.VMInterface',
on_delete=models.PROTECT,
null=True,
blank=True,
verbose_name=_('VM Interface')
)
is_primary = models.BooleanField(
verbose_name=_('is primary for interface'),
default=False
)

View File

@ -226,7 +226,7 @@ class VirtualMachineFilterSet(
label=_('Platform (slug)'), label=_('Platform (slug)'),
) )
mac_address = MultiValueMACAddressFilter( mac_address = MultiValueMACAddressFilter(
field_name='interfaces__mac_address', field_name='interfaces___mac_address',
label=_('MAC address'), label=_('MAC address'),
) )
has_primary_ip = django_filters.BooleanFilter( has_primary_ip = django_filters.BooleanFilter(
@ -297,7 +297,7 @@ class VMInterfaceFilterSet(NetBoxModelFilterSet, CommonInterfaceFilterSet):
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
label=_('Bridged interface (ID)'), label=_('Bridged interface (ID)'),
) )
mac_address = MultiValueMACAddressFilter( _mac_address = MultiValueMACAddressFilter(
label=_('MAC address'), label=_('MAC address'),
) )

View File

@ -178,7 +178,7 @@ class VMInterfaceImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = VMInterface model = VMInterface
fields = ( fields = (
'virtual_machine', 'name', 'parent', 'bridge', 'enabled', 'mac_address', 'mtu', 'description', 'mode', 'virtual_machine', 'name', 'parent', 'bridge', 'enabled', '_mac_address', 'mtu', 'description', 'mode',
'vrf', 'tags' 'vrf', 'tags'
) )

View File

@ -95,7 +95,7 @@ class VirtualMachineType(ConfigContextMixin, ContactsMixin, NetBoxObjectType):
filters=VMInterfaceFilter filters=VMInterfaceFilter
) )
class VMInterfaceType(IPAddressesMixin, ComponentType): class VMInterfaceType(IPAddressesMixin, ComponentType):
mac_address: str | None _mac_address: str | None
parent: Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')] | None parent: Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')] | None
bridge: Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')] | None bridge: Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')] | None
untagged_vlan: Annotated["VLANType", strawberry.lazy('ipam.graphql.types')] | None untagged_vlan: Annotated["VLANType", strawberry.lazy('ipam.graphql.types')] | None