mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-29 11:56:25 -06:00
Reorganize "Addressing" sections to remove from proximity to "Device Components" and related groupings
This commit is contained in:
parent
fc4483db48
commit
0214b9e382
@ -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)
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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',
|
||||
)
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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.")
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user