views.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. from django.contrib import messages
  2. from django.contrib.auth.mixins import PermissionRequiredMixin
  3. from django.db import transaction
  4. from django.db.models import Count
  5. from django.shortcuts import get_object_or_404, redirect, render
  6. from django.urls import reverse
  7. from django.views.generic import View
  8. from dcim.models import Device, Interface
  9. from dcim.tables import DeviceTable
  10. from extras.views import ObjectConfigContextView
  11. from ipam.models import Service
  12. from utilities.views import (
  13. BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, ObjectDeleteView,
  14. ObjectEditView, ObjectListView,
  15. )
  16. from . import filters, forms, tables
  17. from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
  18. #
  19. # Cluster types
  20. #
  21. class ClusterTypeListView(PermissionRequiredMixin, ObjectListView):
  22. permission_required = 'virtualization.view_clustertype'
  23. queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
  24. table = tables.ClusterTypeTable
  25. class ClusterTypeCreateView(PermissionRequiredMixin, ObjectEditView):
  26. permission_required = 'virtualization.add_clustertype'
  27. model = ClusterType
  28. model_form = forms.ClusterTypeForm
  29. default_return_url = 'virtualization:clustertype_list'
  30. class ClusterTypeEditView(ClusterTypeCreateView):
  31. permission_required = 'virtualization.change_clustertype'
  32. class ClusterTypeBulkImportView(PermissionRequiredMixin, BulkImportView):
  33. permission_required = 'virtualization.add_clustertype'
  34. model_form = forms.ClusterTypeCSVForm
  35. table = tables.ClusterTypeTable
  36. default_return_url = 'virtualization:clustertype_list'
  37. class ClusterTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  38. permission_required = 'virtualization.delete_clustertype'
  39. queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
  40. table = tables.ClusterTypeTable
  41. default_return_url = 'virtualization:clustertype_list'
  42. #
  43. # Cluster groups
  44. #
  45. class ClusterGroupListView(PermissionRequiredMixin, ObjectListView):
  46. permission_required = 'virtualization.view_clustergroup'
  47. queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
  48. table = tables.ClusterGroupTable
  49. class ClusterGroupCreateView(PermissionRequiredMixin, ObjectEditView):
  50. permission_required = 'virtualization.add_clustergroup'
  51. model = ClusterGroup
  52. model_form = forms.ClusterGroupForm
  53. default_return_url = 'virtualization:clustergroup_list'
  54. class ClusterGroupEditView(ClusterGroupCreateView):
  55. permission_required = 'virtualization.change_clustergroup'
  56. class ClusterGroupBulkImportView(PermissionRequiredMixin, BulkImportView):
  57. permission_required = 'virtualization.add_clustergroup'
  58. model_form = forms.ClusterGroupCSVForm
  59. table = tables.ClusterGroupTable
  60. default_return_url = 'virtualization:clustergroup_list'
  61. class ClusterGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  62. permission_required = 'virtualization.delete_clustergroup'
  63. queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
  64. table = tables.ClusterGroupTable
  65. default_return_url = 'virtualization:clustergroup_list'
  66. #
  67. # Clusters
  68. #
  69. class ClusterListView(PermissionRequiredMixin, ObjectListView):
  70. permission_required = 'virtualization.view_cluster'
  71. queryset = Cluster.objects.prefetch_related('type', 'group', 'site', 'tenant')
  72. table = tables.ClusterTable
  73. filterset = filters.ClusterFilterSet
  74. filterset_form = forms.ClusterFilterForm
  75. class ClusterView(PermissionRequiredMixin, View):
  76. permission_required = 'virtualization.view_cluster'
  77. def get(self, request, pk):
  78. cluster = get_object_or_404(Cluster, pk=pk)
  79. devices = Device.objects.filter(cluster=cluster).prefetch_related(
  80. 'site', 'rack', 'tenant', 'device_type__manufacturer'
  81. )
  82. device_table = DeviceTable(list(devices), orderable=False)
  83. if request.user.has_perm('virtualization.change_cluster'):
  84. device_table.columns.show('pk')
  85. return render(request, 'virtualization/cluster.html', {
  86. 'cluster': cluster,
  87. 'device_table': device_table,
  88. })
  89. class ClusterCreateView(PermissionRequiredMixin, ObjectEditView):
  90. permission_required = 'virtualization.add_cluster'
  91. template_name = 'virtualization/cluster_edit.html'
  92. model = Cluster
  93. model_form = forms.ClusterForm
  94. class ClusterEditView(ClusterCreateView):
  95. permission_required = 'virtualization.change_cluster'
  96. class ClusterDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  97. permission_required = 'virtualization.delete_cluster'
  98. model = Cluster
  99. default_return_url = 'virtualization:cluster_list'
  100. class ClusterBulkImportView(PermissionRequiredMixin, BulkImportView):
  101. permission_required = 'virtualization.add_cluster'
  102. model_form = forms.ClusterCSVForm
  103. table = tables.ClusterTable
  104. default_return_url = 'virtualization:cluster_list'
  105. class ClusterBulkEditView(PermissionRequiredMixin, BulkEditView):
  106. permission_required = 'virtualization.change_cluster'
  107. queryset = Cluster.objects.prefetch_related('type', 'group', 'site')
  108. filterset = filters.ClusterFilterSet
  109. table = tables.ClusterTable
  110. form = forms.ClusterBulkEditForm
  111. default_return_url = 'virtualization:cluster_list'
  112. class ClusterBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  113. permission_required = 'virtualization.delete_cluster'
  114. queryset = Cluster.objects.prefetch_related('type', 'group', 'site')
  115. filterset = filters.ClusterFilterSet
  116. table = tables.ClusterTable
  117. default_return_url = 'virtualization:cluster_list'
  118. class ClusterAddDevicesView(PermissionRequiredMixin, View):
  119. permission_required = 'virtualization.change_cluster'
  120. form = forms.ClusterAddDevicesForm
  121. template_name = 'virtualization/cluster_add_devices.html'
  122. def get(self, request, pk):
  123. cluster = get_object_or_404(Cluster, pk=pk)
  124. form = self.form(cluster)
  125. return render(request, self.template_name, {
  126. 'cluster': cluster,
  127. 'form': form,
  128. 'return_url': reverse('virtualization:cluster', kwargs={'pk': pk}),
  129. })
  130. def post(self, request, pk):
  131. cluster = get_object_or_404(Cluster, pk=pk)
  132. form = self.form(cluster, request.POST)
  133. if form.is_valid():
  134. device_pks = form.cleaned_data['devices']
  135. with transaction.atomic():
  136. # Assign the selected Devices to the Cluster
  137. for device in Device.objects.filter(pk__in=device_pks):
  138. device.cluster = cluster
  139. device.save()
  140. messages.success(request, "Added {} devices to cluster {}".format(
  141. len(device_pks), cluster
  142. ))
  143. return redirect(cluster.get_absolute_url())
  144. return render(request, self.template_name, {
  145. 'cluster': cluster,
  146. 'form': form,
  147. 'return_url': cluster.get_absolute_url(),
  148. })
  149. class ClusterRemoveDevicesView(PermissionRequiredMixin, View):
  150. permission_required = 'virtualization.change_cluster'
  151. form = forms.ClusterRemoveDevicesForm
  152. template_name = 'utilities/obj_bulk_remove.html'
  153. def post(self, request, pk):
  154. cluster = get_object_or_404(Cluster, pk=pk)
  155. if '_confirm' in request.POST:
  156. form = self.form(request.POST)
  157. if form.is_valid():
  158. device_pks = form.cleaned_data['pk']
  159. with transaction.atomic():
  160. # Remove the selected Devices from the Cluster
  161. for device in Device.objects.filter(pk__in=device_pks):
  162. device.cluster = None
  163. device.save()
  164. messages.success(request, "Removed {} devices from cluster {}".format(
  165. len(device_pks), cluster
  166. ))
  167. return redirect(cluster.get_absolute_url())
  168. else:
  169. form = self.form(initial={'pk': request.POST.getlist('pk')})
  170. selected_objects = Device.objects.filter(pk__in=form.initial['pk'])
  171. device_table = DeviceTable(list(selected_objects), orderable=False)
  172. return render(request, self.template_name, {
  173. 'form': form,
  174. 'parent_obj': cluster,
  175. 'table': device_table,
  176. 'obj_type_plural': 'devices',
  177. 'return_url': cluster.get_absolute_url(),
  178. })
  179. #
  180. # Virtual machines
  181. #
  182. class VirtualMachineListView(PermissionRequiredMixin, ObjectListView):
  183. permission_required = 'virtualization.view_virtualmachine'
  184. queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role', 'primary_ip4', 'primary_ip6')
  185. filterset = filters.VirtualMachineFilterSet
  186. filterset_form = forms.VirtualMachineFilterForm
  187. table = tables.VirtualMachineDetailTable
  188. template_name = 'virtualization/virtualmachine_list.html'
  189. class VirtualMachineView(PermissionRequiredMixin, View):
  190. permission_required = 'virtualization.view_virtualmachine'
  191. def get(self, request, pk):
  192. virtualmachine = get_object_or_404(VirtualMachine.objects.prefetch_related('tenant__group'), pk=pk)
  193. interfaces = Interface.objects.filter(virtual_machine=virtualmachine)
  194. services = Service.objects.filter(virtual_machine=virtualmachine)
  195. return render(request, 'virtualization/virtualmachine.html', {
  196. 'virtualmachine': virtualmachine,
  197. 'interfaces': interfaces,
  198. 'services': services,
  199. })
  200. class VirtualMachineConfigContextView(PermissionRequiredMixin, ObjectConfigContextView):
  201. permission_required = 'virtualization.view_virtualmachine'
  202. object_class = VirtualMachine
  203. base_template = 'virtualization/virtualmachine.html'
  204. class VirtualMachineCreateView(PermissionRequiredMixin, ObjectEditView):
  205. permission_required = 'virtualization.add_virtualmachine'
  206. model = VirtualMachine
  207. model_form = forms.VirtualMachineForm
  208. template_name = 'virtualization/virtualmachine_edit.html'
  209. default_return_url = 'virtualization:virtualmachine_list'
  210. class VirtualMachineEditView(VirtualMachineCreateView):
  211. permission_required = 'virtualization.change_virtualmachine'
  212. class VirtualMachineDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  213. permission_required = 'virtualization.delete_virtualmachine'
  214. model = VirtualMachine
  215. default_return_url = 'virtualization:virtualmachine_list'
  216. class VirtualMachineBulkImportView(PermissionRequiredMixin, BulkImportView):
  217. permission_required = 'virtualization.add_virtualmachine'
  218. model_form = forms.VirtualMachineCSVForm
  219. table = tables.VirtualMachineTable
  220. default_return_url = 'virtualization:virtualmachine_list'
  221. class VirtualMachineBulkEditView(PermissionRequiredMixin, BulkEditView):
  222. permission_required = 'virtualization.change_virtualmachine'
  223. queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role')
  224. filterset = filters.VirtualMachineFilterSet
  225. table = tables.VirtualMachineTable
  226. form = forms.VirtualMachineBulkEditForm
  227. default_return_url = 'virtualization:virtualmachine_list'
  228. class VirtualMachineBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  229. permission_required = 'virtualization.delete_virtualmachine'
  230. queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role')
  231. filterset = filters.VirtualMachineFilterSet
  232. table = tables.VirtualMachineTable
  233. default_return_url = 'virtualization:virtualmachine_list'
  234. #
  235. # VM interfaces
  236. #
  237. class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView):
  238. permission_required = 'dcim.add_interface'
  239. model = Interface
  240. form = forms.InterfaceCreateForm
  241. model_form = forms.InterfaceForm
  242. template_name = 'virtualization/virtualmachine_component_add.html'
  243. class InterfaceEditView(PermissionRequiredMixin, ObjectEditView):
  244. permission_required = 'dcim.change_interface'
  245. model = Interface
  246. model_form = forms.InterfaceForm
  247. template_name = 'virtualization/interface_edit.html'
  248. class InterfaceDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  249. permission_required = 'dcim.delete_interface'
  250. model = Interface
  251. class InterfaceBulkEditView(PermissionRequiredMixin, BulkEditView):
  252. permission_required = 'dcim.change_interface'
  253. queryset = Interface.objects.all()
  254. table = tables.InterfaceTable
  255. form = forms.InterfaceBulkEditForm
  256. class InterfaceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  257. permission_required = 'dcim.delete_interface'
  258. queryset = Interface.objects.all()
  259. table = tables.InterfaceTable
  260. #
  261. # Bulk Device component creation
  262. #
  263. class VirtualMachineBulkAddInterfaceView(PermissionRequiredMixin, BulkComponentCreateView):
  264. permission_required = 'dcim.add_interface'
  265. parent_model = VirtualMachine
  266. parent_field = 'virtual_machine'
  267. form = forms.VirtualMachineBulkAddInterfaceForm
  268. model = Interface
  269. model_form = forms.InterfaceForm
  270. filterset = filters.VirtualMachineFilterSet
  271. table = tables.VirtualMachineTable
  272. default_return_url = 'virtualization:virtualmachine_list'