2017-08-21 16:53:36 -04:00
|
|
|
from django.contrib import messages
|
2017-08-04 17:02:52 -04:00
|
|
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
2018-08-17 14:26:50 -04:00
|
|
|
from django.db import transaction
|
2017-08-04 17:02:52 -04:00
|
|
|
from django.db.models import Count
|
2017-08-21 16:53:36 -04:00
|
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
2017-08-04 17:02:52 -04:00
|
|
|
from django.urls import reverse
|
|
|
|
from django.views.generic import View
|
|
|
|
|
2017-08-29 14:24:58 -04:00
|
|
|
from dcim.models import Device, Interface
|
2017-08-21 16:53:36 -04:00
|
|
|
from dcim.tables import DeviceTable
|
2018-06-28 13:48:12 -04:00
|
|
|
from extras.views import ObjectConfigContextView
|
2017-08-31 12:50:35 -04:00
|
|
|
from ipam.models import Service
|
2017-08-04 17:02:52 -04:00
|
|
|
from utilities.views import (
|
2017-12-15 15:57:49 -05:00
|
|
|
BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, ObjectDeleteView,
|
|
|
|
ObjectEditView, ObjectListView,
|
2017-08-04 17:02:52 -04:00
|
|
|
)
|
2017-11-07 11:08:23 -05:00
|
|
|
from . import filters, forms, tables
|
2017-08-29 14:24:58 -04:00
|
|
|
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
2017-08-04 17:02:52 -04:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Cluster types
|
|
|
|
#
|
|
|
|
|
|
|
|
class ClusterTypeListView(ObjectListView):
|
|
|
|
queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
|
|
|
|
table = tables.ClusterTypeTable
|
|
|
|
template_name = 'virtualization/clustertype_list.html'
|
|
|
|
|
|
|
|
|
|
|
|
class ClusterTypeCreateView(PermissionRequiredMixin, ObjectEditView):
|
|
|
|
permission_required = 'virtualization.add_clustertype'
|
|
|
|
model = ClusterType
|
2017-09-12 13:54:44 -04:00
|
|
|
model_form = forms.ClusterTypeForm
|
2018-07-02 11:54:41 -04:00
|
|
|
default_return_url = 'virtualization:clustertype_list'
|
2017-08-04 17:02:52 -04:00
|
|
|
|
|
|
|
|
|
|
|
class ClusterTypeEditView(ClusterTypeCreateView):
|
|
|
|
permission_required = 'virtualization.change_clustertype'
|
|
|
|
|
|
|
|
|
2017-10-09 15:49:48 -04:00
|
|
|
class ClusterTypeBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
|
|
permission_required = 'virtualization.add_clustertype'
|
|
|
|
model_form = forms.ClusterTypeCSVForm
|
|
|
|
table = tables.ClusterTypeTable
|
|
|
|
default_return_url = 'virtualization:clustertype_list'
|
|
|
|
|
|
|
|
|
2017-08-04 17:02:52 -04:00
|
|
|
class ClusterTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|
|
|
permission_required = 'virtualization.delete_clustertype'
|
|
|
|
queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
|
|
|
|
table = tables.ClusterTypeTable
|
|
|
|
default_return_url = 'virtualization:clustertype_list'
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Cluster groups
|
|
|
|
#
|
|
|
|
|
|
|
|
class ClusterGroupListView(ObjectListView):
|
|
|
|
queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
|
|
|
|
table = tables.ClusterGroupTable
|
|
|
|
template_name = 'virtualization/clustergroup_list.html'
|
|
|
|
|
|
|
|
|
|
|
|
class ClusterGroupCreateView(PermissionRequiredMixin, ObjectEditView):
|
|
|
|
permission_required = 'virtualization.add_clustergroup'
|
|
|
|
model = ClusterGroup
|
2017-09-12 13:54:44 -04:00
|
|
|
model_form = forms.ClusterGroupForm
|
2018-07-02 11:54:41 -04:00
|
|
|
default_return_url = 'virtualization:clustergroup_list'
|
2017-08-04 17:02:52 -04:00
|
|
|
|
|
|
|
|
|
|
|
class ClusterGroupEditView(ClusterGroupCreateView):
|
|
|
|
permission_required = 'virtualization.change_clustergroup'
|
|
|
|
|
|
|
|
|
2017-10-09 15:49:48 -04:00
|
|
|
class ClusterGroupBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
|
|
permission_required = 'virtualization.add_clustergroup'
|
|
|
|
model_form = forms.ClusterGroupCSVForm
|
|
|
|
table = tables.ClusterGroupTable
|
|
|
|
default_return_url = 'virtualization:clustergroup_list'
|
|
|
|
|
|
|
|
|
2017-08-04 17:02:52 -04:00
|
|
|
class ClusterGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|
|
|
permission_required = 'virtualization.delete_clustergroup'
|
|
|
|
queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
|
|
|
|
table = tables.ClusterGroupTable
|
|
|
|
default_return_url = 'virtualization:clustergroup_list'
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Clusters
|
|
|
|
#
|
|
|
|
|
|
|
|
class ClusterListView(ObjectListView):
|
2018-07-20 21:18:10 -04:00
|
|
|
queryset = Cluster.objects.select_related('type', 'group', 'site')
|
2017-08-04 17:02:52 -04:00
|
|
|
table = tables.ClusterTable
|
2017-08-16 17:00:17 -04:00
|
|
|
filter = filters.ClusterFilter
|
|
|
|
filter_form = forms.ClusterFilterForm
|
2017-08-04 17:02:52 -04:00
|
|
|
template_name = 'virtualization/cluster_list.html'
|
|
|
|
|
|
|
|
|
|
|
|
class ClusterView(View):
|
|
|
|
|
|
|
|
def get(self, request, pk):
|
|
|
|
|
|
|
|
cluster = get_object_or_404(Cluster, pk=pk)
|
2017-08-21 16:53:36 -04:00
|
|
|
devices = Device.objects.filter(cluster=cluster).select_related(
|
|
|
|
'site', 'rack', 'tenant', 'device_type__manufacturer'
|
|
|
|
)
|
|
|
|
device_table = DeviceTable(list(devices), orderable=False)
|
2018-05-19 11:50:03 +02:00
|
|
|
if request.user.has_perm('virtualization.change_cluster'):
|
2017-08-21 16:53:36 -04:00
|
|
|
device_table.columns.show('pk')
|
2017-08-04 17:02:52 -04:00
|
|
|
|
|
|
|
return render(request, 'virtualization/cluster.html', {
|
|
|
|
'cluster': cluster,
|
2017-08-21 16:53:36 -04:00
|
|
|
'device_table': device_table,
|
2017-08-04 17:02:52 -04:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
class ClusterCreateView(PermissionRequiredMixin, ObjectEditView):
|
|
|
|
permission_required = 'virtualization.add_cluster'
|
2018-05-10 12:53:11 -04:00
|
|
|
template_name = 'virtualization/cluster_edit.html'
|
2017-08-04 17:02:52 -04:00
|
|
|
model = Cluster
|
2017-09-12 13:54:44 -04:00
|
|
|
model_form = forms.ClusterForm
|
2017-08-04 17:02:52 -04:00
|
|
|
|
|
|
|
|
|
|
|
class ClusterEditView(ClusterCreateView):
|
|
|
|
permission_required = 'virtualization.change_cluster'
|
|
|
|
|
|
|
|
|
|
|
|
class ClusterDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
|
|
|
permission_required = 'virtualization.delete_cluster'
|
|
|
|
model = Cluster
|
|
|
|
default_return_url = 'virtualization:cluster_list'
|
|
|
|
|
|
|
|
|
|
|
|
class ClusterBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
|
|
permission_required = 'virtualization.add_cluster'
|
|
|
|
model_form = forms.ClusterCSVForm
|
|
|
|
table = tables.ClusterTable
|
|
|
|
default_return_url = 'virtualization:cluster_list'
|
|
|
|
|
|
|
|
|
2017-09-11 16:14:05 -04:00
|
|
|
class ClusterBulkEditView(PermissionRequiredMixin, BulkEditView):
|
|
|
|
permission_required = 'virtualization.change_cluster'
|
2018-07-20 21:18:10 -04:00
|
|
|
queryset = Cluster.objects.select_related('type', 'group', 'site')
|
2017-09-11 16:14:05 -04:00
|
|
|
filter = filters.ClusterFilter
|
|
|
|
table = tables.ClusterTable
|
|
|
|
form = forms.ClusterBulkEditForm
|
|
|
|
default_return_url = 'virtualization:cluster_list'
|
|
|
|
|
|
|
|
|
2017-08-04 17:02:52 -04:00
|
|
|
class ClusterBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|
|
|
permission_required = 'virtualization.delete_cluster'
|
2018-07-20 21:18:10 -04:00
|
|
|
queryset = Cluster.objects.select_related('type', 'group', 'site')
|
2018-04-19 11:17:17 -04:00
|
|
|
filter = filters.ClusterFilter
|
2017-08-04 17:02:52 -04:00
|
|
|
table = tables.ClusterTable
|
|
|
|
default_return_url = 'virtualization:cluster_list'
|
|
|
|
|
|
|
|
|
2017-08-21 16:53:36 -04:00
|
|
|
class ClusterAddDevicesView(PermissionRequiredMixin, View):
|
|
|
|
permission_required = 'virtualization.change_cluster'
|
|
|
|
form = forms.ClusterAddDevicesForm
|
|
|
|
template_name = 'virtualization/cluster_add_devices.html'
|
|
|
|
|
|
|
|
def get(self, request, pk):
|
|
|
|
|
|
|
|
cluster = get_object_or_404(Cluster, pk=pk)
|
2017-09-22 12:53:09 -04:00
|
|
|
form = self.form(cluster)
|
2017-08-21 16:53:36 -04:00
|
|
|
|
|
|
|
return render(request, self.template_name, {
|
|
|
|
'cluster': cluster,
|
|
|
|
'form': form,
|
|
|
|
'return_url': reverse('virtualization:cluster', kwargs={'pk': pk}),
|
|
|
|
})
|
|
|
|
|
|
|
|
def post(self, request, pk):
|
|
|
|
|
|
|
|
cluster = get_object_or_404(Cluster, pk=pk)
|
2017-09-22 12:53:09 -04:00
|
|
|
form = self.form(cluster, request.POST)
|
2017-08-21 16:53:36 -04:00
|
|
|
|
|
|
|
if form.is_valid():
|
|
|
|
|
2018-08-17 14:26:50 -04:00
|
|
|
device_pks = form.cleaned_data['devices']
|
|
|
|
with transaction.atomic():
|
|
|
|
|
|
|
|
# Assign the selected Devices to the Cluster
|
|
|
|
for device in Device.objects.filter(pk__in=device_pks):
|
|
|
|
device.cluster = cluster
|
|
|
|
device.save()
|
2017-08-21 16:53:36 -04:00
|
|
|
|
|
|
|
messages.success(request, "Added {} devices to cluster {}".format(
|
2018-08-17 14:26:50 -04:00
|
|
|
len(device_pks), cluster
|
2017-08-21 16:53:36 -04:00
|
|
|
))
|
|
|
|
return redirect(cluster.get_absolute_url())
|
|
|
|
|
|
|
|
return render(request, self.template_name, {
|
2018-08-17 14:26:50 -04:00
|
|
|
'cluster': cluster,
|
2017-08-21 16:53:36 -04:00
|
|
|
'form': form,
|
|
|
|
'return_url': cluster.get_absolute_url(),
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
class ClusterRemoveDevicesView(PermissionRequiredMixin, View):
|
|
|
|
permission_required = 'virtualization.change_cluster'
|
|
|
|
form = forms.ClusterRemoveDevicesForm
|
|
|
|
template_name = 'utilities/obj_bulk_remove.html'
|
|
|
|
|
|
|
|
def post(self, request, pk):
|
|
|
|
|
|
|
|
cluster = get_object_or_404(Cluster, pk=pk)
|
|
|
|
|
|
|
|
if '_confirm' in request.POST:
|
|
|
|
form = self.form(request.POST)
|
|
|
|
if form.is_valid():
|
|
|
|
|
2018-08-17 14:26:50 -04:00
|
|
|
device_pks = form.cleaned_data['pk']
|
|
|
|
with transaction.atomic():
|
|
|
|
|
|
|
|
# Remove the selected Devices from the Cluster
|
|
|
|
for device in Device.objects.filter(pk__in=device_pks):
|
|
|
|
device.cluster = None
|
|
|
|
device.save()
|
2017-08-21 16:53:36 -04:00
|
|
|
|
|
|
|
messages.success(request, "Removed {} devices from cluster {}".format(
|
2018-08-17 14:26:50 -04:00
|
|
|
len(device_pks), cluster
|
2017-08-21 16:53:36 -04:00
|
|
|
))
|
|
|
|
return redirect(cluster.get_absolute_url())
|
|
|
|
|
|
|
|
else:
|
|
|
|
form = self.form(initial={'pk': request.POST.getlist('pk')})
|
|
|
|
|
|
|
|
selected_objects = Device.objects.filter(pk__in=form.initial['pk'])
|
|
|
|
device_table = DeviceTable(list(selected_objects), orderable=False)
|
|
|
|
|
|
|
|
return render(request, self.template_name, {
|
|
|
|
'form': form,
|
|
|
|
'parent_obj': cluster,
|
|
|
|
'table': device_table,
|
|
|
|
'obj_type_plural': 'devices',
|
|
|
|
'return_url': cluster.get_absolute_url(),
|
|
|
|
})
|
|
|
|
|
|
|
|
|
2017-08-04 17:02:52 -04:00
|
|
|
#
|
|
|
|
# Virtual machines
|
|
|
|
#
|
|
|
|
|
|
|
|
class VirtualMachineListView(ObjectListView):
|
2018-07-20 21:18:10 -04:00
|
|
|
queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role', 'primary_ip4', 'primary_ip6')
|
2017-08-16 17:00:17 -04:00
|
|
|
filter = filters.VirtualMachineFilter
|
|
|
|
filter_form = forms.VirtualMachineFilterForm
|
2017-09-15 11:47:29 -04:00
|
|
|
table = tables.VirtualMachineDetailTable
|
2017-08-04 17:02:52 -04:00
|
|
|
template_name = 'virtualization/virtualmachine_list.html'
|
|
|
|
|
|
|
|
|
|
|
|
class VirtualMachineView(View):
|
|
|
|
|
|
|
|
def get(self, request, pk):
|
|
|
|
|
2018-06-14 16:15:14 -04:00
|
|
|
virtualmachine = get_object_or_404(VirtualMachine.objects.select_related('tenant__group'), pk=pk)
|
|
|
|
interfaces = Interface.objects.filter(virtual_machine=virtualmachine)
|
|
|
|
services = Service.objects.filter(virtual_machine=virtualmachine)
|
2017-08-04 17:02:52 -04:00
|
|
|
|
|
|
|
return render(request, 'virtualization/virtualmachine.html', {
|
2018-06-14 16:15:14 -04:00
|
|
|
'virtualmachine': virtualmachine,
|
2017-08-18 14:37:19 -04:00
|
|
|
'interfaces': interfaces,
|
2017-08-31 12:50:35 -04:00
|
|
|
'services': services,
|
2017-08-04 17:02:52 -04:00
|
|
|
})
|
|
|
|
|
|
|
|
|
2018-06-28 13:48:12 -04:00
|
|
|
class VirtualMachineConfigContextView(ObjectConfigContextView):
|
|
|
|
object_class = VirtualMachine
|
|
|
|
base_template = 'virtualization/virtualmachine.html'
|
2018-06-27 16:02:34 -04:00
|
|
|
|
|
|
|
|
2017-08-04 17:02:52 -04:00
|
|
|
class VirtualMachineCreateView(PermissionRequiredMixin, ObjectEditView):
|
|
|
|
permission_required = 'virtualization.add_virtualmachine'
|
|
|
|
model = VirtualMachine
|
2017-09-12 13:54:44 -04:00
|
|
|
model_form = forms.VirtualMachineForm
|
2017-08-04 17:02:52 -04:00
|
|
|
template_name = 'virtualization/virtualmachine_edit.html'
|
|
|
|
default_return_url = 'virtualization:virtualmachine_list'
|
|
|
|
|
|
|
|
|
|
|
|
class VirtualMachineEditView(VirtualMachineCreateView):
|
|
|
|
permission_required = 'virtualization.change_virtualmachine'
|
|
|
|
|
|
|
|
|
|
|
|
class VirtualMachineDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
|
|
|
permission_required = 'virtualization.delete_virtualmachine'
|
|
|
|
model = VirtualMachine
|
|
|
|
default_return_url = 'virtualization:virtualmachine_list'
|
|
|
|
|
|
|
|
|
|
|
|
class VirtualMachineBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
|
|
permission_required = 'virtualization.add_virtualmachine'
|
|
|
|
model_form = forms.VirtualMachineCSVForm
|
|
|
|
table = tables.VirtualMachineTable
|
|
|
|
default_return_url = 'virtualization:virtualmachine_list'
|
|
|
|
|
|
|
|
|
|
|
|
class VirtualMachineBulkEditView(PermissionRequiredMixin, BulkEditView):
|
|
|
|
permission_required = 'virtualization.change_virtualmachine'
|
2018-07-20 21:18:10 -04:00
|
|
|
queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role')
|
2017-08-16 17:00:17 -04:00
|
|
|
filter = filters.VirtualMachineFilter
|
2017-08-04 17:02:52 -04:00
|
|
|
table = tables.VirtualMachineTable
|
|
|
|
form = forms.VirtualMachineBulkEditForm
|
|
|
|
default_return_url = 'virtualization:virtualmachine_list'
|
|
|
|
|
|
|
|
|
2017-09-11 16:14:05 -04:00
|
|
|
class VirtualMachineBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|
|
|
permission_required = 'virtualization.delete_virtualmachine'
|
2018-07-20 21:18:10 -04:00
|
|
|
queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role')
|
2017-10-18 12:31:58 -04:00
|
|
|
filter = filters.VirtualMachineFilter
|
2017-09-11 16:14:05 -04:00
|
|
|
table = tables.VirtualMachineTable
|
|
|
|
default_return_url = 'virtualization:virtualmachine_list'
|
|
|
|
|
|
|
|
|
2017-08-04 17:02:52 -04:00
|
|
|
#
|
|
|
|
# VM interfaces
|
|
|
|
#
|
|
|
|
|
2017-08-29 14:24:58 -04:00
|
|
|
class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView):
|
|
|
|
permission_required = 'dcim.add_interface'
|
2017-08-18 14:37:19 -04:00
|
|
|
parent_model = VirtualMachine
|
|
|
|
parent_field = 'virtual_machine'
|
2017-08-29 14:24:58 -04:00
|
|
|
model = Interface
|
|
|
|
form = forms.InterfaceCreateForm
|
|
|
|
model_form = forms.InterfaceForm
|
2017-08-18 14:37:19 -04:00
|
|
|
template_name = 'virtualization/virtualmachine_component_add.html'
|
|
|
|
|
|
|
|
|
2017-12-15 15:57:49 -05:00
|
|
|
class InterfaceEditView(PermissionRequiredMixin, ObjectEditView):
|
2017-08-29 14:24:58 -04:00
|
|
|
permission_required = 'dcim.change_interface'
|
|
|
|
model = Interface
|
2017-09-12 13:54:44 -04:00
|
|
|
model_form = forms.InterfaceForm
|
2018-03-14 14:53:28 -04:00
|
|
|
template_name = 'virtualization/interface_edit.html'
|
2017-08-18 14:37:19 -04:00
|
|
|
|
|
|
|
|
2017-12-15 15:57:49 -05:00
|
|
|
class InterfaceDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
2017-08-29 14:24:58 -04:00
|
|
|
permission_required = 'dcim.delete_interface'
|
|
|
|
model = Interface
|
2017-08-18 14:37:19 -04:00
|
|
|
|
|
|
|
|
2017-08-29 14:24:58 -04:00
|
|
|
class InterfaceBulkEditView(PermissionRequiredMixin, BulkEditView):
|
|
|
|
permission_required = 'dcim.change_interface'
|
2018-07-20 21:18:10 -04:00
|
|
|
queryset = Interface.objects.all()
|
|
|
|
parent_model = VirtualMachine
|
2017-08-29 14:24:58 -04:00
|
|
|
table = tables.InterfaceTable
|
|
|
|
form = forms.InterfaceBulkEditForm
|
2017-08-18 14:37:19 -04:00
|
|
|
|
|
|
|
|
2017-08-29 14:24:58 -04:00
|
|
|
class InterfaceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|
|
|
permission_required = 'dcim.delete_interface'
|
2018-07-20 21:18:10 -04:00
|
|
|
queryset = Interface.objects.all()
|
|
|
|
parent_model = VirtualMachine
|
2017-08-29 14:24:58 -04:00
|
|
|
table = tables.InterfaceTable
|
2017-09-12 12:49:01 -04:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Bulk Device component creation
|
|
|
|
#
|
|
|
|
|
|
|
|
class VirtualMachineBulkAddInterfaceView(PermissionRequiredMixin, BulkComponentCreateView):
|
|
|
|
permission_required = 'dcim.add_interface'
|
|
|
|
parent_model = VirtualMachine
|
|
|
|
parent_field = 'virtual_machine'
|
|
|
|
form = forms.VirtualMachineBulkAddInterfaceForm
|
|
|
|
model = Interface
|
|
|
|
model_form = forms.InterfaceForm
|
2018-12-19 10:59:12 -05:00
|
|
|
filter = filters.VirtualMachineFilter
|
2017-09-12 12:49:01 -04:00
|
|
|
table = tables.VirtualMachineTable
|
2017-09-29 12:15:14 -04:00
|
|
|
default_return_url = 'virtualization:virtualmachine_list'
|