From beff774295b82db0cbe56b09650406f03b528d32 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 26 Feb 2019 16:38:49 -0500 Subject: [PATCH 01/10] Fixes #2705: Fix endpoint grouping in API docs --- CHANGELOG.md | 1 + netbox/netbox/views.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2a5445fe..253f54e47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ v2.5.8 (FUTURE) ## Bug Fixes +* [#2705](https://github.com/digitalocean/netbox/issues/2705) - Fix endpoint grouping in API docs * [#2923](https://github.com/digitalocean/netbox/issues/2923) - Provider filter form's site field should be blank by default --- diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index ff11e3892..837d9473d 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -267,6 +267,7 @@ class SearchView(View): class APIRootView(APIView): _ignore_model_permissions = True exclude_from_schema = True + swagger_schema = None def get_view_name(self): return "API Root" From f2471aedb28b232f926ec3f43dddb981d0d404f9 Mon Sep 17 00:00:00 2001 From: dansheps Date: Wed, 27 Feb 2019 11:39:25 -0600 Subject: [PATCH 02/10] Fixes #2781: Fixes filter by regions on site and device list --- netbox/dcim/filters.py | 17 ++++++++++------- netbox/utilities/filters.py | 9 +++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 96ecefafd..b8086322d 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -8,7 +8,9 @@ from netaddr.core import AddrFormatError from extras.filters import CustomFieldFilterSet from tenancy.models import Tenant from utilities.constants import COLOR_CHOICES -from utilities.filters import NameSlugSearchFilterSet, NullableCharFieldFilter, NumericInFilter, TagFilter +from utilities.filters import ( + NameSlugSearchFilterSet, NullableCharFieldFilter, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter +) from virtualization.models import Cluster from .constants import * from .models import ( @@ -49,14 +51,15 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet): choices=SITE_STATUS_CHOICES, null_value=None ) - region_id = django_filters.NumberFilter( - method='filter_region', - field_name='pk', + region_id = TreeNodeMultipleChoiceFilter( + queryset=Region.objects.all(), + field_name='region__in', label='Region (ID)', ) - region = django_filters.CharFilter( - method='filter_region', - field_name='slug', + region = TreeNodeMultipleChoiceFilter( + queryset=Region.objects.all(), + field_name='region__in', + to_field_name='slug', label='Region (slug)', ) tenant_id = django_filters.ModelMultipleChoiceFilter( diff --git a/netbox/utilities/filters.py b/netbox/utilities/filters.py index 40e687077..b0c2b3ec3 100644 --- a/netbox/utilities/filters.py +++ b/netbox/utilities/filters.py @@ -4,6 +4,15 @@ from django.db.models import Q from taggit.models import Tag +class TreeNodeMultipleChoiceFilter(django_filters.ModelMultipleChoiceFilter): + """ + Filters for a set of Models, including all descendant models within a Tree. Example: [,] + """ + def filter(self, qs, value): + value = [node.get_descendants(include_self=True) for node in value] + return super().filter(qs, value) + + class NumericInFilter(django_filters.BaseInFilter, django_filters.NumberFilter): """ Filters for a set of numeric values. Example: id__in=100,200,300 From 00aaf500de1ac67bcba46fbcc75d9ea51cf6ddca Mon Sep 17 00:00:00 2001 From: dansheps Date: Wed, 27 Feb 2019 14:46:11 -0600 Subject: [PATCH 03/10] Fixes #2781: Fixes filter by regions on site and device list * Add Device filter --- netbox/dcim/filters.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index b8086322d..d06a65ad3 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -98,16 +98,6 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet): pass return queryset.filter(qs_filter) - def filter_region(self, queryset, name, value): - try: - region = Region.objects.get(**{name: value}) - except ObjectDoesNotExist: - return queryset.none() - return queryset.filter( - Q(region=region) | - Q(region__in=region.get_descendants()) - ) - class RackGroupFilter(NameSlugSearchFilterSet): site_id = django_filters.ModelMultipleChoiceFilter( @@ -516,14 +506,15 @@ class DeviceFilter(CustomFieldFilterSet): ) name = NullableCharFieldFilter() asset_tag = NullableCharFieldFilter() - region_id = django_filters.NumberFilter( - method='filter_region', - field_name='pk', + region_id = TreeNodeMultipleChoiceFilter( + queryset=Region.objects.all(), + field_name='region__in', label='Region (ID)', ) - region = django_filters.CharFilter( - method='filter_region', - field_name='slug', + region = TreeNodeMultipleChoiceFilter( + queryset=Region.objects.all(), + field_name='region__in', + to_field_name='slug', label='Region (slug)', ) site_id = django_filters.ModelMultipleChoiceFilter( From 32f63a18ff4f0edf8cd165459cd9da7a13b2dd0f Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 28 Feb 2019 09:49:23 -0500 Subject: [PATCH 04/10] Fixes #2938: Enforce deterministic ordering of device components returned by API --- CHANGELOG.md | 1 + netbox/dcim/managers.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 253f54e47..f1c42a976 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ v2.5.8 (FUTURE) * [#2705](https://github.com/digitalocean/netbox/issues/2705) - Fix endpoint grouping in API docs * [#2923](https://github.com/digitalocean/netbox/issues/2923) - Provider filter form's site field should be blank by default +* [#2938](https://github.com/digitalocean/netbox/issues/2938) - Enforce deterministic ordering of device components returned by API --- diff --git a/netbox/dcim/managers.py b/netbox/dcim/managers.py index 52df1afe8..feaa09d74 100644 --- a/netbox/dcim/managers.py +++ b/netbox/dcim/managers.py @@ -27,7 +27,7 @@ class DeviceComponentManager(Manager): select={ 'name_padded': sql.format(table_name, table_name), } - ).order_by('name_padded') + ).order_by('name_padded', 'pk') class InterfaceQuerySet(QuerySet): From 3e6033e9ff0adb7942e420e0d83f6166a1057756 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 28 Feb 2019 09:59:17 -0500 Subject: [PATCH 05/10] Fixes #2938: Exclude circuit terminations from API interface connections endpoint --- CHANGELOG.md | 1 + netbox/dcim/api/views.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1c42a976..82949ff16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ v2.5.8 (FUTURE) * [#2705](https://github.com/digitalocean/netbox/issues/2705) - Fix endpoint grouping in API docs * [#2923](https://github.com/digitalocean/netbox/issues/2923) - Provider filter form's site field should be blank by default * [#2938](https://github.com/digitalocean/netbox/issues/2938) - Enforce deterministic ordering of device components returned by API +* [#2939](https://github.com/digitalocean/netbox/issues/2939) - Exclude circuit terminations from API interface connections endpoint --- diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 4e14d8163..8fddc7129 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -496,11 +496,11 @@ class PowerConnectionViewSet(ListModelMixin, GenericViewSet): class InterfaceConnectionViewSet(ListModelMixin, GenericViewSet): queryset = Interface.objects.select_related( - 'device', '_connected_interface', '_connected_circuittermination' + 'device', '_connected_interface__device' ).filter( # Avoid duplicate connections by only selecting the lower PK in a connected pair - Q(_connected_interface__isnull=False, pk__lt=F('_connected_interface')) | - Q(_connected_circuittermination__isnull=False) + _connected_interface__isnull=False, + pk__lt=F('_connected_interface') ) serializer_class = serializers.InterfaceConnectionSerializer filterset_class = filters.InterfaceConnectionFilter From 6f5c35c2781a1dab157313b1ef87de2ae8de92be Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 28 Feb 2019 11:40:32 -0500 Subject: [PATCH 06/10] Force resolution of request User object when logging an object deletion (resolves intermittent test failures) --- netbox/extras/middleware.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/netbox/extras/middleware.py b/netbox/extras/middleware.py index 16461c32a..38dde6275 100644 --- a/netbox/extras/middleware.py +++ b/netbox/extras/middleware.py @@ -29,7 +29,11 @@ def cache_changed_object(instance, **kwargs): def _record_object_deleted(request, instance, **kwargs): - # Record that the object was deleted. + # Force resolution of request.user in case it's still a SimpleLazyObject. This seems to happen + # occasionally during tests, but haven't been able to determine why. + assert request.user.is_authenticated + + # Record that the object was deleted if hasattr(instance, 'log_change'): instance.log_change(request.user, request.id, OBJECTCHANGE_ACTION_DELETE) From b381bdec271167641718c472b78167e50622454f Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sun, 3 Mar 2019 18:52:57 -0500 Subject: [PATCH 07/10] fixes #2952 - slug field absent from TenantFilter --- CHANGELOG.md | 1 + netbox/tenancy/filters.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82949ff16..82df28edc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ v2.5.8 (FUTURE) * [#2923](https://github.com/digitalocean/netbox/issues/2923) - Provider filter form's site field should be blank by default * [#2938](https://github.com/digitalocean/netbox/issues/2938) - Enforce deterministic ordering of device components returned by API * [#2939](https://github.com/digitalocean/netbox/issues/2939) - Exclude circuit terminations from API interface connections endpoint +* [#2952](https://github.com/digitalocean/netbox/issues/2952) - Added the `slug` field to the Tenant filter for use in the API and search function --- diff --git a/netbox/tenancy/filters.py b/netbox/tenancy/filters.py index 745391898..2610b3ec0 100644 --- a/netbox/tenancy/filters.py +++ b/netbox/tenancy/filters.py @@ -36,13 +36,14 @@ class TenantFilter(CustomFieldFilterSet, django_filters.FilterSet): class Meta: model = Tenant - fields = ['name'] + fields = ['name', 'slug'] def search(self, queryset, name, value): if not value.strip(): return queryset return queryset.filter( Q(name__icontains=value) | + Q(slug__icontains=value) | Q(description__icontains=value) | Q(comments__icontains=value) ) From 4d18d9661b641b60a7da94671bbd3cb625e036f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=20V=C3=AEjdea?= Date: Mon, 4 Mar 2019 03:20:47 +0200 Subject: [PATCH 08/10] Remove trailing slashes from filesystem paths Paths with trailing slashes do not work on windows, they cause errors such as `django.core.exceptions.SuspiciousFileOperation: The joined path (C:\Projects\netbox\netbox\static\clipboard-2.0.4.min.js) is located outside of the base path component (C:\Projects\netbox\netbox\static\)`. --- netbox/netbox/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index a85a5d78e..c2622998f 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -197,7 +197,7 @@ ROOT_URLCONF = 'netbox.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [BASE_DIR + '/templates/'], + 'DIRS': [BASE_DIR + '/templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -223,7 +223,7 @@ USE_I18N = True USE_TZ = True # Static files (CSS, JavaScript, Images) -STATIC_ROOT = BASE_DIR + '/static/' +STATIC_ROOT = BASE_DIR + '/static' STATIC_URL = '/{}static/'.format(BASE_PATH) STATICFILES_DIRS = ( os.path.join(BASE_DIR, "project-static"), From 78725b8483a6920620f5125ccb8fdd2a07d48218 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 4 Mar 2019 14:57:35 -0500 Subject: [PATCH 09/10] Follow-up from #2781 --- CHANGELOG.md | 1 + netbox/dcim/filters.py | 15 ++------------- netbox/virtualization/filters.py | 25 ++++++++----------------- 3 files changed, 11 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82df28edc..a2acd88dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ v2.5.8 (FUTURE) ## Bug Fixes * [#2705](https://github.com/digitalocean/netbox/issues/2705) - Fix endpoint grouping in API docs +* [#2781](https://github.com/digitalocean/netbox/issues/2781) - Fix filtering of sites/devices/VMs by multiple regions * [#2923](https://github.com/digitalocean/netbox/issues/2923) - Provider filter form's site field should be blank by default * [#2938](https://github.com/digitalocean/netbox/issues/2938) - Enforce deterministic ordering of device components returned by API * [#2939](https://github.com/digitalocean/netbox/issues/2939) - Exclude circuit terminations from API interface connections endpoint diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index d06a65ad3..dda904f1c 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -1,6 +1,5 @@ import django_filters from django.contrib.auth.models import User -from django.core.exceptions import ObjectDoesNotExist from django.db.models import Q from netaddr import EUI from netaddr.core import AddrFormatError @@ -508,12 +507,12 @@ class DeviceFilter(CustomFieldFilterSet): asset_tag = NullableCharFieldFilter() region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), - field_name='region__in', + field_name='site__region__in', label='Region (ID)', ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), - field_name='region__in', + field_name='site__region__in', to_field_name='slug', label='Region (slug)', ) @@ -613,16 +612,6 @@ class DeviceFilter(CustomFieldFilterSet): Q(comments__icontains=value) ).distinct() - def filter_region(self, queryset, name, value): - try: - region = Region.objects.get(**{name: value}) - except ObjectDoesNotExist: - return queryset.none() - return queryset.filter( - Q(site__region=region) | - Q(site__region__in=region.get_descendants()) - ) - def _mac_address(self, queryset, name, value): value = value.strip() if not value: diff --git a/netbox/virtualization/filters.py b/netbox/virtualization/filters.py index 0b7e57ba7..0e5ff6cd2 100644 --- a/netbox/virtualization/filters.py +++ b/netbox/virtualization/filters.py @@ -7,7 +7,7 @@ from netaddr.core import AddrFormatError from dcim.models import DeviceRole, Interface, Platform, Region, Site from extras.filters import CustomFieldFilterSet from tenancy.models import Tenant -from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter +from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter from .constants import VM_STATUS_CHOICES from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine @@ -119,14 +119,15 @@ class VirtualMachineFilter(CustomFieldFilterSet): queryset=Cluster.objects.all(), label='Cluster (ID)', ) - region_id = django_filters.NumberFilter( - method='filter_region', - field_name='pk', + region_id = TreeNodeMultipleChoiceFilter( + queryset=Region.objects.all(), + field_name='cluster__site__region__in', label='Region (ID)', ) - region = django_filters.CharFilter( - method='filter_region', - field_name='slug', + region = TreeNodeMultipleChoiceFilter( + queryset=Region.objects.all(), + field_name='cluster__site__region__in', + to_field_name='slug', label='Region (slug)', ) site_id = django_filters.ModelMultipleChoiceFilter( @@ -184,16 +185,6 @@ class VirtualMachineFilter(CustomFieldFilterSet): Q(comments__icontains=value) ) - def filter_region(self, queryset, name, value): - try: - region = Region.objects.get(**{name: value}) - except ObjectDoesNotExist: - return queryset.none() - return queryset.filter( - Q(cluster__site__region=region) | - Q(cluster__site__region__in=region.get_descendants()) - ) - class InterfaceFilter(django_filters.FilterSet): q = django_filters.CharFilter( From 0c142f207832cb563bed654fd21bcda0bb7aff59 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 4 Mar 2019 15:16:35 -0500 Subject: [PATCH 10/10] Changelog for #2954 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2acd88dc..d96ca2ad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ v2.5.8 (FUTURE) * [#2938](https://github.com/digitalocean/netbox/issues/2938) - Enforce deterministic ordering of device components returned by API * [#2939](https://github.com/digitalocean/netbox/issues/2939) - Exclude circuit terminations from API interface connections endpoint * [#2952](https://github.com/digitalocean/netbox/issues/2952) - Added the `slug` field to the Tenant filter for use in the API and search function +* [#2954](https://github.com/digitalocean/netbox/issues/2954) - Remove trailing slashes to fix root/template paths on Windows ---