Reorganize "Addressing" sections to remove from proximity to "Device Components" and related groupings

This commit is contained in:
Brian Tiemann 2024-11-14 19:11:05 -05:00
parent fc4483db48
commit 0214b9e382
6 changed files with 238 additions and 232 deletions

View File

@ -42,7 +42,6 @@ router.register('virtual-device-contexts', views.VirtualDeviceContextViewSet)
router.register('modules', views.ModuleViewSet)
# Device components
router.register('mac-addresses', views.MACAddressViewSet)
router.register('console-ports', views.ConsolePortViewSet)
router.register('console-server-ports', views.ConsoleServerPortViewSet)
router.register('power-ports', views.PowerPortViewSet)
@ -57,6 +56,9 @@ router.register('inventory-items', views.InventoryItemViewSet)
# Device component roles
router.register('inventory-item-roles', views.InventoryItemRoleViewSet)
# Addressing
router.register('mac-addresses', views.MACAddressViewSet)
# Cables
router.register('cables', views.CableViewSet)
router.register('cable-terminations', views.CableTerminationViewSet)

View File

@ -408,12 +408,6 @@ class ModuleViewSet(NetBoxModelViewSet):
# Device components
#
class MACAddressViewSet(NetBoxModelViewSet):
queryset = MACAddress.objects.all()
serializer_class = serializers.MACAddressSerializer
filterset_class = filtersets.MACAddressFilterSet
class ConsolePortViewSet(PathEndpointMixin, NetBoxModelViewSet):
queryset = ConsolePort.objects.prefetch_related(
'_path', 'cable__terminations',
@ -505,6 +499,16 @@ class InventoryItemRoleViewSet(NetBoxModelViewSet):
filterset_class = filtersets.InventoryItemRoleFilterSet
#
# Addressing
#
class MACAddressViewSet(NetBoxModelViewSet):
queryset = MACAddress.objects.all()
serializer_class = serializers.MACAddressSerializer
filterset_class = filtersets.MACAddressFilterSet
#
# Cables
#

View File

@ -1274,32 +1274,6 @@ class InventoryItemTemplateBulkEditForm(BulkEditForm):
nullable_fields = ('label', 'role', 'manufacturer', 'part_id', 'description')
#
# Addressing
#
class MACAddressBulkEditForm(NetBoxModelBulkEditForm):
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
is_primary = forms.NullBooleanField(
label=_('Is primary'),
required=False,
widget=BulkEditNullBooleanSelect(),
)
comments = CommentField()
model = MACAddress
fieldsets = (
FieldSet('description', 'is_primary'),
)
nullable_fields = (
'description', 'comments',
)
#
# Device components
#
@ -1746,3 +1720,29 @@ class VirtualDeviceContextBulkEditForm(NetBoxModelBulkEditForm):
FieldSet('device', 'status', 'tenant'),
)
nullable_fields = ('device', 'tenant', )
#
# Addressing
#
class MACAddressBulkEditForm(NetBoxModelBulkEditForm):
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
is_primary = forms.NullBooleanField(
label=_('Is primary'),
required=False,
widget=BulkEditNullBooleanSelect(),
)
comments = CommentField()
model = MACAddress
fieldsets = (
FieldSet('description', 'is_primary'),
)
nullable_fields = (
'description', 'comments',
)

View File

@ -696,90 +696,6 @@ class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm):
return self.cleaned_data['replicate_components']
#
# Addressing
#
class MACAddressImportForm(NetBoxModelImportForm):
device = CSVModelChoiceField(
label=_('Device'),
queryset=Device.objects.all(),
required=False,
to_field_name='name',
help_text=_('Parent device of assigned interface (if any)')
)
virtual_machine = CSVModelChoiceField(
label=_('Virtual machine'),
queryset=VirtualMachine.objects.all(),
required=False,
to_field_name='name',
help_text=_('Parent VM of assigned interface (if any)')
)
interface = CSVModelChoiceField(
label=_('Interface'),
queryset=Interface.objects.none(), # Can also refer to VMInterface
required=False,
to_field_name='name',
help_text=_('Assigned interface')
)
is_primary = forms.BooleanField(
label=_('Is primary'),
help_text=_('Make this the primary MAC address for the assigned interface'),
required=False
)
class Meta:
model = MACAddress
fields = [
'mac_address', 'device', 'virtual_machine', 'interface', 'is_primary',
'description', 'comments', 'tags',
]
def __init__(self, data=None, *args, **kwargs):
super().__init__(data, *args, **kwargs)
if data:
# Limit interface queryset by assigned device
if data.get('device'):
self.fields['interface'].queryset = Interface.objects.filter(
**{f"device__{self.fields['device'].to_field_name}": data['device']}
)
# Limit interface queryset by assigned device
elif data.get('virtual_machine'):
self.fields['interface'].queryset = VMInterface.objects.filter(
**{f"virtual_machine__{self.fields['virtual_machine'].to_field_name}": data['virtual_machine']}
)
def clean(self):
super().clean()
device = self.cleaned_data.get('device')
virtual_machine = self.cleaned_data.get('virtual_machine')
interface = self.cleaned_data.get('interface')
is_primary = self.cleaned_data.get('is_primary')
# Validate is_primary
# TODO: scope to interface rather than device/VM
if is_primary and not device and not virtual_machine:
raise forms.ValidationError({
"is_primary": _("No device or virtual machine specified; cannot set as primary")
})
if is_primary and not interface:
raise forms.ValidationError({
"is_primary": _("No interface specified; cannot set as primary")
})
def save(self, *args, **kwargs):
# Set interface assignment
if self.cleaned_data.get('interface'):
self.instance.assigned_object = self.cleaned_data['interface']
return super().save(*args, **kwargs)
#
# Device components
#
@ -1252,6 +1168,90 @@ class InventoryItemRoleImportForm(NetBoxModelImportForm):
fields = ('name', 'slug', 'color', 'description')
#
# Addressing
#
class MACAddressImportForm(NetBoxModelImportForm):
device = CSVModelChoiceField(
label=_('Device'),
queryset=Device.objects.all(),
required=False,
to_field_name='name',
help_text=_('Parent device of assigned interface (if any)')
)
virtual_machine = CSVModelChoiceField(
label=_('Virtual machine'),
queryset=VirtualMachine.objects.all(),
required=False,
to_field_name='name',
help_text=_('Parent VM of assigned interface (if any)')
)
interface = CSVModelChoiceField(
label=_('Interface'),
queryset=Interface.objects.none(), # Can also refer to VMInterface
required=False,
to_field_name='name',
help_text=_('Assigned interface')
)
is_primary = forms.BooleanField(
label=_('Is primary'),
help_text=_('Make this the primary MAC address for the assigned interface'),
required=False
)
class Meta:
model = MACAddress
fields = [
'mac_address', 'device', 'virtual_machine', 'interface', 'is_primary',
'description', 'comments', 'tags',
]
def __init__(self, data=None, *args, **kwargs):
super().__init__(data, *args, **kwargs)
if data:
# Limit interface queryset by assigned device
if data.get('device'):
self.fields['interface'].queryset = Interface.objects.filter(
**{f"device__{self.fields['device'].to_field_name}": data['device']}
)
# Limit interface queryset by assigned device
elif data.get('virtual_machine'):
self.fields['interface'].queryset = VMInterface.objects.filter(
**{f"virtual_machine__{self.fields['virtual_machine'].to_field_name}": data['virtual_machine']}
)
def clean(self):
super().clean()
device = self.cleaned_data.get('device')
virtual_machine = self.cleaned_data.get('virtual_machine')
interface = self.cleaned_data.get('interface')
is_primary = self.cleaned_data.get('is_primary')
# Validate is_primary
# TODO: scope to interface rather than device/VM
if is_primary and not device and not virtual_machine:
raise forms.ValidationError({
"is_primary": _("No device or virtual machine specified; cannot set as primary")
})
if is_primary and not interface:
raise forms.ValidationError({
"is_primary": _("No interface specified; cannot set as primary")
})
def save(self, *args, **kwargs):
# Set interface assignment
if self.cleaned_data.get('interface'):
self.instance.assigned_object = self.cleaned_data['interface']
return super().save(*args, **kwargs)
#
# Cables
#

View File

@ -1202,35 +1202,6 @@ class PowerFeedFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model)
#
# Addressing
#
class MACAddressFilterForm(NetBoxModelFilterSetForm):
model = MACAddress
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('mac_address', name=_('Addressing')),
FieldSet('device_id', 'virtual_machine_id', name=_('Device/VM')),
)
selector_fields = ('filter_id', 'q', 'device_id', 'virtual_machine_id')
mac_address = forms.CharField(
required=False,
label=_('MAC address')
)
device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False,
label=_('Assigned Device'),
)
virtual_machine_id = DynamicModelMultipleChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
label=_('Assigned VM'),
)
tag = TagFilterField(model)
#
# Device components
#
@ -1604,6 +1575,35 @@ class InventoryItemRoleFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model)
#
# Addressing
#
class MACAddressFilterForm(NetBoxModelFilterSetForm):
model = MACAddress
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('mac_address', name=_('Addressing')),
FieldSet('device_id', 'virtual_machine_id', name=_('Device/VM')),
)
selector_fields = ('filter_id', 'q', 'device_id', 'virtual_machine_id')
mac_address = forms.CharField(
required=False,
label=_('MAC address')
)
device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False,
label=_('Assigned Device'),
)
virtual_machine_id = DynamicModelMultipleChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
label=_('Assigned VM'),
)
tag = TagFilterField(model)
#
# Connections
#

View File

@ -866,92 +866,6 @@ class VCMemberSelectForm(forms.Form):
return device
#
# Addressing
#
class MACAddressForm(NetBoxModelForm):
mac_address = forms.CharField(
required=True,
label=_('MAC address')
)
interface = DynamicModelChoiceField(
label=_('Interface'),
queryset=Interface.objects.all(),
required=False,
)
vminterface = DynamicModelChoiceField(
label=_('VM Interface'),
queryset=VMInterface.objects.all(),
required=False,
)
is_primary = forms.BooleanField(
required=False,
label=_('Primary for interface'),
)
fieldsets = (
FieldSet(
'mac_address', 'description', 'tags',
),
FieldSet(
TabbedGroups(
FieldSet('interface', name=_('Device')),
FieldSet('vminterface', name=_('Virtual Machine')),
),
'is_primary', name=_('Assignment')
),
)
class Meta:
model = MACAddress
fields = [
'mac_address', 'interface', 'vminterface', 'is_primary', 'description', 'tags',
]
def __init__(self, *args, **kwargs):
# Initialize helper selectors
instance = kwargs.get('instance')
initial = kwargs.get('initial', {}).copy()
if instance:
if type(instance.assigned_object) is Interface:
initial['interface'] = instance.assigned_object
elif type(instance.assigned_object) is VMInterface:
initial['vminterface'] = instance.assigned_object
kwargs['initial'] = initial
super().__init__(*args, **kwargs)
def clean(self):
super().clean()
# Handle object assignment
selected_objects = [
field for field in ('interface', 'vminterface') if self.cleaned_data[field]
]
if len(selected_objects) > 1:
raise forms.ValidationError({
selected_objects[1]: _("A MAC address can only be assigned to a single object.")
})
elif selected_objects:
assigned_object = self.cleaned_data[selected_objects[0]]
if self.instance.pk and self.instance.assigned_object and self.instance.is_primary and assigned_object != self.instance.assigned_object:
raise ValidationError(
_("Cannot reassign MAC address while it is designated as the primary for the interface")
)
self.instance.assigned_object = assigned_object
else:
self.instance.assigned_object = None
# Primary MAC address assignment is only available if an interface has been assigned.
interface = self.cleaned_data.get('interface') or self.cleaned_data.get('vminterface')
if self.cleaned_data.get('is_primary') and not interface:
self.add_error(
'is_primary', _("Only IP addresses assigned to an interface can be designated as primary IPs.")
)
#
# Device component templates
#
@ -1820,3 +1734,89 @@ class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm):
'device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant',
'comments', 'tags'
]
#
# Addressing
#
class MACAddressForm(NetBoxModelForm):
mac_address = forms.CharField(
required=True,
label=_('MAC address')
)
interface = DynamicModelChoiceField(
label=_('Interface'),
queryset=Interface.objects.all(),
required=False,
)
vminterface = DynamicModelChoiceField(
label=_('VM Interface'),
queryset=VMInterface.objects.all(),
required=False,
)
is_primary = forms.BooleanField(
required=False,
label=_('Primary for interface'),
)
fieldsets = (
FieldSet(
'mac_address', 'description', 'tags',
),
FieldSet(
TabbedGroups(
FieldSet('interface', name=_('Device')),
FieldSet('vminterface', name=_('Virtual Machine')),
),
'is_primary', name=_('Assignment')
),
)
class Meta:
model = MACAddress
fields = [
'mac_address', 'interface', 'vminterface', 'is_primary', 'description', 'tags',
]
def __init__(self, *args, **kwargs):
# Initialize helper selectors
instance = kwargs.get('instance')
initial = kwargs.get('initial', {}).copy()
if instance:
if type(instance.assigned_object) is Interface:
initial['interface'] = instance.assigned_object
elif type(instance.assigned_object) is VMInterface:
initial['vminterface'] = instance.assigned_object
kwargs['initial'] = initial
super().__init__(*args, **kwargs)
def clean(self):
super().clean()
# Handle object assignment
selected_objects = [
field for field in ('interface', 'vminterface') if self.cleaned_data[field]
]
if len(selected_objects) > 1:
raise forms.ValidationError({
selected_objects[1]: _("A MAC address can only be assigned to a single object.")
})
elif selected_objects:
assigned_object = self.cleaned_data[selected_objects[0]]
if self.instance.pk and self.instance.assigned_object and self.instance.is_primary and assigned_object != self.instance.assigned_object:
raise ValidationError(
_("Cannot reassign MAC address while it is designated as the primary for the interface")
)
self.instance.assigned_object = assigned_object
else:
self.instance.assigned_object = None
# Primary MAC address assignment is only available if an interface has been assigned.
interface = self.cleaned_data.get('interface') or self.cleaned_data.get('vminterface')
if self.cleaned_data.get('is_primary') and not interface:
self.add_error(
'is_primary', _("Only IP addresses assigned to an interface can be designated as primary IPs.")
)