8356 add supplemental forms

This commit is contained in:
Arthur 2023-10-18 16:21:29 -07:00
parent 5bcf351bdc
commit 12861a19a8
10 changed files with 219 additions and 4 deletions

View File

@ -10,7 +10,7 @@ from netbox.filtersets import OrganizationalModelFilterSet, NetBoxModelFilterSet
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
from utilities.filters import MultiValueCharFilter, MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter from utilities.filters import MultiValueCharFilter, MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter
from .choices import * from .choices import *
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from .models import Cluster, ClusterGroup, ClusterType, VirtualDisk, VirtualMachine, VMInterface
__all__ = ( __all__ = (
'ClusterFilterSet', 'ClusterFilterSet',
@ -303,3 +303,28 @@ class VMInterfaceFilterSet(NetBoxModelFilterSet, CommonInterfaceFilterSet):
Q(name__icontains=value) | Q(name__icontains=value) |
Q(description__icontains=value) Q(description__icontains=value)
) )
class VirtualDiskFilterSet(NetBoxModelFilterSet):
virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine',
queryset=VirtualMachine.objects.all(),
label=_('Virtual machine (ID)'),
)
virtual_machine = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine__name',
queryset=VirtualMachine.objects.all(),
to_field_name='name',
label=_('Virtual machine'),
)
class Meta:
model = VirtualDisk
fields = ['id', 'name', 'size',]
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(name__icontains=value)
)

View File

@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _
from utilities.forms import BootstrapMixin, form_from_model from utilities.forms import BootstrapMixin, form_from_model
from utilities.forms.fields import ExpandableNameField from utilities.forms.fields import ExpandableNameField
from virtualization.models import VMInterface, VirtualMachine from virtualization.models import VirtualDisk, VMInterface, VirtualMachine
__all__ = ( __all__ = (
'VMInterfaceBulkCreateForm', 'VMInterfaceBulkCreateForm',
@ -30,3 +30,10 @@ class VMInterfaceBulkCreateForm(
VirtualMachineBulkAddComponentForm VirtualMachineBulkAddComponentForm
): ):
replication_fields = ('name',) replication_fields = ('name',)
class VirtualDiskBulkCreateForm(
form_from_model(VirtualDisk, ['tags']),
VirtualMachineBulkAddComponentForm
):
replication_fields = ('name', 'size')

View File

@ -18,6 +18,7 @@ __all__ = (
'ClusterBulkEditForm', 'ClusterBulkEditForm',
'ClusterGroupBulkEditForm', 'ClusterGroupBulkEditForm',
'ClusterTypeBulkEditForm', 'ClusterTypeBulkEditForm',
'VirtualDiskBulkEditForm',
'VirtualMachineBulkEditForm', 'VirtualMachineBulkEditForm',
'VMInterfaceBulkEditForm', 'VMInterfaceBulkEditForm',
'VMInterfaceBulkRenameForm', 'VMInterfaceBulkRenameForm',
@ -315,3 +316,19 @@ class VMInterfaceBulkRenameForm(BulkRenameForm):
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
widget=forms.MultipleHiddenInput() widget=forms.MultipleHiddenInput()
) )
class VirtualDiskBulkEditForm(NetBoxModelBulkEditForm):
virtual_machine = forms.ModelChoiceField(
label=_('Virtual machine'),
queryset=VirtualMachine.objects.all(),
required=False,
disabled=True,
widget=forms.HiddenInput()
)
model = VirtualDisk
fieldsets = (
(None, ('mtu', 'enabled', 'vrf', 'size')),
)
nullable_fields = ()

View File

@ -14,6 +14,7 @@ __all__ = (
'ClusterImportForm', 'ClusterImportForm',
'ClusterGroupImportForm', 'ClusterGroupImportForm',
'ClusterTypeImportForm', 'ClusterTypeImportForm',
'VirtualDiskImportForm',
'VirtualMachineImportForm', 'VirtualMachineImportForm',
'VMInterfaceImportForm', 'VMInterfaceImportForm',
) )
@ -199,3 +200,17 @@ class VMInterfaceImportForm(NetBoxModelImportForm):
return True return True
else: else:
return self.cleaned_data['enabled'] return self.cleaned_data['enabled']
class VirtualDiskImportForm(NetBoxModelImportForm):
virtual_machine = CSVModelChoiceField(
label=_('Virtual machine'),
queryset=VirtualMachine.objects.all(),
to_field_name='name'
)
class Meta:
model = VirtualDisk
fields = (
'virtual_machine', 'name', 'size', 'tags'
)

View File

@ -16,6 +16,7 @@ __all__ = (
'ClusterFilterForm', 'ClusterFilterForm',
'ClusterGroupFilterForm', 'ClusterGroupFilterForm',
'ClusterTypeFilterForm', 'ClusterTypeFilterForm',
'VirtualDiskFilterForm',
'VirtualMachineFilterForm', 'VirtualMachineFilterForm',
'VMInterfaceFilterForm', 'VMInterfaceFilterForm',
) )
@ -221,3 +222,20 @@ class VMInterfaceFilterForm(NetBoxModelFilterSetForm):
label=_('L2VPN') label=_('L2VPN')
) )
tag = TagFilterField(model) tag = TagFilterField(model)
class VirtualDiskFilterForm(NetBoxModelFilterSetForm):
model = VirtualDisk
fieldsets = (
(None, ('q', 'filter_id', 'tag')),
(_('Virtual Machine'), ('virtual_machine_id')),
)
virtual_machine_id = DynamicModelMultipleChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
query_params={
'cluster_id': '$cluster_id'
},
label=_('Virtual machine')
)
tag = TagFilterField(model)

View File

@ -22,6 +22,7 @@ __all__ = (
'ClusterGroupForm', 'ClusterGroupForm',
'ClusterRemoveDevicesForm', 'ClusterRemoveDevicesForm',
'ClusterTypeForm', 'ClusterTypeForm',
'VirtualDiskForm',
'VirtualMachineForm', 'VirtualMachineForm',
'VMInterfaceForm', 'VMInterfaceForm',
) )
@ -349,3 +350,28 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
# Disable reassignment of VirtualMachine when editing an existing instance # Disable reassignment of VirtualMachine when editing an existing instance
if self.instance.pk: if self.instance.pk:
self.fields['virtual_machine'].disabled = True self.fields['virtual_machine'].disabled = True
class VirtualDiskForm(NetBoxModelForm):
virtual_machine = DynamicModelChoiceField(
label=_('Virtual machine'),
queryset=VirtualMachine.objects.all(),
selector=True
)
fieldsets = (
(_(''), ('virtual_machine', 'name', 'size', 'tags')),
)
class Meta:
model = VirtualDisk
fields = [
'virtual_machine', 'name', 'size', 'tags',
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Disable reassignment of VirtualMachine when editing an existing instance
if self.instance.pk:
self.fields['virtual_machine'].disabled = True

View File

@ -21,6 +21,7 @@ from utilities.tracking import TrackingModelMixin
from virtualization.choices import * from virtualization.choices import *
__all__ = ( __all__ = (
'VirtualDisk',
'VirtualMachine', 'VirtualMachine',
'VMInterface', 'VMInterface',
) )

View File

@ -4,9 +4,10 @@ from django.utils.translation import gettext_lazy as _
from dcim.tables.devices import BaseInterfaceTable from dcim.tables.devices import BaseInterfaceTable
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from virtualization.models import VirtualMachine, VMInterface from virtualization.models import VirtualDisk, VirtualMachine, VMInterface
__all__ = ( __all__ = (
'VirtualDiskTable',
'VirtualMachineTable', 'VirtualMachineTable',
'VirtualMachineVMInterfaceTable', 'VirtualMachineVMInterfaceTable',
'VMInterfaceTable', 'VMInterfaceTable',
@ -155,3 +156,19 @@ class VirtualMachineVMInterfaceTable(VMInterfaceTable):
row_attrs = { row_attrs = {
'data-name': lambda record: record.name, 'data-name': lambda record: record.name,
} }
class VirtualDiskTable(VMInterfaceTable):
actions = columns.ActionsColumn(
actions=('edit', 'delete'),
)
class Meta(NetBoxTable.Meta):
model = VirtualDisk
fields = (
'pk', 'id', 'name', 'size', 'tags', 'actions',
)
default_columns = ('pk', 'name', 'size')
row_attrs = {
'data-name': lambda record: record.name,
}

View File

@ -48,4 +48,13 @@ urlpatterns = [
path('interfaces/<int:pk>/', include(get_model_urls('virtualization', 'vminterface'))), path('interfaces/<int:pk>/', include(get_model_urls('virtualization', 'vminterface'))),
path('virtual-machines/interfaces/add/', views.VirtualMachineBulkAddInterfaceView.as_view(), name='virtualmachine_bulk_add_vminterface'), path('virtual-machines/interfaces/add/', views.VirtualMachineBulkAddInterfaceView.as_view(), name='virtualmachine_bulk_add_vminterface'),
# Virtual disks
# path('disks/', views.VirtualDiskListView.as_view(), name='virtualdisk_list'),
# path('disks/add/', views.VirtualDiskCreateView.as_view(), name='virtualdisk_add'),
# path('disks/import/', views.VirtualDiskBulkImportView.as_view(), name='virtualdisk_import'),
# path('disks/edit/', views.VirtualDiskBulkEditView.as_view(), name='virtualdisk_bulk_edit'),
# path('disks/rename/', views.VirtualDiskBulkRenameView.as_view(), name='virtualdisk_bulk_rename'),
# path('disks/delete/', views.VirtualDiskBulkDeleteView.as_view(), name='virtualdisk_bulk_delete'),
# path('disks/<int:pk>/', include(get_model_urls('virtualization', 'virtualdisk'))),
# path('virtual-machines/disks/add/', views.VirtualMachineBulkAddDiskView.as_view(), name='virtualmachine_bulk_add_disk'),
] ]

View File

@ -21,7 +21,7 @@ from tenancy.views import ObjectContactsView
from utilities.utils import count_related from utilities.utils import count_related
from utilities.views import ViewTab, register_model_view from utilities.views import ViewTab, register_model_view
from . import filtersets, forms, tables from . import filtersets, forms, tables
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from .models import Cluster, ClusterGroup, ClusterType, VirtualDisk, VirtualMachine, VMInterface
# #
@ -574,3 +574,83 @@ class VirtualMachineBulkAddInterfaceView(generic.BulkComponentCreateView):
def get_required_permission(self): def get_required_permission(self):
return f'virtualization.add_vminterface' return f'virtualization.add_vminterface'
#
# Virtual Disk
#
class VirtualDiskListView(generic.ObjectListView):
queryset = VirtualDisk.objects.all()
filterset = filtersets.VirtualDiskFilterSet
filterset_form = forms.VirtualDiskFilterForm
table = tables.VirtualDiskTable
@register_model_view(VirtualDisk)
class VirtualDiskView(generic.ObjectView):
queryset = VirtualDisk.objects.all()
def get_extra_context(self, request, instance):
# Get child interfaces
child_interfaces = VirtualDisk.objects.restrict(request.user, 'view').filter(parent=instance)
child_interfaces_tables = tables.VirtualDiskTable(
child_interfaces,
exclude=('virtual_machine',),
orderable=False
)
# Get assigned VLANs and annotate whether each is tagged or untagged
vlans = []
if instance.untagged_vlan is not None:
vlans.append(instance.untagged_vlan)
vlans[0].tagged = False
for vlan in instance.tagged_vlans.restrict(request.user).prefetch_related('site', 'group', 'tenant', 'role'):
vlan.tagged = True
vlans.append(vlan)
vlan_table = InterfaceVLANTable(
interface=instance,
data=vlans,
orderable=False
)
return {
'child_interfaces_table': child_interfaces_tables,
'vlan_table': vlan_table,
}
# class VirtualDiskCreateView(generic.ComponentCreateView):
# queryset = VirtualDisk.objects.all()
# form = forms.VirtualDiskCreateForm
# model_form = forms.VirtualDiskForm
@register_model_view(VirtualDisk, 'edit')
class VirtualDiskEditView(generic.ObjectEditView):
queryset = VirtualDisk.objects.all()
form = forms.VirtualDiskForm
@register_model_view(VirtualDisk, 'delete')
class VirtualDiskDeleteView(generic.ObjectDeleteView):
queryset = VirtualDisk.objects.all()
class VirtualDiskBulkImportView(generic.BulkImportView):
queryset = VirtualDisk.objects.all()
model_form = forms.VirtualDiskImportForm
class VirtualDiskBulkEditView(generic.BulkEditView):
queryset = VirtualDisk.objects.all()
filterset = filtersets.VirtualDiskFilterSet
table = tables.VirtualDiskTable
form = forms.VirtualDiskBulkEditForm
class VirtualDiskBulkDeleteView(generic.BulkDeleteView):
queryset = VirtualDisk.objects.all()
filterset = filtersets.VirtualDiskFilterSet
table = tables.VirtualDiskTable