common.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. from django import forms
  2. from django.utils.translation import gettext as _
  3. from dcim.choices import *
  4. from dcim.constants import *
  5. from utilities.forms.utils import get_field_value
  6. __all__ = (
  7. 'InterfaceCommonForm',
  8. 'ModuleCommonForm'
  9. )
  10. class InterfaceCommonForm(forms.Form):
  11. mac_address = forms.CharField(
  12. empty_value=None,
  13. required=False,
  14. label=_('MAC address')
  15. )
  16. mtu = forms.IntegerField(
  17. required=False,
  18. min_value=INTERFACE_MTU_MIN,
  19. max_value=INTERFACE_MTU_MAX,
  20. label=_('MTU')
  21. )
  22. def __init__(self, *args, **kwargs):
  23. super().__init__(*args, **kwargs)
  24. # Determine the selected 802.1Q mode
  25. interface_mode = get_field_value(self, 'mode')
  26. # Delete VLAN tagging fields which are not relevant for the selected mode
  27. if interface_mode in (InterfaceModeChoices.MODE_ACCESS, InterfaceModeChoices.MODE_TAGGED_ALL):
  28. del self.fields['tagged_vlans']
  29. elif not interface_mode:
  30. del self.fields['vlan_group']
  31. del self.fields['untagged_vlan']
  32. del self.fields['tagged_vlans']
  33. def clean(self):
  34. super().clean()
  35. parent_field = 'device' if 'device' in self.cleaned_data else 'virtual_machine'
  36. tagged_vlans = self.cleaned_data.get('tagged_vlans')
  37. # Untagged interfaces cannot be assigned tagged VLANs
  38. if self.cleaned_data['mode'] == InterfaceModeChoices.MODE_ACCESS and tagged_vlans:
  39. raise forms.ValidationError({
  40. 'mode': "An access interface cannot have tagged VLANs assigned."
  41. })
  42. # Remove all tagged VLAN assignments from "tagged all" interfaces
  43. elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED_ALL:
  44. self.cleaned_data['tagged_vlans'] = []
  45. # Validate tagged VLANs; must be a global VLAN or in the same site
  46. elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED and tagged_vlans:
  47. valid_sites = [None, self.cleaned_data[parent_field].site]
  48. invalid_vlans = [str(v) for v in tagged_vlans if v.site not in valid_sites]
  49. if invalid_vlans:
  50. raise forms.ValidationError({
  51. 'tagged_vlans': f"The tagged VLANs ({', '.join(invalid_vlans)}) must belong to the same site as "
  52. f"the interface's parent device/VM, or they must be global"
  53. })
  54. class ModuleCommonForm(forms.Form):
  55. def clean(self):
  56. super().clean()
  57. replicate_components = self.cleaned_data.get('replicate_components')
  58. adopt_components = self.cleaned_data.get('adopt_components')
  59. device = self.cleaned_data.get('device')
  60. module_type = self.cleaned_data.get('module_type')
  61. module_bay = self.cleaned_data.get('module_bay')
  62. if adopt_components:
  63. self.instance._adopt_components = True
  64. # Bail out if we are not installing a new module or if we are not replicating components (or if
  65. # validation has already failed)
  66. if self.errors or self.instance.pk or not replicate_components:
  67. self.instance._disable_replication = True
  68. return
  69. for templates, component_attribute in [
  70. ("consoleporttemplates", "consoleports"),
  71. ("consoleserverporttemplates", "consoleserverports"),
  72. ("interfacetemplates", "interfaces"),
  73. ("powerporttemplates", "powerports"),
  74. ("poweroutlettemplates", "poweroutlets"),
  75. ("rearporttemplates", "rearports"),
  76. ("frontporttemplates", "frontports")
  77. ]:
  78. # Prefetch installed components
  79. installed_components = {
  80. component.name: component for component in getattr(device, component_attribute).all()
  81. }
  82. # Get the templates for the module type.
  83. for template in getattr(module_type, templates).all():
  84. # Installing modules with placeholders require that the bay has a position value
  85. if MODULE_TOKEN in template.name and not module_bay.position:
  86. raise forms.ValidationError(
  87. "Cannot install module with placeholder values in a module bay with no position defined"
  88. )
  89. resolved_name = template.name.replace(MODULE_TOKEN, module_bay.position)
  90. existing_item = installed_components.get(resolved_name)
  91. # It is not possible to adopt components already belonging to a module
  92. if adopt_components and existing_item and existing_item.module:
  93. raise forms.ValidationError(
  94. f"Cannot adopt {template.component_model.__name__} '{resolved_name}' as it already belongs "
  95. f"to a module"
  96. )
  97. # If we are not adopting components we error if the component exists
  98. if not adopt_components and resolved_name in installed_components:
  99. raise forms.ValidationError(
  100. f"{template.component_model.__name__} - {resolved_name} already exists"
  101. )