From af126fe7e353c259f867956601b6eb2183e91bf6 Mon Sep 17 00:00:00 2001 From: kkthxbye-code Date: Tue, 10 May 2022 17:50:33 +0200 Subject: [PATCH 1/2] Added form validation to model installation Raises a ValidationError whenever installation would cause a foreign key violation. --- netbox/dcim/forms/models.py | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/netbox/dcim/forms/models.py b/netbox/dcim/forms/models.py index 1d3677cce..81c798c71 100644 --- a/netbox/dcim/forms/models.py +++ b/netbox/dcim/forms/models.py @@ -675,6 +675,56 @@ class ModuleForm(NetBoxModelForm): return super().save(*args, **kwargs) + def clean(self): + super().clean() + + replicate_components = self.cleaned_data.get("replicate_components") + adopt_components = self.cleaned_data.get("adopt_components") + device = self.cleaned_data['device'] + module_type = self.cleaned_data['module_type'] + module_bay = self.cleaned_data['module_bay'] + + # Bail out if we are not installing a new module or if we are not replicating components + if self.instance.pk or not replicate_components: + return + + for templates, component_attribute in [ + ("consoleporttemplates", "consoleports"), + ("consoleserverporttemplates", "consoleserverports"), + ("interfacetemplates", "interfaces"), + ("powerporttemplates", "powerports"), + ("poweroutlettemplates", "poweroutlets"), + ("rearporttemplates", "rearports"), + ("frontporttemplates", "frontports") + ]: + # Prefetch installed components + installed_components = { + component.name: component for component in getattr(device, component_attribute).all() + } + + # Get the templates for the module type. + for template in getattr(module_type, templates).all(): + # Installing modules with placeholders require that the bay has a position value + if '{module}' in template.name and not module_bay.position: + raise forms.ValidationError( + "Cannot install module with placeholder values in a module bay with no position defined" + ) + + resolved_name = template.name.replace('{module}', module_bay.position) + existing_item = installed_components.get(resolved_name) + + # It is not possible to adopt components already belonging to a module + if adopt_components and existing_item and existing_item.module: + raise forms.ValidationError( + f"Cannot adopt {template.component_model.__name__} '{resolved_name}' as it already belongs to a module" + ) + + # If we are not adopting components we error if the component exists + if not adopt_components and resolved_name in installed_components: + raise forms.ValidationError( + f"{template.component_model.__name__} - {resolved_name} already exists" + ) + class CableForm(TenancyForm, NetBoxModelForm): From d858eceb387f65ec96d297def940205cddee7bf3 Mon Sep 17 00:00:00 2001 From: kkthxbye-code Date: Tue, 10 May 2022 17:53:01 +0200 Subject: [PATCH 2/2] Fix pep8 --- netbox/dcim/forms/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/dcim/forms/models.py b/netbox/dcim/forms/models.py index 81c798c71..cd0be3096 100644 --- a/netbox/dcim/forms/models.py +++ b/netbox/dcim/forms/models.py @@ -718,7 +718,7 @@ class ModuleForm(NetBoxModelForm): raise forms.ValidationError( f"Cannot adopt {template.component_model.__name__} '{resolved_name}' as it already belongs to a module" ) - + # If we are not adopting components we error if the component exists if not adopt_components and resolved_name in installed_components: raise forms.ValidationError(