views.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. from django.contrib import messages
  2. from django.db import transaction
  3. from django.db.models import Prefetch, Sum
  4. from django.http import HttpResponse
  5. from django.shortcuts import get_object_or_404, redirect, render
  6. from django.urls import reverse
  7. from django.utils.translation import gettext_lazy as _
  8. from jinja2.exceptions import TemplateError
  9. from dcim.filtersets import DeviceFilterSet
  10. from dcim.forms import DeviceFilterForm
  11. from dcim.models import Device
  12. from dcim.tables import DeviceTable
  13. from extras.views import ObjectConfigContextView
  14. from ipam.models import IPAddress
  15. from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
  16. from netbox.constants import DEFAULT_ACTION_PERMISSIONS
  17. from netbox.views import generic
  18. from tenancy.views import ObjectContactsView
  19. from utilities.query import count_related
  20. from utilities.query_functions import CollateAsChar
  21. from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
  22. from . import filtersets, forms, tables
  23. from .models import *
  24. #
  25. # Cluster types
  26. #
  27. @register_model_view(ClusterType, 'list', path='', detail=False)
  28. class ClusterTypeListView(generic.ObjectListView):
  29. queryset = ClusterType.objects.annotate(
  30. cluster_count=count_related(Cluster, 'type')
  31. )
  32. filterset = filtersets.ClusterTypeFilterSet
  33. filterset_form = forms.ClusterTypeFilterForm
  34. table = tables.ClusterTypeTable
  35. @register_model_view(ClusterType)
  36. class ClusterTypeView(GetRelatedModelsMixin, generic.ObjectView):
  37. queryset = ClusterType.objects.all()
  38. def get_extra_context(self, request, instance):
  39. return {
  40. 'related_models': self.get_related_models(request, instance),
  41. }
  42. @register_model_view(ClusterType, 'add', detail=False)
  43. @register_model_view(ClusterType, 'edit')
  44. class ClusterTypeEditView(generic.ObjectEditView):
  45. queryset = ClusterType.objects.all()
  46. form = forms.ClusterTypeForm
  47. @register_model_view(ClusterType, 'delete')
  48. class ClusterTypeDeleteView(generic.ObjectDeleteView):
  49. queryset = ClusterType.objects.all()
  50. @register_model_view(ClusterType, 'bulk_import', detail=False)
  51. class ClusterTypeBulkImportView(generic.BulkImportView):
  52. queryset = ClusterType.objects.all()
  53. model_form = forms.ClusterTypeImportForm
  54. @register_model_view(ClusterType, 'bulk_edit', path='edit', detail=False)
  55. class ClusterTypeBulkEditView(generic.BulkEditView):
  56. queryset = ClusterType.objects.annotate(
  57. cluster_count=count_related(Cluster, 'type')
  58. )
  59. filterset = filtersets.ClusterTypeFilterSet
  60. table = tables.ClusterTypeTable
  61. form = forms.ClusterTypeBulkEditForm
  62. @register_model_view(ClusterType, 'bulk_delete', path='delete', detail=False)
  63. class ClusterTypeBulkDeleteView(generic.BulkDeleteView):
  64. queryset = ClusterType.objects.annotate(
  65. cluster_count=count_related(Cluster, 'type')
  66. )
  67. filterset = filtersets.ClusterTypeFilterSet
  68. table = tables.ClusterTypeTable
  69. #
  70. # Cluster groups
  71. #
  72. @register_model_view(ClusterGroup, 'list', path='', detail=False)
  73. class ClusterGroupListView(generic.ObjectListView):
  74. queryset = ClusterGroup.objects.annotate(
  75. cluster_count=count_related(Cluster, 'group')
  76. )
  77. filterset = filtersets.ClusterGroupFilterSet
  78. filterset_form = forms.ClusterGroupFilterForm
  79. table = tables.ClusterGroupTable
  80. @register_model_view(ClusterGroup)
  81. class ClusterGroupView(GetRelatedModelsMixin, generic.ObjectView):
  82. queryset = ClusterGroup.objects.all()
  83. def get_extra_context(self, request, instance):
  84. return {
  85. 'related_models': self.get_related_models(request, instance),
  86. }
  87. @register_model_view(ClusterGroup, 'add', detail=False)
  88. @register_model_view(ClusterGroup, 'edit')
  89. class ClusterGroupEditView(generic.ObjectEditView):
  90. queryset = ClusterGroup.objects.all()
  91. form = forms.ClusterGroupForm
  92. @register_model_view(ClusterGroup, 'delete')
  93. class ClusterGroupDeleteView(generic.ObjectDeleteView):
  94. queryset = ClusterGroup.objects.all()
  95. @register_model_view(ClusterGroup, 'bulk_import', detail=False)
  96. class ClusterGroupBulkImportView(generic.BulkImportView):
  97. queryset = ClusterGroup.objects.annotate(
  98. cluster_count=count_related(Cluster, 'group')
  99. )
  100. model_form = forms.ClusterGroupImportForm
  101. @register_model_view(ClusterGroup, 'bulk_edit', path='edit', detail=False)
  102. class ClusterGroupBulkEditView(generic.BulkEditView):
  103. queryset = ClusterGroup.objects.annotate(
  104. cluster_count=count_related(Cluster, 'group')
  105. )
  106. filterset = filtersets.ClusterGroupFilterSet
  107. table = tables.ClusterGroupTable
  108. form = forms.ClusterGroupBulkEditForm
  109. @register_model_view(ClusterGroup, 'bulk_delete', path='delete', detail=False)
  110. class ClusterGroupBulkDeleteView(generic.BulkDeleteView):
  111. queryset = ClusterGroup.objects.annotate(
  112. cluster_count=count_related(Cluster, 'group')
  113. )
  114. filterset = filtersets.ClusterGroupFilterSet
  115. table = tables.ClusterGroupTable
  116. @register_model_view(ClusterGroup, 'contacts')
  117. class ClusterGroupContactsView(ObjectContactsView):
  118. queryset = ClusterGroup.objects.all()
  119. #
  120. # Clusters
  121. #
  122. @register_model_view(Cluster, 'list', path='', detail=False)
  123. class ClusterListView(generic.ObjectListView):
  124. permission_required = 'virtualization.view_cluster'
  125. queryset = Cluster.objects.annotate(
  126. device_count=count_related(Device, 'cluster'),
  127. vm_count=count_related(VirtualMachine, 'cluster')
  128. )
  129. table = tables.ClusterTable
  130. filterset = filtersets.ClusterFilterSet
  131. filterset_form = forms.ClusterFilterForm
  132. @register_model_view(Cluster)
  133. class ClusterView(generic.ObjectView):
  134. queryset = Cluster.objects.all()
  135. def get_extra_context(self, request, instance):
  136. return instance.virtual_machines.aggregate(
  137. vcpus_sum=Sum('vcpus'),
  138. memory_sum=Sum('memory'),
  139. disk_sum=Sum('disk')
  140. )
  141. @register_model_view(Cluster, 'virtualmachines', path='virtual-machines')
  142. class ClusterVirtualMachinesView(generic.ObjectChildrenView):
  143. queryset = Cluster.objects.all()
  144. child_model = VirtualMachine
  145. table = tables.VirtualMachineTable
  146. filterset = filtersets.VirtualMachineFilterSet
  147. filterset_form = forms.VirtualMachineFilterForm
  148. tab = ViewTab(
  149. label=_('Virtual Machines'),
  150. badge=lambda obj: obj.virtual_machines.count(),
  151. permission='virtualization.view_virtualmachine',
  152. weight=500
  153. )
  154. def get_children(self, request, parent):
  155. return VirtualMachine.objects.restrict(request.user, 'view').filter(cluster=parent)
  156. @register_model_view(Cluster, 'devices')
  157. class ClusterDevicesView(generic.ObjectChildrenView):
  158. queryset = Cluster.objects.all()
  159. child_model = Device
  160. table = DeviceTable
  161. filterset = DeviceFilterSet
  162. filterset_form = DeviceFilterForm
  163. template_name = 'virtualization/cluster/devices.html'
  164. actions = {
  165. 'add': {'add'},
  166. 'export': {'view'},
  167. 'bulk_import': {'add'},
  168. 'bulk_edit': {'change'},
  169. 'bulk_remove_devices': {'change'},
  170. }
  171. tab = ViewTab(
  172. label=_('Devices'),
  173. badge=lambda obj: obj.devices.count(),
  174. permission='virtualization.view_virtualmachine',
  175. weight=600
  176. )
  177. def get_children(self, request, parent):
  178. return Device.objects.restrict(request.user, 'view').filter(cluster=parent)
  179. @register_model_view(Cluster, 'add', detail=False)
  180. @register_model_view(Cluster, 'edit')
  181. class ClusterEditView(generic.ObjectEditView):
  182. queryset = Cluster.objects.all()
  183. form = forms.ClusterForm
  184. @register_model_view(Cluster, 'delete')
  185. class ClusterDeleteView(generic.ObjectDeleteView):
  186. queryset = Cluster.objects.all()
  187. @register_model_view(Cluster, 'bulk_import', detail=False)
  188. class ClusterBulkImportView(generic.BulkImportView):
  189. queryset = Cluster.objects.all()
  190. model_form = forms.ClusterImportForm
  191. @register_model_view(Cluster, 'bulk_edit', path='edit', detail=False)
  192. class ClusterBulkEditView(generic.BulkEditView):
  193. queryset = Cluster.objects.all()
  194. filterset = filtersets.ClusterFilterSet
  195. table = tables.ClusterTable
  196. form = forms.ClusterBulkEditForm
  197. @register_model_view(Cluster, 'bulk_delete', path='delete', detail=False)
  198. class ClusterBulkDeleteView(generic.BulkDeleteView):
  199. queryset = Cluster.objects.all()
  200. filterset = filtersets.ClusterFilterSet
  201. table = tables.ClusterTable
  202. @register_model_view(Cluster, 'add_devices', path='devices/add')
  203. class ClusterAddDevicesView(generic.ObjectEditView):
  204. queryset = Cluster.objects.all()
  205. form = forms.ClusterAddDevicesForm
  206. template_name = 'virtualization/cluster_add_devices.html'
  207. def get(self, request, pk):
  208. cluster = get_object_or_404(self.queryset, pk=pk)
  209. form = self.form(cluster, initial=request.GET)
  210. return render(request, self.template_name, {
  211. 'cluster': cluster,
  212. 'form': form,
  213. 'return_url': reverse('virtualization:cluster', kwargs={'pk': pk}),
  214. })
  215. def post(self, request, pk):
  216. cluster = get_object_or_404(self.queryset, pk=pk)
  217. form = self.form(cluster, request.POST)
  218. if form.is_valid():
  219. device_pks = form.cleaned_data['devices']
  220. with transaction.atomic():
  221. # Assign the selected Devices to the Cluster
  222. for device in Device.objects.filter(pk__in=device_pks):
  223. device.cluster = cluster
  224. device.save()
  225. messages.success(request, _("Added {count} devices to cluster {cluster}").format(
  226. count=len(device_pks),
  227. cluster=cluster
  228. ))
  229. return redirect(cluster.get_absolute_url())
  230. return render(request, self.template_name, {
  231. 'cluster': cluster,
  232. 'form': form,
  233. 'return_url': cluster.get_absolute_url(),
  234. })
  235. @register_model_view(Cluster, 'remove_devices', path='devices/remove')
  236. class ClusterRemoveDevicesView(generic.ObjectEditView):
  237. queryset = Cluster.objects.all()
  238. form = forms.ClusterRemoveDevicesForm
  239. template_name = 'generic/bulk_remove.html'
  240. def post(self, request, pk):
  241. cluster = get_object_or_404(self.queryset, pk=pk)
  242. if '_confirm' in request.POST:
  243. form = self.form(request.POST)
  244. if form.is_valid():
  245. device_pks = form.cleaned_data['pk']
  246. with transaction.atomic():
  247. # Remove the selected Devices from the Cluster
  248. for device in Device.objects.filter(pk__in=device_pks):
  249. device.cluster = None
  250. device.save()
  251. messages.success(request, _("Removed {count} devices from cluster {cluster}").format(
  252. count=len(device_pks),
  253. cluster=cluster
  254. ))
  255. return redirect(cluster.get_absolute_url())
  256. else:
  257. form = self.form(initial={'pk': request.POST.getlist('pk')})
  258. selected_objects = Device.objects.filter(pk__in=form.initial['pk'])
  259. device_table = DeviceTable(list(selected_objects), orderable=False)
  260. return render(request, self.template_name, {
  261. 'form': form,
  262. 'parent_obj': cluster,
  263. 'table': device_table,
  264. 'obj_type_plural': 'devices',
  265. 'return_url': cluster.get_absolute_url(),
  266. })
  267. @register_model_view(Cluster, 'contacts')
  268. class ClusterContactsView(ObjectContactsView):
  269. queryset = Cluster.objects.all()
  270. #
  271. # Virtual machines
  272. #
  273. @register_model_view(VirtualMachine, 'list', path='', detail=False)
  274. class VirtualMachineListView(generic.ObjectListView):
  275. queryset = VirtualMachine.objects.prefetch_related('primary_ip4', 'primary_ip6')
  276. filterset = filtersets.VirtualMachineFilterSet
  277. filterset_form = forms.VirtualMachineFilterForm
  278. table = tables.VirtualMachineTable
  279. template_name = 'virtualization/virtualmachine_list.html'
  280. @register_model_view(VirtualMachine)
  281. class VirtualMachineView(generic.ObjectView):
  282. queryset = VirtualMachine.objects.all()
  283. @register_model_view(VirtualMachine, 'interfaces')
  284. class VirtualMachineInterfacesView(generic.ObjectChildrenView):
  285. queryset = VirtualMachine.objects.all()
  286. child_model = VMInterface
  287. table = tables.VirtualMachineVMInterfaceTable
  288. filterset = filtersets.VMInterfaceFilterSet
  289. filterset_form = forms.VMInterfaceFilterForm
  290. template_name = 'virtualization/virtualmachine/interfaces.html'
  291. actions = {
  292. **DEFAULT_ACTION_PERMISSIONS,
  293. 'bulk_rename': {'change'},
  294. }
  295. tab = ViewTab(
  296. label=_('Interfaces'),
  297. badge=lambda obj: obj.interface_count,
  298. permission='virtualization.view_vminterface',
  299. weight=500
  300. )
  301. def get_children(self, request, parent):
  302. return parent.interfaces.restrict(request.user, 'view').prefetch_related(
  303. Prefetch('ip_addresses', queryset=IPAddress.objects.restrict(request.user)),
  304. 'tags',
  305. )
  306. @register_model_view(VirtualMachine, 'disks')
  307. class VirtualMachineVirtualDisksView(generic.ObjectChildrenView):
  308. queryset = VirtualMachine.objects.all()
  309. child_model = VirtualDisk
  310. table = tables.VirtualMachineVirtualDiskTable
  311. filterset = filtersets.VirtualDiskFilterSet
  312. filterset_form = forms.VirtualDiskFilterForm
  313. template_name = 'virtualization/virtualmachine/virtual_disks.html'
  314. tab = ViewTab(
  315. label=_('Virtual Disks'),
  316. badge=lambda obj: obj.virtual_disk_count,
  317. permission='virtualization.view_virtualdisk',
  318. weight=500
  319. )
  320. actions = {
  321. **DEFAULT_ACTION_PERMISSIONS,
  322. 'bulk_rename': {'change'},
  323. }
  324. def get_children(self, request, parent):
  325. return parent.virtualdisks.restrict(request.user, 'view').prefetch_related('tags')
  326. @register_model_view(VirtualMachine, 'configcontext', path='config-context')
  327. class VirtualMachineConfigContextView(ObjectConfigContextView):
  328. queryset = VirtualMachine.objects.annotate_config_context_data()
  329. base_template = 'virtualization/virtualmachine.html'
  330. tab = ViewTab(
  331. label=_('Config Context'),
  332. weight=2000
  333. )
  334. @register_model_view(VirtualMachine, 'render-config')
  335. class VirtualMachineRenderConfigView(generic.ObjectView):
  336. queryset = VirtualMachine.objects.all()
  337. template_name = 'virtualization/virtualmachine/render_config.html'
  338. tab = ViewTab(
  339. label=_('Render Config'),
  340. weight=2100
  341. )
  342. def get(self, request, **kwargs):
  343. instance = self.get_object(**kwargs)
  344. context = self.get_extra_context(request, instance)
  345. # If a direct export has been requested, return the rendered template content as a
  346. # downloadable file.
  347. if request.GET.get('export'):
  348. content = context['rendered_config'] or context['error_message']
  349. response = HttpResponse(content, content_type='text')
  350. filename = f"{instance.name or 'config'}.txt"
  351. response['Content-Disposition'] = f'attachment; filename="{filename}"'
  352. return response
  353. return render(request, self.get_template_name(), {
  354. 'object': instance,
  355. 'tab': self.tab,
  356. **context,
  357. })
  358. def get_extra_context(self, request, instance):
  359. # Compile context data
  360. context_data = instance.get_config_context()
  361. context_data.update({'virtualmachine': instance})
  362. # Render the config template
  363. rendered_config = None
  364. error_message = None
  365. if config_template := instance.get_config_template():
  366. try:
  367. rendered_config = config_template.render(context=context_data)
  368. except TemplateError as e:
  369. error_message = _("An error occurred while rendering the template: {error}").format(error=e)
  370. return {
  371. 'config_template': config_template,
  372. 'context_data': context_data,
  373. 'rendered_config': rendered_config,
  374. 'error_message': error_message,
  375. }
  376. @register_model_view(VirtualMachine, 'add', detail=False)
  377. @register_model_view(VirtualMachine, 'edit')
  378. class VirtualMachineEditView(generic.ObjectEditView):
  379. queryset = VirtualMachine.objects.all()
  380. form = forms.VirtualMachineForm
  381. @register_model_view(VirtualMachine, 'delete')
  382. class VirtualMachineDeleteView(generic.ObjectDeleteView):
  383. queryset = VirtualMachine.objects.all()
  384. @register_model_view(VirtualMachine, 'bulk_import', detail=False)
  385. class VirtualMachineBulkImportView(generic.BulkImportView):
  386. queryset = VirtualMachine.objects.all()
  387. model_form = forms.VirtualMachineImportForm
  388. @register_model_view(VirtualMachine, 'bulk_edit', path='edit', detail=False)
  389. class VirtualMachineBulkEditView(generic.BulkEditView):
  390. queryset = VirtualMachine.objects.prefetch_related('primary_ip4', 'primary_ip6')
  391. filterset = filtersets.VirtualMachineFilterSet
  392. table = tables.VirtualMachineTable
  393. form = forms.VirtualMachineBulkEditForm
  394. @register_model_view(VirtualMachine, 'bulk_delete', path='delete', detail=False)
  395. class VirtualMachineBulkDeleteView(generic.BulkDeleteView):
  396. queryset = VirtualMachine.objects.prefetch_related('primary_ip4', 'primary_ip6')
  397. filterset = filtersets.VirtualMachineFilterSet
  398. table = tables.VirtualMachineTable
  399. @register_model_view(VirtualMachine, 'contacts')
  400. class VirtualMachineContactsView(ObjectContactsView):
  401. queryset = VirtualMachine.objects.all()
  402. #
  403. # VM interfaces
  404. #
  405. @register_model_view(VMInterface, 'list', path='', detail=False)
  406. class VMInterfaceListView(generic.ObjectListView):
  407. queryset = VMInterface.objects.all()
  408. filterset = filtersets.VMInterfaceFilterSet
  409. filterset_form = forms.VMInterfaceFilterForm
  410. table = tables.VMInterfaceTable
  411. @register_model_view(VMInterface)
  412. class VMInterfaceView(generic.ObjectView):
  413. queryset = VMInterface.objects.all()
  414. def get_extra_context(self, request, instance):
  415. # Get child interfaces
  416. child_interfaces = VMInterface.objects.restrict(request.user, 'view').filter(parent=instance)
  417. child_interfaces_tables = tables.VMInterfaceTable(
  418. child_interfaces,
  419. exclude=('virtual_machine',),
  420. orderable=False
  421. )
  422. # Get VLAN translation rules
  423. vlan_translation_table = None
  424. if instance.vlan_translation_policy:
  425. vlan_translation_table = VLANTranslationRuleTable(
  426. data=instance.vlan_translation_policy.rules.all(),
  427. orderable=False
  428. )
  429. # Get assigned VLANs and annotate whether each is tagged or untagged
  430. vlans = []
  431. if instance.untagged_vlan is not None:
  432. vlans.append(instance.untagged_vlan)
  433. vlans[0].tagged = False
  434. for vlan in instance.tagged_vlans.restrict(request.user).prefetch_related('site', 'group', 'tenant', 'role'):
  435. vlan.tagged = True
  436. vlans.append(vlan)
  437. vlan_table = InterfaceVLANTable(
  438. interface=instance,
  439. data=vlans,
  440. orderable=False
  441. )
  442. return {
  443. 'child_interfaces_table': child_interfaces_tables,
  444. 'vlan_table': vlan_table,
  445. 'vlan_translation_table': vlan_translation_table,
  446. }
  447. @register_model_view(VMInterface, 'add', detail=False)
  448. class VMInterfaceCreateView(generic.ComponentCreateView):
  449. queryset = VMInterface.objects.all()
  450. form = forms.VMInterfaceCreateForm
  451. model_form = forms.VMInterfaceForm
  452. @register_model_view(VMInterface, 'edit')
  453. class VMInterfaceEditView(generic.ObjectEditView):
  454. queryset = VMInterface.objects.all()
  455. form = forms.VMInterfaceForm
  456. @register_model_view(VMInterface, 'delete')
  457. class VMInterfaceDeleteView(generic.ObjectDeleteView):
  458. queryset = VMInterface.objects.all()
  459. @register_model_view(VMInterface, 'bulk_import', detail=False)
  460. class VMInterfaceBulkImportView(generic.BulkImportView):
  461. queryset = VMInterface.objects.all()
  462. model_form = forms.VMInterfaceImportForm
  463. @register_model_view(VMInterface, 'bulk_edit', path='edit', detail=False)
  464. class VMInterfaceBulkEditView(generic.BulkEditView):
  465. queryset = VMInterface.objects.all()
  466. filterset = filtersets.VMInterfaceFilterSet
  467. table = tables.VMInterfaceTable
  468. form = forms.VMInterfaceBulkEditForm
  469. @register_model_view(VMInterface, 'bulk_rename', path='rename', detail=False)
  470. class VMInterfaceBulkRenameView(generic.BulkRenameView):
  471. queryset = VMInterface.objects.all()
  472. form = forms.VMInterfaceBulkRenameForm
  473. @register_model_view(VMInterface, 'bulk_delete', path='delete', detail=False)
  474. class VMInterfaceBulkDeleteView(generic.BulkDeleteView):
  475. # Ensure child interfaces are deleted prior to their parents
  476. queryset = VMInterface.objects.order_by('virtual_machine', 'parent', CollateAsChar('_name'))
  477. filterset = filtersets.VMInterfaceFilterSet
  478. table = tables.VMInterfaceTable
  479. #
  480. # Virtual disks
  481. #
  482. @register_model_view(VirtualDisk, 'list', path='', detail=False)
  483. class VirtualDiskListView(generic.ObjectListView):
  484. queryset = VirtualDisk.objects.all()
  485. filterset = filtersets.VirtualDiskFilterSet
  486. filterset_form = forms.VirtualDiskFilterForm
  487. table = tables.VirtualDiskTable
  488. @register_model_view(VirtualDisk)
  489. class VirtualDiskView(generic.ObjectView):
  490. queryset = VirtualDisk.objects.all()
  491. @register_model_view(VirtualDisk, 'add', detail=False)
  492. class VirtualDiskCreateView(generic.ComponentCreateView):
  493. queryset = VirtualDisk.objects.all()
  494. form = forms.VirtualDiskCreateForm
  495. model_form = forms.VirtualDiskForm
  496. @register_model_view(VirtualDisk, 'edit')
  497. class VirtualDiskEditView(generic.ObjectEditView):
  498. queryset = VirtualDisk.objects.all()
  499. form = forms.VirtualDiskForm
  500. @register_model_view(VirtualDisk, 'delete')
  501. class VirtualDiskDeleteView(generic.ObjectDeleteView):
  502. queryset = VirtualDisk.objects.all()
  503. @register_model_view(VirtualDisk, 'bulk_import', detail=False)
  504. class VirtualDiskBulkImportView(generic.BulkImportView):
  505. queryset = VirtualDisk.objects.all()
  506. model_form = forms.VirtualDiskImportForm
  507. @register_model_view(VirtualDisk, 'bulk_edit', path='edit', detail=False)
  508. class VirtualDiskBulkEditView(generic.BulkEditView):
  509. queryset = VirtualDisk.objects.all()
  510. filterset = filtersets.VirtualDiskFilterSet
  511. table = tables.VirtualDiskTable
  512. form = forms.VirtualDiskBulkEditForm
  513. @register_model_view(VirtualDisk, 'bulk_rename', path='rename', detail=False)
  514. class VirtualDiskBulkRenameView(generic.BulkRenameView):
  515. queryset = VirtualDisk.objects.all()
  516. form = forms.VirtualDiskBulkRenameForm
  517. @register_model_view(VirtualDisk, 'bulk_delete', path='delete', detail=False)
  518. class VirtualDiskBulkDeleteView(generic.BulkDeleteView):
  519. queryset = VirtualDisk.objects.all()
  520. filterset = filtersets.VirtualDiskFilterSet
  521. table = tables.VirtualDiskTable
  522. #
  523. # Bulk Device component creation
  524. #
  525. class VirtualMachineBulkAddInterfaceView(generic.BulkComponentCreateView):
  526. parent_model = VirtualMachine
  527. parent_field = 'virtual_machine'
  528. form = forms.VMInterfaceBulkCreateForm
  529. queryset = VMInterface.objects.all()
  530. model_form = forms.VMInterfaceForm
  531. filterset = filtersets.VirtualMachineFilterSet
  532. table = tables.VirtualMachineTable
  533. default_return_url = 'virtualization:virtualmachine_list'
  534. def get_required_permission(self):
  535. return 'virtualization.add_vminterface'
  536. class VirtualMachineBulkAddVirtualDiskView(generic.BulkComponentCreateView):
  537. parent_model = VirtualMachine
  538. parent_field = 'virtual_machine'
  539. form = forms.VirtualDiskBulkCreateForm
  540. queryset = VirtualDisk.objects.all()
  541. model_form = forms.VirtualDiskForm
  542. filterset = filtersets.VirtualMachineFilterSet
  543. table = tables.VirtualMachineTable
  544. default_return_url = 'virtualization:virtualmachine_list'
  545. def get_required_permission(self):
  546. return 'virtualization.add_virtualdisk'