views.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. from __future__ import unicode_literals
  2. from django.contrib import messages
  3. from django.contrib.auth.mixins import PermissionRequiredMixin
  4. from django.db import transaction
  5. from django.db.models import Count
  6. from django.shortcuts import get_object_or_404, redirect, render
  7. from django.urls import reverse
  8. from django.views.generic import View
  9. from dcim.models import Device, Interface
  10. from dcim.tables import DeviceTable
  11. from extras.views import ObjectConfigContextView
  12. from ipam.models import Service
  13. from utilities.views import (
  14. BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, ObjectDeleteView,
  15. ObjectEditView, ObjectListView,
  16. )
  17. from . import filters, forms, tables
  18. from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
  19. #
  20. # Cluster types
  21. #
  22. class ClusterTypeListView(ObjectListView):
  23. queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
  24. table = tables.ClusterTypeTable
  25. template_name = 'virtualization/clustertype_list.html'
  26. class ClusterTypeCreateView(PermissionRequiredMixin, ObjectEditView):
  27. permission_required = 'virtualization.add_clustertype'
  28. model = ClusterType
  29. model_form = forms.ClusterTypeForm
  30. default_return_url = 'virtualization:clustertype_list'
  31. class ClusterTypeEditView(ClusterTypeCreateView):
  32. permission_required = 'virtualization.change_clustertype'
  33. class ClusterTypeBulkImportView(PermissionRequiredMixin, BulkImportView):
  34. permission_required = 'virtualization.add_clustertype'
  35. model_form = forms.ClusterTypeCSVForm
  36. table = tables.ClusterTypeTable
  37. default_return_url = 'virtualization:clustertype_list'
  38. class ClusterTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  39. permission_required = 'virtualization.delete_clustertype'
  40. queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
  41. table = tables.ClusterTypeTable
  42. default_return_url = 'virtualization:clustertype_list'
  43. #
  44. # Cluster groups
  45. #
  46. class ClusterGroupListView(ObjectListView):
  47. queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
  48. table = tables.ClusterGroupTable
  49. template_name = 'virtualization/clustergroup_list.html'
  50. class ClusterGroupCreateView(PermissionRequiredMixin, ObjectEditView):
  51. permission_required = 'virtualization.add_clustergroup'
  52. model = ClusterGroup
  53. model_form = forms.ClusterGroupForm
  54. default_return_url = 'virtualization:clustergroup_list'
  55. class ClusterGroupEditView(ClusterGroupCreateView):
  56. permission_required = 'virtualization.change_clustergroup'
  57. class ClusterGroupBulkImportView(PermissionRequiredMixin, BulkImportView):
  58. permission_required = 'virtualization.add_clustergroup'
  59. model_form = forms.ClusterGroupCSVForm
  60. table = tables.ClusterGroupTable
  61. default_return_url = 'virtualization:clustergroup_list'
  62. class ClusterGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  63. permission_required = 'virtualization.delete_clustergroup'
  64. queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
  65. table = tables.ClusterGroupTable
  66. default_return_url = 'virtualization:clustergroup_list'
  67. #
  68. # Clusters
  69. #
  70. class ClusterListView(ObjectListView):
  71. queryset = Cluster.objects.select_related('type', 'group', 'site')
  72. table = tables.ClusterTable
  73. filter = filters.ClusterFilter
  74. filter_form = forms.ClusterFilterForm
  75. template_name = 'virtualization/cluster_list.html'
  76. class ClusterView(View):
  77. def get(self, request, pk):
  78. cluster = get_object_or_404(Cluster, pk=pk)
  79. devices = Device.objects.filter(cluster=cluster).select_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.select_related('type', 'group', 'site')
  108. filter = filters.ClusterFilter
  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.select_related('type', 'group', 'site')
  115. filter = filters.ClusterFilter
  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(ObjectListView):
  183. queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role', 'primary_ip4', 'primary_ip6')
  184. filter = filters.VirtualMachineFilter
  185. filter_form = forms.VirtualMachineFilterForm
  186. table = tables.VirtualMachineDetailTable
  187. template_name = 'virtualization/virtualmachine_list.html'
  188. class VirtualMachineView(View):
  189. def get(self, request, pk):
  190. virtualmachine = get_object_or_404(VirtualMachine.objects.select_related('tenant__group'), pk=pk)
  191. interfaces = Interface.objects.filter(virtual_machine=virtualmachine)
  192. services = Service.objects.filter(virtual_machine=virtualmachine)
  193. return render(request, 'virtualization/virtualmachine.html', {
  194. 'virtualmachine': virtualmachine,
  195. 'interfaces': interfaces,
  196. 'services': services,
  197. })
  198. class VirtualMachineConfigContextView(ObjectConfigContextView):
  199. object_class = VirtualMachine
  200. base_template = 'virtualization/virtualmachine.html'
  201. class VirtualMachineCreateView(PermissionRequiredMixin, ObjectEditView):
  202. permission_required = 'virtualization.add_virtualmachine'
  203. model = VirtualMachine
  204. model_form = forms.VirtualMachineForm
  205. template_name = 'virtualization/virtualmachine_edit.html'
  206. default_return_url = 'virtualization:virtualmachine_list'
  207. class VirtualMachineEditView(VirtualMachineCreateView):
  208. permission_required = 'virtualization.change_virtualmachine'
  209. class VirtualMachineDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  210. permission_required = 'virtualization.delete_virtualmachine'
  211. model = VirtualMachine
  212. default_return_url = 'virtualization:virtualmachine_list'
  213. class VirtualMachineBulkImportView(PermissionRequiredMixin, BulkImportView):
  214. permission_required = 'virtualization.add_virtualmachine'
  215. model_form = forms.VirtualMachineCSVForm
  216. table = tables.VirtualMachineTable
  217. default_return_url = 'virtualization:virtualmachine_list'
  218. class VirtualMachineBulkEditView(PermissionRequiredMixin, BulkEditView):
  219. permission_required = 'virtualization.change_virtualmachine'
  220. queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role')
  221. filter = filters.VirtualMachineFilter
  222. table = tables.VirtualMachineTable
  223. form = forms.VirtualMachineBulkEditForm
  224. default_return_url = 'virtualization:virtualmachine_list'
  225. class VirtualMachineBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  226. permission_required = 'virtualization.delete_virtualmachine'
  227. queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role')
  228. filter = filters.VirtualMachineFilter
  229. table = tables.VirtualMachineTable
  230. default_return_url = 'virtualization:virtualmachine_list'
  231. #
  232. # VM interfaces
  233. #
  234. class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView):
  235. permission_required = 'dcim.add_interface'
  236. parent_model = VirtualMachine
  237. parent_field = 'virtual_machine'
  238. model = Interface
  239. form = forms.InterfaceCreateForm
  240. model_form = forms.InterfaceForm
  241. template_name = 'virtualization/virtualmachine_component_add.html'
  242. class InterfaceEditView(PermissionRequiredMixin, ObjectEditView):
  243. permission_required = 'dcim.change_interface'
  244. model = Interface
  245. model_form = forms.InterfaceForm
  246. template_name = 'virtualization/interface_edit.html'
  247. class InterfaceDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  248. permission_required = 'dcim.delete_interface'
  249. model = Interface
  250. class InterfaceBulkEditView(PermissionRequiredMixin, BulkEditView):
  251. permission_required = 'dcim.change_interface'
  252. queryset = Interface.objects.all()
  253. parent_model = VirtualMachine
  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. parent_model = VirtualMachine
  260. table = tables.InterfaceTable
  261. #
  262. # Bulk Device component creation
  263. #
  264. class VirtualMachineBulkAddInterfaceView(PermissionRequiredMixin, BulkComponentCreateView):
  265. permission_required = 'dcim.add_interface'
  266. parent_model = VirtualMachine
  267. parent_field = 'virtual_machine'
  268. form = forms.VirtualMachineBulkAddInterfaceForm
  269. model = Interface
  270. model_form = forms.InterfaceForm
  271. table = tables.VirtualMachineTable
  272. default_return_url = 'virtualization:virtualmachine_list'