views.py 12 KB

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