mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Fixes: #3543 - Adds inline vlan editing to virtual machine interfaces
This commit is contained in:
@ -17,6 +17,7 @@ v2.6.5 (FUTURE)
|
|||||||
* [#3531](https://github.com/netbox-community/netbox/issues/3531) - Fixed rack role foreground color
|
* [#3531](https://github.com/netbox-community/netbox/issues/3531) - Fixed rack role foreground color
|
||||||
* [#3534](https://github.com/netbox-community/netbox/issues/3534) - Added blank option for untagged VLANs
|
* [#3534](https://github.com/netbox-community/netbox/issues/3534) - Added blank option for untagged VLANs
|
||||||
* [#3540](https://github.com/netbox-community/netbox/issues/3540) - Fixed virtual machine interface edit with new inline vlan edit fields
|
* [#3540](https://github.com/netbox-community/netbox/issues/3540) - Fixed virtual machine interface edit with new inline vlan edit fields
|
||||||
|
* [#3543](https://github.com/netbox-community/netbox/issues/3543) - Added inline VLAN editing to virtual machine interfaces
|
||||||
|
|
||||||
v2.6.4 (2019-09-19)
|
v2.6.4 (2019-09-19)
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@ from django import forms
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from taggit.forms import TagField
|
from taggit.forms import TagField
|
||||||
|
|
||||||
from dcim.constants import IFACE_TYPE_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL
|
from dcim.constants import IFACE_TYPE_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL, IFACE_MODE_CHOICES
|
||||||
from dcim.forms import INTERFACE_MODE_HELP_TEXT
|
from dcim.forms import INTERFACE_MODE_HELP_TEXT
|
||||||
from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, Site
|
from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, Site
|
||||||
from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
|
from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
|
||||||
from ipam.models import IPAddress
|
from ipam.models import IPAddress, VLANGroup, VLAN
|
||||||
from tenancy.forms import TenancyForm
|
from tenancy.forms import TenancyForm
|
||||||
from tenancy.forms import TenancyFilterForm
|
from tenancy.forms import TenancyFilterForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
@ -616,6 +616,24 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil
|
|||||||
#
|
#
|
||||||
|
|
||||||
class InterfaceForm(BootstrapMixin, forms.ModelForm):
|
class InterfaceForm(BootstrapMixin, forms.ModelForm):
|
||||||
|
untagged_vlan = forms.ModelChoiceField(
|
||||||
|
queryset=VLAN.objects.all(),
|
||||||
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/ipam/vlans/",
|
||||||
|
display_field='display_name',
|
||||||
|
full=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
tagged_vlans = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=VLAN.objects.all(),
|
||||||
|
required=False,
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/ipam/vlans/",
|
||||||
|
display_field='display_name',
|
||||||
|
full=True
|
||||||
|
)
|
||||||
|
)
|
||||||
tags = TagField(
|
tags = TagField(
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
@ -638,6 +656,39 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm):
|
|||||||
'mode': INTERFACE_MODE_HELP_TEXT,
|
'mode': INTERFACE_MODE_HELP_TEXT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site
|
||||||
|
vlan_choices = []
|
||||||
|
global_vlans = VLAN.objects.filter(site=None, group=None)
|
||||||
|
vlan_choices.append(
|
||||||
|
('Global', [(vlan.pk, vlan) for vlan in global_vlans])
|
||||||
|
)
|
||||||
|
for group in VLANGroup.objects.filter(site=None):
|
||||||
|
global_group_vlans = VLAN.objects.filter(group=group)
|
||||||
|
vlan_choices.append(
|
||||||
|
(group.name, [(vlan.pk, vlan) for vlan in global_group_vlans])
|
||||||
|
)
|
||||||
|
|
||||||
|
site = getattr(self.instance.device, 'site', None)
|
||||||
|
if site is not None:
|
||||||
|
|
||||||
|
# Add non-grouped site VLANs
|
||||||
|
site_vlans = VLAN.objects.filter(site=site, group=None)
|
||||||
|
vlan_choices.append((site.name, [(vlan.pk, vlan) for vlan in site_vlans]))
|
||||||
|
|
||||||
|
# Add grouped site VLANs
|
||||||
|
for group in VLANGroup.objects.filter(site=site):
|
||||||
|
site_group_vlans = VLAN.objects.filter(group=group)
|
||||||
|
vlan_choices.append((
|
||||||
|
'{} / {}'.format(group.site.name, group.name),
|
||||||
|
[(vlan.pk, vlan) for vlan in site_group_vlans]
|
||||||
|
))
|
||||||
|
|
||||||
|
self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices
|
||||||
|
self.fields['tagged_vlans'].choices = vlan_choices
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
@ -681,6 +732,29 @@ class InterfaceCreateForm(ComponentForm):
|
|||||||
max_length=100,
|
max_length=100,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
mode = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(IFACE_MODE_CHOICES),
|
||||||
|
required=False,
|
||||||
|
widget=StaticSelect2(),
|
||||||
|
)
|
||||||
|
untagged_vlan = forms.ModelChoiceField(
|
||||||
|
queryset=VLAN.objects.all(),
|
||||||
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/ipam/vlans/",
|
||||||
|
display_field='display_name',
|
||||||
|
full=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
tagged_vlans = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=VLAN.objects.all(),
|
||||||
|
required=False,
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/ipam/vlans/",
|
||||||
|
display_field='display_name',
|
||||||
|
full=True
|
||||||
|
)
|
||||||
|
)
|
||||||
tags = TagField(
|
tags = TagField(
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
@ -693,6 +767,36 @@ class InterfaceCreateForm(ComponentForm):
|
|||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site
|
||||||
|
vlan_choices = []
|
||||||
|
global_vlans = VLAN.objects.filter(site=None, group=None)
|
||||||
|
vlan_choices.append(
|
||||||
|
('Global', [(vlan.pk, vlan) for vlan in global_vlans])
|
||||||
|
)
|
||||||
|
for group in VLANGroup.objects.filter(site=None):
|
||||||
|
global_group_vlans = VLAN.objects.filter(group=group)
|
||||||
|
vlan_choices.append(
|
||||||
|
(group.name, [(vlan.pk, vlan) for vlan in global_group_vlans])
|
||||||
|
)
|
||||||
|
|
||||||
|
site = getattr(self.parent.cluster, 'site', None)
|
||||||
|
if site is not None:
|
||||||
|
|
||||||
|
# Add non-grouped site VLANs
|
||||||
|
site_vlans = VLAN.objects.filter(site=site, group=None)
|
||||||
|
vlan_choices.append((site.name, [(vlan.pk, vlan) for vlan in site_vlans]))
|
||||||
|
|
||||||
|
# Add grouped site VLANs
|
||||||
|
for group in VLANGroup.objects.filter(site=site):
|
||||||
|
site_group_vlans = VLAN.objects.filter(group=group)
|
||||||
|
vlan_choices.append((
|
||||||
|
'{} / {}'.format(group.site.name, group.name),
|
||||||
|
[(vlan.pk, vlan) for vlan in site_group_vlans]
|
||||||
|
))
|
||||||
|
|
||||||
|
self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices
|
||||||
|
self.fields['tagged_vlans'].choices = vlan_choices
|
||||||
|
|
||||||
|
|
||||||
class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
|
class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
|
||||||
pk = forms.ModelMultipleChoiceField(
|
pk = forms.ModelMultipleChoiceField(
|
||||||
@ -713,12 +817,68 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
|
|||||||
max_length=100,
|
max_length=100,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
mode = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(IFACE_MODE_CHOICES),
|
||||||
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
|
)
|
||||||
|
untagged_vlan = forms.ModelChoiceField(
|
||||||
|
queryset=VLAN.objects.all(),
|
||||||
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/ipam/vlans/",
|
||||||
|
display_field='display_name',
|
||||||
|
full=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
tagged_vlans = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=VLAN.objects.all(),
|
||||||
|
required=False,
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/ipam/vlans/",
|
||||||
|
display_field='display_name',
|
||||||
|
full=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
nullable_fields = [
|
nullable_fields = [
|
||||||
'mtu', 'description',
|
'mtu', 'description',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site
|
||||||
|
vlan_choices = []
|
||||||
|
global_vlans = VLAN.objects.filter(site=None, group=None)
|
||||||
|
vlan_choices.append(
|
||||||
|
('Global', [(vlan.pk, vlan) for vlan in global_vlans])
|
||||||
|
)
|
||||||
|
for group in VLANGroup.objects.filter(site=None):
|
||||||
|
global_group_vlans = VLAN.objects.filter(group=group)
|
||||||
|
vlan_choices.append(
|
||||||
|
(group.name, [(vlan.pk, vlan) for vlan in global_group_vlans])
|
||||||
|
)
|
||||||
|
if self.parent_obj.cluster is not None:
|
||||||
|
site = getattr(self.parent_obj.cluster, 'site', None)
|
||||||
|
if site is not None:
|
||||||
|
|
||||||
|
# Add non-grouped site VLANs
|
||||||
|
site_vlans = VLAN.objects.filter(site=site, group=None)
|
||||||
|
vlan_choices.append((site.name, [(vlan.pk, vlan) for vlan in site_vlans]))
|
||||||
|
|
||||||
|
# Add grouped site VLANs
|
||||||
|
for group in VLANGroup.objects.filter(site=site):
|
||||||
|
site_group_vlans = VLAN.objects.filter(group=group)
|
||||||
|
vlan_choices.append((
|
||||||
|
'{} / {}'.format(group.site.name, group.name),
|
||||||
|
[(vlan.pk, vlan) for vlan in site_group_vlans]
|
||||||
|
))
|
||||||
|
|
||||||
|
self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices
|
||||||
|
self.fields['tagged_vlans'].choices = vlan_choices
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Bulk VirtualMachine component creation
|
# Bulk VirtualMachine component creation
|
||||||
|
Reference in New Issue
Block a user