diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index edd1867ed..132094325 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -980,21 +980,65 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet): to_field_name='slug', label='L2VPN (slug)', ) - device = MultiValueCharFilter( - method='filter_device', - field_name='name', - label='Device (name)', + region = MultiValueCharFilter( + method='filter_region', + field_name='slug', + label='Region (slug)', ) - device_id = MultiValueNumberFilter( - method='filter_device', + region_id = MultiValueNumberFilter( + method='filter_region', + field_name='pk', + label='Region (ID)', + ) + site = MultiValueCharFilter( + method='filter_site', + field_name='slug', + label='Device (slug)', + ) + site_id = MultiValueNumberFilter( + method='filter_site', field_name='pk', label='Device (ID)', ) + device = django_filters.ModelMultipleChoiceFilter( + field_name='interface__device__name', + queryset=Device.objects.all(), + to_field_name='name', + label='Device (name)', + ) + 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 diff --git a/netbox/ipam/forms/filtersets.py b/netbox/ipam/forms/filtersets.py index 384a4da33..d93bd16d0 100644 --- a/netbox/ipam/forms/filtersets.py +++ b/netbox/ipam/forms/filtersets.py @@ -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_type_id', )), + ('Assigned Object', ('region_id', 'site_id', 'device_id', 'virtual_machine_id', 'vlan_id')), ) l2vpn_id = DynamicModelChoiceField( queryset=L2VPN.objects.all(), @@ -520,3 +521,44 @@ class L2VPNTerminationFilterForm(NetBoxModelFilterSetForm): required=False, label='Object type' ) + 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') + ) diff --git a/netbox/ipam/models/l2vpn.py b/netbox/ipam/models/l2vpn.py index 5d85fe915..5adf5e05d 100644 --- a/netbox/ipam/models/l2vpn.py +++ b/netbox/ipam/models/l2vpn.py @@ -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 diff --git a/netbox/ipam/tables/l2vpn.py b/netbox/ipam/tables/l2vpn.py index 5be525343..e2eae7a32 100644 --- a/netbox/ipam/tables/l2vpn.py +++ b/netbox/ipam/tables/l2vpn.py @@ -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')