views.py 13 KB

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