|
@@ -675,6 +675,56 @@ class ModuleForm(NetBoxModelForm):
|
|
|
|
|
|
|
|
return super().save(*args, **kwargs)
|
|
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):
|
|
class CableForm(TenancyForm, NetBoxModelForm):
|
|
|
|
|
|