Merge pull request #9904 from netbox-community/9888-site_device_filters

Fixes: #9888 - Add filter and columns for device and site
This commit is contained in:
Jeremy Stretch 2022-08-03 13:31:58 -04:00 committed by GitHub
commit 44850feaf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 161 additions and 20 deletions

View File

@ -980,21 +980,65 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
to_field_name='slug',
label='L2VPN (slug)',
)
device = MultiValueCharFilter(
method='filter_device',
field_name='name',
region = MultiValueCharFilter(
method='filter_region',
field_name='slug',
label='Region (slug)',
)
region_id = MultiValueNumberFilter(
method='filter_region',
field_name='pk',
label='Region (ID)',
)
site = MultiValueCharFilter(
method='filter_site',
field_name='slug',
label='Site (slug)',
)
site_id = MultiValueNumberFilter(
method='filter_site',
field_name='pk',
label='Site (ID)',
)
device = django_filters.ModelMultipleChoiceFilter(
field_name='interface__device__name',
queryset=Device.objects.all(),
to_field_name='name',
label='Device (name)',
)
device_id = MultiValueNumberFilter(
method='filter_device',
field_name='pk',
device_id = django_filters.ModelMultipleChoiceFilter(
field_name='interface__device',
queryset=Device.objects.all(),
label='Device (ID)',
)
virtual_machine = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface__virtual_machine__name',
queryset=VirtualMachine.objects.all(),
to_field_name='name',
label='Virtual machine (name)',
)
virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface__virtual_machine',
queryset=VirtualMachine.objects.all(),
label='Virtual machine (ID)',
)
interface = django_filters.ModelMultipleChoiceFilter(
field_name='interface__name',
queryset=Interface.objects.all(),
to_field_name='name',
label='Interface (name)',
)
interface_id = django_filters.ModelMultipleChoiceFilter(
field_name='interface',
queryset=Interface.objects.all(),
label='Interface (ID)',
)
vminterface = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface__name',
queryset=VMInterface.objects.all(),
to_field_name='name',
label='VM interface (name)',
)
vminterface_id = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface',
queryset=VMInterface.objects.all(),
@ -1027,13 +1071,22 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
qs_filter = Q(l2vpn__name__icontains=value)
return queryset.filter(qs_filter)
def filter_device(self, queryset, name, value):
devices = Device.objects.filter(**{'{}__in'.format(name): value})
if not devices.exists():
return queryset.none()
interface_ids = []
for device in devices:
interface_ids.extend(device.vc_interfaces().values_list('id', flat=True))
return queryset.filter(
interface__in=interface_ids
def filter_site(self, queryset, name, value):
qs = queryset.filter(
Q(
Q(**{'vlan__site__{}__in'.format(name): value}) |
Q(**{'interface__device__site__{}__in'.format(name): value}) |
Q(**{'vminterface__virtual_machine__site__{}__in'.format(name): value})
)
)
return qs
def filter_region(self, queryset, name, value):
qs = queryset.filter(
Q(
Q(**{'vlan__site__region__{}__in'.format(name): value}) |
Q(**{'interface__device__site__region__{}__in'.format(name): value}) |
Q(**{'vminterface__virtual_machine__site__region__{}__in'.format(name): value})
)
)
return qs

View File

@ -11,7 +11,7 @@ from netbox.forms import NetBoxModelFilterSetForm
from tenancy.forms import TenancyFilterForm
from utilities.forms import (
add_blank_choice, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
MultipleChoiceField, StaticSelect, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
MultipleChoiceField, StaticSelect, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES, APISelectMultiple,
)
from virtualization.models import VirtualMachine
@ -508,7 +508,8 @@ class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
class L2VPNTerminationFilterForm(NetBoxModelFilterSetForm):
model = L2VPNTermination
fieldsets = (
(None, ('l2vpn_id', 'assigned_object_type_id')),
(None, ('l2vpn_id', )),
('Assigned Object', ('assigned_object_type_id', 'region_id', 'site_id', 'device_id', 'virtual_machine_id', 'vlan_id')),
)
l2vpn_id = DynamicModelChoiceField(
queryset=L2VPN.objects.all(),
@ -516,7 +517,49 @@ class L2VPNTerminationFilterForm(NetBoxModelFilterSetForm):
label='L2VPN'
)
assigned_object_type_id = ContentTypeMultipleChoiceField(
queryset=ContentType.objects.all(),
queryset=ContentType.objects.filter(L2VPN_ASSIGNMENT_MODELS),
required=False,
label='Object type'
label=_('Assigned Object Type'),
limit_choices_to=L2VPN_ASSIGNMENT_MODELS
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
required=False,
label=_('Region')
)
site_id = DynamicModelMultipleChoiceField(
queryset=Site.objects.all(),
required=False,
null_option='None',
query_params={
'region_id': '$region_id'
},
label=_('Site')
)
device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False,
null_option='None',
query_params={
'site_id': '$site_id'
},
label=_('Device')
)
vlan_id = DynamicModelMultipleChoiceField(
queryset=VLAN.objects.all(),
required=False,
null_option='None',
query_params={
'site_id': '$site_id'
},
label=_('VLAN')
)
virtual_machine_id = DynamicModelMultipleChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
null_option='None',
query_params={
'site_id': '$site_id'
},
label=_('Virtual Machine')
)

View File

@ -113,3 +113,18 @@ class L2VPNTermination(NetBoxModel):
f'{l2vpn_type} L2VPNs cannot have more than two terminations; found {terminations_count} already '
f'defined.'
)
@property
def assigned_object_parent(self):
obj_type = ContentType.objects.get_for_model(self.assigned_object)
if obj_type.model == 'vminterface':
return self.assigned_object.virtual_machine
elif obj_type.model == 'interface':
return self.assigned_object.device
elif obj_type.model == 'vminterface':
return self.assigned_object.virtual_machine
return None
@property
def assigned_object_site(self):
return self.assigned_object_parent.site

View File

@ -53,8 +53,17 @@ class L2VPNTerminationTable(NetBoxTable):
linkify=True,
orderable=False
)
assigned_object_parent = tables.Column(
linkify=True,
orderable=False
)
assigned_object_site = tables.Column(
linkify=True,
orderable=False
)
class Meta(NetBoxTable.Meta):
model = L2VPNTermination
fields = ('pk', 'l2vpn', 'assigned_object_type', 'assigned_object', 'actions')
fields = ('pk', 'l2vpn', 'assigned_object_type', 'assigned_object', 'assigned_object_parent',
'assigned_object_site', 'actions')
default_columns = ('pk', 'l2vpn', 'assigned_object_type', 'assigned_object', 'actions')

View File

@ -1600,3 +1600,24 @@ class L2VPNTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'vlan': ['VLAN 1', 'VLAN 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_site(self):
site = Site.objects.all().first()
params = {'site_id': [site.pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
params = {'site': ['site-1']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
def test_device(self):
device = Device.objects.all().first()
params = {'device_id': [device.pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
params = {'device': ['Device 1']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
def test_virtual_machine(self):
virtual_machine = VirtualMachine.objects.all().first()
params = {'virtual_machine_id': [virtual_machine.pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
params = {'virtual_machine': ['Virtual Machine 1']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)