mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-23 07:56:44 -06:00
12336 add locks to all views using mptt models
This commit is contained in:
parent
495b15b291
commit
e9c447ad92
@ -1,6 +1,5 @@
|
|||||||
from django.http import Http404, HttpResponse
|
from django.http import Http404, HttpResponse
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django_pglocks import advisory_lock
|
|
||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_spectacular.utils import extend_schema, OpenApiParameter
|
from drf_spectacular.utils import extend_schema, OpenApiParameter
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
@ -21,9 +20,9 @@ from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
|
|||||||
from netbox.api.metadata import ContentTypeMetadata
|
from netbox.api.metadata import ContentTypeMetadata
|
||||||
from netbox.api.pagination import StripCountAnnotationsPaginator
|
from netbox.api.pagination import StripCountAnnotationsPaginator
|
||||||
from netbox.api.renderers import TextRenderer
|
from netbox.api.renderers import TextRenderer
|
||||||
from netbox.api.viewsets import NetBoxModelViewSet
|
from netbox.api.viewsets import NetBoxModelViewSet, MPTTLockedMixin
|
||||||
from netbox.api.viewsets.mixins import SequentialBulkCreatesMixin
|
from netbox.api.viewsets.mixins import SequentialBulkCreatesMixin
|
||||||
from netbox.constants import NESTED_SERIALIZER_PREFIX, ADVISORY_LOCK_KEYS
|
from netbox.constants import NESTED_SERIALIZER_PREFIX
|
||||||
from utilities.api import get_serializer_for_model
|
from utilities.api import get_serializer_for_model
|
||||||
from utilities.utils import count_related
|
from utilities.utils import count_related
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
@ -99,7 +98,7 @@ class PassThroughPortMixin(object):
|
|||||||
# Regions
|
# Regions
|
||||||
#
|
#
|
||||||
|
|
||||||
class RegionViewSet(NetBoxModelViewSet):
|
class RegionViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||||
queryset = Region.objects.add_related_count(
|
queryset = Region.objects.add_related_count(
|
||||||
Region.objects.all(),
|
Region.objects.all(),
|
||||||
Site,
|
Site,
|
||||||
@ -110,24 +109,12 @@ class RegionViewSet(NetBoxModelViewSet):
|
|||||||
serializer_class = serializers.RegionSerializer
|
serializer_class = serializers.RegionSerializer
|
||||||
filterset_class = filtersets.RegionFilterSet
|
filterset_class = filtersets.RegionFilterSet
|
||||||
|
|
||||||
@advisory_lock(ADVISORY_LOCK_KEYS['regions'])
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
return super().create(request, *args, **kwargs)
|
|
||||||
|
|
||||||
@advisory_lock(ADVISORY_LOCK_KEYS['regions'])
|
|
||||||
def update(self, request, *args, **kwargs):
|
|
||||||
return super().update(request, *args, **kwargs)
|
|
||||||
|
|
||||||
@advisory_lock(ADVISORY_LOCK_KEYS['regions'])
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
|
||||||
return super().destroy(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Site groups
|
# Site groups
|
||||||
#
|
#
|
||||||
|
|
||||||
class SiteGroupViewSet(NetBoxModelViewSet):
|
class SiteGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||||
queryset = SiteGroup.objects.add_related_count(
|
queryset = SiteGroup.objects.add_related_count(
|
||||||
SiteGroup.objects.all(),
|
SiteGroup.objects.all(),
|
||||||
Site,
|
Site,
|
||||||
@ -162,7 +149,7 @@ class SiteViewSet(NetBoxModelViewSet):
|
|||||||
# Locations
|
# Locations
|
||||||
#
|
#
|
||||||
|
|
||||||
class LocationViewSet(NetBoxModelViewSet):
|
class LocationViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||||
queryset = Location.objects.add_related_count(
|
queryset = Location.objects.add_related_count(
|
||||||
Location.objects.add_related_count(
|
Location.objects.add_related_count(
|
||||||
Location.objects.all(),
|
Location.objects.all(),
|
||||||
@ -363,7 +350,7 @@ class DeviceBayTemplateViewSet(NetBoxModelViewSet):
|
|||||||
filterset_class = filtersets.DeviceBayTemplateFilterSet
|
filterset_class = filtersets.DeviceBayTemplateFilterSet
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemTemplateViewSet(NetBoxModelViewSet):
|
class InventoryItemTemplateViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||||
queryset = InventoryItemTemplate.objects.prefetch_related('device_type__manufacturer', 'role')
|
queryset = InventoryItemTemplate.objects.prefetch_related('device_type__manufacturer', 'role')
|
||||||
serializer_class = serializers.InventoryItemTemplateSerializer
|
serializer_class = serializers.InventoryItemTemplateSerializer
|
||||||
filterset_class = filtersets.InventoryItemTemplateFilterSet
|
filterset_class = filtersets.InventoryItemTemplateFilterSet
|
||||||
@ -551,7 +538,7 @@ class DeviceBayViewSet(NetBoxModelViewSet):
|
|||||||
brief_prefetch_fields = ['device']
|
brief_prefetch_fields = ['device']
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemViewSet(NetBoxModelViewSet):
|
class InventoryItemViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||||
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer', 'tags')
|
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer', 'tags')
|
||||||
serializer_class = serializers.InventoryItemSerializer
|
serializer_class = serializers.InventoryItemSerializer
|
||||||
filterset_class = filtersets.InventoryItemFilterSet
|
filterset_class = filtersets.InventoryItemFilterSet
|
||||||
|
@ -3,6 +3,8 @@ import logging
|
|||||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import ProtectedError
|
from django.db.models import ProtectedError
|
||||||
|
from django_pglocks import advisory_lock
|
||||||
|
from netbox.constants import ADVISORY_LOCK_KEYS
|
||||||
from rest_framework import mixins as drf_mixins
|
from rest_framework import mixins as drf_mixins
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import GenericViewSet
|
from rest_framework.viewsets import GenericViewSet
|
||||||
@ -157,3 +159,22 @@ class NetBoxModelViewSet(
|
|||||||
logger.info(f"Deleting {model._meta.verbose_name} {instance} (PK: {instance.pk})")
|
logger.info(f"Deleting {model._meta.verbose_name} {instance} (PK: {instance.pk})")
|
||||||
|
|
||||||
return super().perform_destroy(instance)
|
return super().perform_destroy(instance)
|
||||||
|
|
||||||
|
|
||||||
|
class MPTTLockedMixin(GenericViewSet):
|
||||||
|
"""
|
||||||
|
Puts pglock on objects that derive from MPTTModel for parallel API calling.
|
||||||
|
Note: If adding this to a view, must add the model name to ADVISORY_LOCK_KEYS
|
||||||
|
"""
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
with advisory_lock(ADVISORY_LOCK_KEYS[self.queryset.model._meta.verbose_name.lower()]):
|
||||||
|
return super().create(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def update(self, request, *args, **kwargs):
|
||||||
|
with advisory_lock(ADVISORY_LOCK_KEYS[self.queryset.model._meta.verbose_name.lower()]):
|
||||||
|
return super().update(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def destroy(self, request, *args, **kwargs):
|
||||||
|
with advisory_lock(ADVISORY_LOCK_KEYS[self.queryset.model._meta.verbose_name.lower()]):
|
||||||
|
return super().destroy(request, *args, **kwargs)
|
||||||
|
@ -15,5 +15,14 @@ ADVISORY_LOCK_KEYS = {
|
|||||||
'available-ips': 100200,
|
'available-ips': 100200,
|
||||||
'available-vlans': 100300,
|
'available-vlans': 100300,
|
||||||
'available-asns': 100400,
|
'available-asns': 100400,
|
||||||
'regions': 100500,
|
|
||||||
|
# MPTT locks
|
||||||
|
'region': 100500,
|
||||||
|
'sitegroup': 100501,
|
||||||
|
'location': 100502,
|
||||||
|
'tenantgroup': 100503,
|
||||||
|
'contactgroup': 100504,
|
||||||
|
'wirelesslangroup': 100505,
|
||||||
|
'inventoryitem': 100506,
|
||||||
|
'inventoryitemtemplate': 100507,
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ from rest_framework.routers import APIRootView
|
|||||||
from circuits.models import Circuit
|
from circuits.models import Circuit
|
||||||
from dcim.models import Device, Rack, Site
|
from dcim.models import Device, Rack, Site
|
||||||
from ipam.models import IPAddress, Prefix, VLAN, VRF
|
from ipam.models import IPAddress, Prefix, VLAN, VRF
|
||||||
from netbox.api.viewsets import NetBoxModelViewSet
|
from netbox.api.viewsets import NetBoxModelViewSet, MPTTLockedMixin
|
||||||
from tenancy import filtersets
|
from tenancy import filtersets
|
||||||
from tenancy.models import *
|
from tenancy.models import *
|
||||||
from utilities.utils import count_related
|
from utilities.utils import count_related
|
||||||
@ -23,7 +23,7 @@ class TenancyRootView(APIRootView):
|
|||||||
# Tenants
|
# Tenants
|
||||||
#
|
#
|
||||||
|
|
||||||
class TenantGroupViewSet(NetBoxModelViewSet):
|
class TenantGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||||
queryset = TenantGroup.objects.add_related_count(
|
queryset = TenantGroup.objects.add_related_count(
|
||||||
TenantGroup.objects.all(),
|
TenantGroup.objects.all(),
|
||||||
Tenant,
|
Tenant,
|
||||||
@ -58,7 +58,7 @@ class TenantViewSet(NetBoxModelViewSet):
|
|||||||
# Contacts
|
# Contacts
|
||||||
#
|
#
|
||||||
|
|
||||||
class ContactGroupViewSet(NetBoxModelViewSet):
|
class ContactGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||||
queryset = ContactGroup.objects.add_related_count(
|
queryset = ContactGroup.objects.add_related_count(
|
||||||
ContactGroup.objects.all(),
|
ContactGroup.objects.all(),
|
||||||
Contact,
|
Contact,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from rest_framework.routers import APIRootView
|
from rest_framework.routers import APIRootView
|
||||||
|
|
||||||
from netbox.api.viewsets import NetBoxModelViewSet
|
from netbox.api.viewsets import NetBoxModelViewSet, MPTTLockedMixin
|
||||||
from wireless import filtersets
|
from wireless import filtersets
|
||||||
from wireless.models import *
|
from wireless.models import *
|
||||||
from . import serializers
|
from . import serializers
|
||||||
@ -14,7 +14,7 @@ class WirelessRootView(APIRootView):
|
|||||||
return 'Wireless'
|
return 'Wireless'
|
||||||
|
|
||||||
|
|
||||||
class WirelessLANGroupViewSet(NetBoxModelViewSet):
|
class WirelessLANGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||||
queryset = WirelessLANGroup.objects.add_related_count(
|
queryset = WirelessLANGroup.objects.add_related_count(
|
||||||
WirelessLANGroup.objects.all(),
|
WirelessLANGroup.objects.all(),
|
||||||
WirelessLAN,
|
WirelessLAN,
|
||||||
|
@ -2,7 +2,6 @@ from django.core.exceptions import ValidationError
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from mptt.models import MPTTModel
|
|
||||||
|
|
||||||
from dcim.choices import LinkStatusChoices
|
from dcim.choices import LinkStatusChoices
|
||||||
from dcim.constants import WIRELESS_IFACE_TYPES
|
from dcim.constants import WIRELESS_IFACE_TYPES
|
||||||
|
Loading…
Reference in New Issue
Block a user