bulk_edit.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. from django import forms
  2. from django.utils.translation import gettext as _
  3. from dcim.choices import InterfaceModeChoices
  4. from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
  5. from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup
  6. from ipam.models import VLAN, VLANGroup, VRF
  7. from netbox.forms import NetBoxModelBulkEditForm
  8. from tenancy.models import Tenant
  9. from utilities.forms import (
  10. add_blank_choice, BulkEditNullBooleanSelect, BulkRenameForm, CommentField, DynamicModelChoiceField,
  11. DynamicModelMultipleChoiceField
  12. )
  13. from virtualization.choices import *
  14. from virtualization.models import *
  15. __all__ = (
  16. 'ClusterBulkEditForm',
  17. 'ClusterGroupBulkEditForm',
  18. 'ClusterTypeBulkEditForm',
  19. 'VirtualMachineBulkEditForm',
  20. 'VMInterfaceBulkEditForm',
  21. 'VMInterfaceBulkRenameForm',
  22. )
  23. class ClusterTypeBulkEditForm(NetBoxModelBulkEditForm):
  24. description = forms.CharField(
  25. max_length=200,
  26. required=False
  27. )
  28. model = ClusterType
  29. fieldsets = (
  30. (None, ('description',)),
  31. )
  32. nullable_fields = ('description',)
  33. class ClusterGroupBulkEditForm(NetBoxModelBulkEditForm):
  34. description = forms.CharField(
  35. max_length=200,
  36. required=False
  37. )
  38. model = ClusterGroup
  39. fieldsets = (
  40. (None, ('description',)),
  41. )
  42. nullable_fields = ('description',)
  43. class ClusterBulkEditForm(NetBoxModelBulkEditForm):
  44. type = DynamicModelChoiceField(
  45. queryset=ClusterType.objects.all(),
  46. required=False
  47. )
  48. group = DynamicModelChoiceField(
  49. queryset=ClusterGroup.objects.all(),
  50. required=False
  51. )
  52. status = forms.ChoiceField(
  53. choices=add_blank_choice(ClusterStatusChoices),
  54. required=False,
  55. initial=''
  56. )
  57. tenant = DynamicModelChoiceField(
  58. queryset=Tenant.objects.all(),
  59. required=False
  60. )
  61. region = DynamicModelChoiceField(
  62. queryset=Region.objects.all(),
  63. required=False,
  64. )
  65. site_group = DynamicModelChoiceField(
  66. queryset=SiteGroup.objects.all(),
  67. required=False,
  68. )
  69. site = DynamicModelChoiceField(
  70. queryset=Site.objects.all(),
  71. required=False,
  72. query_params={
  73. 'region_id': '$region',
  74. 'group_id': '$site_group',
  75. }
  76. )
  77. description = forms.CharField(
  78. max_length=200,
  79. required=False
  80. )
  81. comments = CommentField(
  82. widget=forms.Textarea,
  83. label=_('Comments')
  84. )
  85. model = Cluster
  86. fieldsets = (
  87. (None, ('type', 'group', 'status', 'tenant', 'description')),
  88. ('Site', ('region', 'site_group', 'site')),
  89. )
  90. nullable_fields = (
  91. 'group', 'site', 'tenant', 'description', 'comments',
  92. )
  93. class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm):
  94. status = forms.ChoiceField(
  95. choices=add_blank_choice(VirtualMachineStatusChoices),
  96. required=False,
  97. initial='',
  98. )
  99. site = DynamicModelChoiceField(
  100. queryset=Site.objects.all(),
  101. required=False
  102. )
  103. cluster = DynamicModelChoiceField(
  104. queryset=Cluster.objects.all(),
  105. required=False,
  106. query_params={
  107. 'site_id': '$site'
  108. }
  109. )
  110. device = DynamicModelChoiceField(
  111. queryset=Device.objects.all(),
  112. required=False,
  113. query_params={
  114. 'cluster_id': '$cluster'
  115. }
  116. )
  117. role = DynamicModelChoiceField(
  118. queryset=DeviceRole.objects.filter(
  119. vm_role=True
  120. ),
  121. required=False,
  122. query_params={
  123. "vm_role": "True"
  124. }
  125. )
  126. tenant = DynamicModelChoiceField(
  127. queryset=Tenant.objects.all(),
  128. required=False
  129. )
  130. platform = DynamicModelChoiceField(
  131. queryset=Platform.objects.all(),
  132. required=False
  133. )
  134. vcpus = forms.IntegerField(
  135. required=False,
  136. label=_('vCPUs')
  137. )
  138. memory = forms.IntegerField(
  139. required=False,
  140. label=_('Memory (MB)')
  141. )
  142. disk = forms.IntegerField(
  143. required=False,
  144. label=_('Disk (GB)')
  145. )
  146. description = forms.CharField(
  147. max_length=200,
  148. required=False
  149. )
  150. comments = CommentField(
  151. widget=forms.Textarea,
  152. label=_('Comments')
  153. )
  154. model = VirtualMachine
  155. fieldsets = (
  156. (None, ('site', 'cluster', 'device', 'status', 'role', 'tenant', 'platform', 'description')),
  157. ('Resources', ('vcpus', 'memory', 'disk'))
  158. )
  159. nullable_fields = (
  160. 'site', 'cluster', 'device', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'description', 'comments',
  161. )
  162. class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm):
  163. virtual_machine = forms.ModelChoiceField(
  164. queryset=VirtualMachine.objects.all(),
  165. required=False,
  166. disabled=True,
  167. widget=forms.HiddenInput()
  168. )
  169. parent = DynamicModelChoiceField(
  170. queryset=VMInterface.objects.all(),
  171. required=False
  172. )
  173. bridge = DynamicModelChoiceField(
  174. queryset=VMInterface.objects.all(),
  175. required=False
  176. )
  177. enabled = forms.NullBooleanField(
  178. required=False,
  179. widget=BulkEditNullBooleanSelect()
  180. )
  181. mtu = forms.IntegerField(
  182. required=False,
  183. min_value=INTERFACE_MTU_MIN,
  184. max_value=INTERFACE_MTU_MAX,
  185. label=_('MTU')
  186. )
  187. description = forms.CharField(
  188. max_length=100,
  189. required=False
  190. )
  191. mode = forms.ChoiceField(
  192. choices=add_blank_choice(InterfaceModeChoices),
  193. required=False
  194. )
  195. vlan_group = DynamicModelChoiceField(
  196. queryset=VLANGroup.objects.all(),
  197. required=False,
  198. label=_('VLAN group')
  199. )
  200. untagged_vlan = DynamicModelChoiceField(
  201. queryset=VLAN.objects.all(),
  202. required=False,
  203. query_params={
  204. 'group_id': '$vlan_group',
  205. },
  206. label=_('Untagged VLAN')
  207. )
  208. tagged_vlans = DynamicModelMultipleChoiceField(
  209. queryset=VLAN.objects.all(),
  210. required=False,
  211. query_params={
  212. 'group_id': '$vlan_group',
  213. },
  214. label=_('Tagged VLANs')
  215. )
  216. vrf = DynamicModelChoiceField(
  217. queryset=VRF.objects.all(),
  218. required=False,
  219. label=_('VRF')
  220. )
  221. model = VMInterface
  222. fieldsets = (
  223. (None, ('mtu', 'enabled', 'vrf', 'description')),
  224. ('Related Interfaces', ('parent', 'bridge')),
  225. ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')),
  226. )
  227. nullable_fields = (
  228. 'parent', 'bridge', 'mtu', 'vrf', 'description',
  229. )
  230. def __init__(self, *args, **kwargs):
  231. super().__init__(*args, **kwargs)
  232. if 'virtual_machine' in self.initial:
  233. vm_id = self.initial.get('virtual_machine')
  234. # Restrict parent/bridge interface assignment by VM
  235. self.fields['parent'].widget.add_query_param('virtual_machine_id', vm_id)
  236. self.fields['bridge'].widget.add_query_param('virtual_machine_id', vm_id)
  237. # Limit VLAN choices by virtual machine
  238. self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id)
  239. self.fields['tagged_vlans'].widget.add_query_param('available_on_virtualmachine', vm_id)
  240. else:
  241. # See 5643
  242. if 'pk' in self.initial:
  243. site = None
  244. interfaces = VMInterface.objects.filter(
  245. pk__in=self.initial['pk']
  246. ).prefetch_related(
  247. 'virtual_machine__site'
  248. )
  249. # Check interface sites. First interface should set site, further interfaces will either continue the
  250. # loop or reset back to no site and break the loop.
  251. for interface in interfaces:
  252. if site is None:
  253. site = interface.virtual_machine.cluster.site
  254. elif interface.virtual_machine.cluster.site is not site:
  255. site = None
  256. break
  257. if site is not None:
  258. self.fields['untagged_vlan'].widget.add_query_param('site_id', site.pk)
  259. self.fields['tagged_vlans'].widget.add_query_param('site_id', site.pk)
  260. self.fields['parent'].choices = ()
  261. self.fields['parent'].widget.attrs['disabled'] = True
  262. self.fields['bridge'].choices = ()
  263. self.fields['bridge'].widget.attrs['disabled'] = True
  264. class VMInterfaceBulkRenameForm(BulkRenameForm):
  265. pk = forms.ModelMultipleChoiceField(
  266. queryset=VMInterface.objects.all(),
  267. widget=forms.MultipleHiddenInput()
  268. )