Files
netbox/netbox/virtualization/forms/bulk_edit.py

342 lines
11 KiB
Python

from django import forms
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from dcim.choices import InterfaceModeChoices
from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
from dcim.forms.mixins import ScopedBulkEditForm
from dcim.models import Device, DeviceRole, Platform, Site
from extras.models import ConfigTemplate
from ipam.models import VLAN, VRF, VLANGroup, VLANTranslationPolicy
from netbox.forms import NetBoxModelBulkEditForm, OrganizationalModelBulkEditForm, PrimaryModelBulkEditForm
from netbox.forms.mixins import OwnerMixin
from tenancy.models import Tenant
from utilities.forms import BulkRenameForm, add_blank_choice
from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField
from utilities.forms.rendering import FieldSet
from utilities.forms.utils import get_capacity_unit_label
from utilities.forms.widgets import BulkEditNullBooleanSelect
from virtualization.choices import *
from virtualization.models import *
__all__ = (
'ClusterBulkEditForm',
'ClusterGroupBulkEditForm',
'ClusterTypeBulkEditForm',
'VMInterfaceBulkEditForm',
'VMInterfaceBulkRenameForm',
'VirtualDiskBulkEditForm',
'VirtualDiskBulkRenameForm',
'VirtualMachineBulkEditForm',
)
class ClusterTypeBulkEditForm(OrganizationalModelBulkEditForm):
model = ClusterType
fieldsets = (
FieldSet('description'),
)
nullable_fields = ('description', 'comments')
class ClusterGroupBulkEditForm(OrganizationalModelBulkEditForm):
model = ClusterGroup
fieldsets = (
FieldSet('description'),
)
nullable_fields = ('description', 'comments')
class ClusterBulkEditForm(ScopedBulkEditForm, PrimaryModelBulkEditForm):
type = DynamicModelChoiceField(
label=_('Type'),
queryset=ClusterType.objects.all(),
required=False
)
group = DynamicModelChoiceField(
label=_('Group'),
queryset=ClusterGroup.objects.all(),
required=False
)
status = forms.ChoiceField(
label=_('Status'),
choices=add_blank_choice(ClusterStatusChoices),
required=False,
initial=''
)
tenant = DynamicModelChoiceField(
label=_('Tenant'),
queryset=Tenant.objects.all(),
required=False
)
model = Cluster
fieldsets = (
FieldSet('type', 'group', 'status', 'tenant', 'description'),
FieldSet('scope_type', 'scope', name=_('Scope')),
)
nullable_fields = (
'group', 'scope', 'tenant', 'description', 'comments',
)
class VirtualMachineBulkEditForm(PrimaryModelBulkEditForm):
status = forms.ChoiceField(
label=_('Status'),
choices=add_blank_choice(VirtualMachineStatusChoices),
required=False,
initial='',
)
start_on_boot = forms.ChoiceField(
label=_('Start on boot'),
choices=add_blank_choice(VirtualMachineStartOnBootChoices),
required=False,
initial='',
)
site = DynamicModelChoiceField(
label=_('Site'),
queryset=Site.objects.all(),
required=False
)
cluster = DynamicModelChoiceField(
label=_('Cluster'),
queryset=Cluster.objects.all(),
required=False,
query_params={
'site_id': '$site'
}
)
device = DynamicModelChoiceField(
label=_('Device'),
queryset=Device.objects.all(),
required=False,
query_params={
'cluster_id': '$cluster'
}
)
role = DynamicModelChoiceField(
label=_('Role'),
queryset=DeviceRole.objects.filter(
vm_role=True
),
required=False,
query_params={
"vm_role": "True"
}
)
tenant = DynamicModelChoiceField(
label=_('Tenant'),
queryset=Tenant.objects.all(),
required=False
)
platform = DynamicModelChoiceField(
label=_('Platform'),
queryset=Platform.objects.all(),
required=False
)
vcpus = forms.IntegerField(
required=False,
label=_('vCPUs')
)
memory = forms.IntegerField(
required=False,
label=_('Memory')
)
disk = forms.IntegerField(
required=False,
label=_('Disk')
)
config_template = DynamicModelChoiceField(
queryset=ConfigTemplate.objects.all(),
required=False
)
model = VirtualMachine
fieldsets = (
FieldSet('site', 'cluster', 'device', 'status', 'start_on_boot', 'role', 'tenant', 'platform', 'description'),
FieldSet('vcpus', 'memory', 'disk', name=_('Resources')),
FieldSet('config_template', name=_('Configuration')),
)
nullable_fields = (
'site', 'cluster', 'device', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'description', 'comments',
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Set unit labels based on configured RAM_BASE_UNIT / DISK_BASE_UNIT (MB vs MiB)
self.fields['memory'].label = _('Memory ({unit})').format(unit=get_capacity_unit_label(settings.RAM_BASE_UNIT))
self.fields['disk'].label = _('Disk ({unit})').format(unit=get_capacity_unit_label(settings.DISK_BASE_UNIT))
class VMInterfaceBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
virtual_machine = forms.ModelChoiceField(
label=_('Virtual machine'),
queryset=VirtualMachine.objects.all(),
required=False,
disabled=True,
widget=forms.HiddenInput()
)
parent = DynamicModelChoiceField(
label=_('Parent'),
queryset=VMInterface.objects.all(),
required=False
)
bridge = DynamicModelChoiceField(
label=_('Bridge'),
queryset=VMInterface.objects.all(),
required=False
)
enabled = forms.NullBooleanField(
label=_('Enabled'),
required=False,
widget=BulkEditNullBooleanSelect()
)
mtu = forms.IntegerField(
required=False,
min_value=INTERFACE_MTU_MIN,
max_value=INTERFACE_MTU_MAX,
label=_('MTU')
)
description = forms.CharField(
label=_('Description'),
max_length=100,
required=False
)
mode = forms.ChoiceField(
label=_('Mode'),
choices=add_blank_choice(InterfaceModeChoices),
required=False
)
vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(),
required=False,
label=_('VLAN group')
)
untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(),
required=False,
query_params={
'group_id': '$vlan_group',
},
label=_('Untagged VLAN')
)
tagged_vlans = DynamicModelMultipleChoiceField(
queryset=VLAN.objects.all(),
required=False,
query_params={
'group_id': '$vlan_group',
},
label=_('Tagged VLANs')
)
vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(),
required=False,
label=_('VRF')
)
vlan_translation_policy = DynamicModelChoiceField(
queryset=VLANTranslationPolicy.objects.all(),
required=False,
label=_('VLAN Translation Policy')
)
model = VMInterface
fieldsets = (
FieldSet('mtu', 'enabled', 'vrf', 'description'),
FieldSet('parent', 'bridge', name=_('Related Interfaces')),
FieldSet(
'mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans', 'vlan_translation_policy',
name=_('802.1Q Switching')
),
)
nullable_fields = (
'parent', 'bridge', 'mtu', 'vrf', 'description', 'vlan_translation_policy',
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if 'virtual_machine' in self.initial:
vm_id = self.initial.get('virtual_machine')
# Restrict parent/bridge interface assignment by VM
self.fields['parent'].widget.add_query_param('virtual_machine_id', vm_id)
self.fields['bridge'].widget.add_query_param('virtual_machine_id', vm_id)
# Limit VLAN choices by virtual machine
self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id)
self.fields['tagged_vlans'].widget.add_query_param('available_on_virtualmachine', vm_id)
else:
# See 5643
if 'pk' in self.initial:
site = None
interfaces = VMInterface.objects.filter(
pk__in=self.initial['pk']
).prefetch_related(
'virtual_machine__site'
)
# Check interface sites. First interface should set site, further interfaces will either continue the
# loop or reset back to no site and break the loop.
for interface in interfaces:
vm_site = interface.virtual_machine.site or interface.virtual_machine.cluster._site
if site is None:
site = vm_site
elif vm_site is not site:
site = None
break
if site is not None:
self.fields['untagged_vlan'].widget.add_query_param('site_id', site.pk)
self.fields['tagged_vlans'].widget.add_query_param('site_id', site.pk)
self.fields['parent'].choices = ()
self.fields['parent'].widget.attrs['disabled'] = True
self.fields['bridge'].choices = ()
self.fields['bridge'].widget.attrs['disabled'] = True
class VMInterfaceBulkRenameForm(BulkRenameForm):
pk = forms.ModelMultipleChoiceField(
queryset=VMInterface.objects.all(),
widget=forms.MultipleHiddenInput()
)
class VirtualDiskBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
virtual_machine = forms.ModelChoiceField(
label=_('Virtual machine'),
queryset=VirtualMachine.objects.all(),
required=False,
disabled=True,
widget=forms.HiddenInput()
)
size = forms.IntegerField(
required=False,
label=_('Size')
)
description = forms.CharField(
label=_('Description'),
max_length=100,
required=False
)
model = VirtualDisk
fieldsets = (
FieldSet('size', 'description'),
)
nullable_fields = ('description',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Set unit label based on configured DISK_BASE_UNIT (MB vs MiB)
self.fields['size'].label = _('Size ({unit})').format(unit=get_capacity_unit_label(settings.DISK_BASE_UNIT))
class VirtualDiskBulkRenameForm(BulkRenameForm):
pk = forms.ModelMultipleChoiceField(
queryset=VirtualDisk.objects.all(),
widget=forms.MultipleHiddenInput()
)