- {% include 'utilities/obj_table.html' %}
+ {% include 'utilities/obj_table.html' with bulk_edit_url='virtualization:virtualmachine_bulk_edit' bulk_delete_url='virtualization:virtualmachine_bulk_delete' %}
{% include 'inc/search_panel.html' %}
diff --git a/netbox/virtualization/forms.py b/netbox/virtualization/forms.py
index 346c82bbf..b1ce920e4 100644
--- a/netbox/virtualization/forms.py
+++ b/netbox/virtualization/forms.py
@@ -13,8 +13,8 @@ from tenancy.forms import TenancyForm
from tenancy.models import Tenant
from utilities.forms import (
APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ChainedFieldsMixin,
- ChainedModelChoiceField, ChainedModelMultipleChoiceField, ComponentForm, ConfirmationForm, ExpandableNameField,
- FilterChoiceField, SlugField,
+ ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm, ConfirmationForm,
+ ExpandableNameField, FilterChoiceField, SlugField, SmallTextarea,
)
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
@@ -78,6 +78,15 @@ class ClusterCSVForm(forms.ModelForm):
fields = ['name', 'type', 'group']
+class ClusterBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
+ pk = forms.ModelMultipleChoiceField(queryset=Cluster.objects.all(), widget=forms.MultipleHiddenInput)
+ type = forms.ModelChoiceField(queryset=ClusterType.objects.all(), required=False)
+ group = forms.ModelChoiceField(queryset=ClusterGroup.objects.all(), required=False)
+
+ class Meta:
+ nullable_fields = ['group']
+
+
class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Cluster
q = forms.CharField(required=False, label='Search')
@@ -226,11 +235,16 @@ class VirtualMachineCSVForm(forms.ModelForm):
class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
pk = forms.ModelMultipleChoiceField(queryset=VirtualMachine.objects.all(), widget=forms.MultipleHiddenInput)
- cluster = forms.ModelChoiceField(queryset=Cluster.objects.all(), required=False, label='Cluster')
+ cluster = forms.ModelChoiceField(queryset=Cluster.objects.all(), required=False)
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
+ platform = forms.ModelChoiceField(queryset=Platform.objects.all(), required=False)
+ vcpus = forms.IntegerField(required=False, label='vCPUs')
+ memory = forms.IntegerField(required=False, label='Memory (MB)')
+ disk = forms.IntegerField(required=False, label='Disk (GB)')
+ comments = CommentField(widget=SmallTextarea)
class Meta:
- nullable_fields = ['tenant']
+ nullable_fields = ['tenant', 'platform', 'vcpus', 'memory', 'disk']
class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
diff --git a/netbox/virtualization/urls.py b/netbox/virtualization/urls.py
index c8d5163b6..bc8c44767 100644
--- a/netbox/virtualization/urls.py
+++ b/netbox/virtualization/urls.py
@@ -25,7 +25,8 @@ urlpatterns = [
url(r'^clusters/$', views.ClusterListView.as_view(), name='cluster_list'),
url(r'^clusters/add/$', views.ClusterCreateView.as_view(), name='cluster_add'),
url(r'^clusters/import/$', views.ClusterBulkImportView.as_view(), name='cluster_import'),
- # url(r'^clusters/edit/$', views.ClusterBulkEditView.as_view(), name='cluster_bulk_edit'),
+ url(r'^clusters/edit/$', views.ClusterBulkEditView.as_view(), name='cluster_bulk_edit'),
+ url(r'^clusters/delete/$', views.ClusterBulkDeleteView.as_view(), name='cluster_bulk_delete'),
url(r'^clusters/(?P
\d+)/$', views.ClusterView.as_view(), name='cluster'),
url(r'^clusters/(?P\d+)/edit/$', views.ClusterEditView.as_view(), name='cluster_edit'),
url(r'^clusters/(?P\d+)/delete/$', views.ClusterDeleteView.as_view(), name='cluster_delete'),
@@ -36,7 +37,8 @@ urlpatterns = [
url(r'^virtual-machines/$', views.VirtualMachineListView.as_view(), name='virtualmachine_list'),
url(r'^virtual-machines/add/$', views.VirtualMachineCreateView.as_view(), name='virtualmachine_add'),
url(r'^virtual-machines/import/$', views.VirtualMachineBulkImportView.as_view(), name='virtualmachine_import'),
- # url(r'^virtual-machines/edit/$', views.VirtualMachineBulkEditView.as_view(), name='virtualmachine_bulk_edit'),
+ url(r'^virtual-machines/edit/$', views.VirtualMachineBulkEditView.as_view(), name='virtualmachine_bulk_edit'),
+ url(r'^virtual-machines/delete/$', views.VirtualMachineBulkDeleteView.as_view(), name='virtualmachine_bulk_delete'),
url(r'^virtual-machines/(?P\d+)/$', views.VirtualMachineView.as_view(), name='virtualmachine'),
url(r'^virtual-machines/(?P\d+)/edit/$', views.VirtualMachineEditView.as_view(), name='virtualmachine_edit'),
url(r'^virtual-machines/(?P\d+)/delete/$', views.VirtualMachineDeleteView.as_view(), name='virtualmachine_delete'),
diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py
index f7b626589..c8b3ea8f2 100644
--- a/netbox/virtualization/views.py
+++ b/netbox/virtualization/views.py
@@ -138,10 +138,22 @@ class ClusterBulkImportView(PermissionRequiredMixin, BulkImportView):
default_return_url = 'virtualization:cluster_list'
+class ClusterBulkEditView(PermissionRequiredMixin, BulkEditView):
+ permission_required = 'virtualization.change_cluster'
+ cls = Cluster
+ filter = filters.ClusterFilter
+ table = tables.ClusterTable
+ form = forms.ClusterBulkEditForm
+ default_return_url = 'virtualization:cluster_list'
+
+
class ClusterBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'virtualization.delete_cluster'
cls = Cluster
- queryset = Cluster.objects.annotate(vm_count=Count('virtual_machines'))
+ queryset = Cluster.objects.annotate(
+ device_count=Count('devices', distinct=True),
+ vm_count=Count('virtual_machines', distinct=True)
+ )
table = tables.ClusterTable
default_return_url = 'virtualization:cluster_list'
@@ -227,7 +239,7 @@ class ClusterRemoveDevicesView(PermissionRequiredMixin, View):
#
class VirtualMachineListView(ObjectListView):
- queryset = VirtualMachine.objects.select_related('tenant')
+ queryset = VirtualMachine.objects.select_related('cluster', 'tenant')
filter = filters.VirtualMachineFilter
filter_form = forms.VirtualMachineFilterForm
table = tables.VirtualMachineTable
@@ -277,13 +289,21 @@ class VirtualMachineBulkImportView(PermissionRequiredMixin, BulkImportView):
class VirtualMachineBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'virtualization.change_virtualmachine'
cls = VirtualMachine
- queryset = VirtualMachine.objects.select_related('tenant')
+ queryset = VirtualMachine.objects.select_related('cluster', 'tenant')
filter = filters.VirtualMachineFilter
table = tables.VirtualMachineTable
form = forms.VirtualMachineBulkEditForm
default_return_url = 'virtualization:virtualmachine_list'
+class VirtualMachineBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
+ permission_required = 'virtualization.delete_virtualmachine'
+ cls = VirtualMachine
+ queryset = VirtualMachine.objects.select_related('cluster', 'tenant')
+ table = tables.VirtualMachineTable
+ default_return_url = 'virtualization:virtualmachine_list'
+
+
#
# VM interfaces
#