From 9ef24d3f43022f61044756741f40e095e9290bc1 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 3 Oct 2022 10:39:03 -0400 Subject: [PATCH] Fixes #10513: Disable the reassignment of a module to a new device --- docs/release-notes/version-3.3.md | 1 + netbox/dcim/forms/models.py | 1 + netbox/dcim/models/devices.py | 8 ++++++++ netbox/dcim/tests/test_views.py | 5 +++-- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index e91e825f5..2c2db9e47 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -16,6 +16,7 @@ * [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI * [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms * [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window +* [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device --- diff --git a/netbox/dcim/forms/models.py b/netbox/dcim/forms/models.py index b33023ece..1f1c869a5 100644 --- a/netbox/dcim/forms/models.py +++ b/netbox/dcim/forms/models.py @@ -679,6 +679,7 @@ class ModuleForm(NetBoxModelForm): super().__init__(*args, **kwargs) if self.instance.pk: + self.fields['device'].disabled = True self.fields['replicate_components'].initial = False self.fields['replicate_components'].disabled = True self.fields['adopt_components'].initial = False diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index ccf4613bf..4c542341e 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -987,6 +987,14 @@ class Module(NetBoxModel, ConfigContextModel): def get_absolute_url(self): return reverse('dcim:module', args=[self.pk]) + def clean(self): + super().clean() + + if self.module_bay.device != self.device: + raise ValidationError( + f"Module must be installed within a module bay belonging to the assigned device ({self.device})." + ) + def save(self, *args, **kwargs): is_new = self.pk is None diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 50b36e36d..db3495521 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1778,10 +1778,12 @@ class ModuleTestCase( ModuleBay(device=devices[0], name='Module Bay 2'), ModuleBay(device=devices[0], name='Module Bay 3'), ModuleBay(device=devices[0], name='Module Bay 4'), + ModuleBay(device=devices[0], name='Module Bay 5'), ModuleBay(device=devices[1], name='Module Bay 1'), ModuleBay(device=devices[1], name='Module Bay 2'), ModuleBay(device=devices[1], name='Module Bay 3'), ModuleBay(device=devices[1], name='Module Bay 4'), + ModuleBay(device=devices[1], name='Module Bay 5'), ) ModuleBay.objects.bulk_create(module_bays) @@ -1795,7 +1797,7 @@ class ModuleTestCase( tags = create_tags('Alpha', 'Bravo', 'Charlie') cls.form_data = { - 'device': devices[1].pk, + 'device': devices[0].pk, 'module_bay': module_bays[3].pk, 'module_type': module_types[0].pk, 'serial': 'A', @@ -1867,7 +1869,6 @@ class ModuleTestCase( self.assertIsNone(interface.module) # Create a module with adopted components - form_data['module_bay'] = ModuleBay.objects.filter(device=device).first() form_data['module_type'] = module_type form_data['replicate_components'] = False form_data['adopt_components'] = True