Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

12336 make region API calls atomic #13942

Merged
merged 7 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions netbox/dcim/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from netbox.api.metadata import ContentTypeMetadata
from netbox.api.pagination import StripCountAnnotationsPaginator
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.constants import NESTED_SERIALIZER_PREFIX
from utilities.api import get_serializer_for_model
Expand Down Expand Up @@ -98,7 +98,7 @@ def paths(self, request, pk):
# Regions
#

class RegionViewSet(NetBoxModelViewSet):
class RegionViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = Region.objects.add_related_count(
Region.objects.all(),
Site,
Expand All @@ -114,7 +114,7 @@ class RegionViewSet(NetBoxModelViewSet):
# Site groups
#

class SiteGroupViewSet(NetBoxModelViewSet):
class SiteGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = SiteGroup.objects.add_related_count(
SiteGroup.objects.all(),
Site,
Expand Down Expand Up @@ -149,7 +149,7 @@ class SiteViewSet(NetBoxModelViewSet):
# Locations
#

class LocationViewSet(NetBoxModelViewSet):
class LocationViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = Location.objects.add_related_count(
Location.objects.add_related_count(
Location.objects.all(),
Expand Down Expand Up @@ -350,7 +350,7 @@ class DeviceBayTemplateViewSet(NetBoxModelViewSet):
filterset_class = filtersets.DeviceBayTemplateFilterSet


class InventoryItemTemplateViewSet(NetBoxModelViewSet):
class InventoryItemTemplateViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = InventoryItemTemplate.objects.prefetch_related('device_type__manufacturer', 'role')
serializer_class = serializers.InventoryItemTemplateSerializer
filterset_class = filtersets.InventoryItemTemplateFilterSet
Expand Down Expand Up @@ -538,7 +538,7 @@ class DeviceBayViewSet(NetBoxModelViewSet):
brief_prefetch_fields = ['device']


class InventoryItemViewSet(NetBoxModelViewSet):
class InventoryItemViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer', 'tags')
serializer_class = serializers.InventoryItemSerializer
filterset_class = filtersets.InventoryItemFilterSet
Expand Down
21 changes: 21 additions & 0 deletions netbox/netbox/api/viewsets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db import transaction
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.response import Response
from rest_framework.viewsets import GenericViewSet
Expand Down Expand Up @@ -157,3 +159,22 @@ def perform_destroy(self, instance):
logger.info(f"Deleting {model._meta.verbose_name} {instance} (PK: {instance.pk})")

return super().perform_destroy(instance)


class MPTTLockedMixin:
"""
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.model_name]):
return super().create(request, *args, **kwargs)

def update(self, request, *args, **kwargs):
with advisory_lock(ADVISORY_LOCK_KEYS[self.queryset.model._meta.model_name]):
return super().update(request, *args, **kwargs)

def destroy(self, request, *args, **kwargs):
with advisory_lock(ADVISORY_LOCK_KEYS[self.queryset.model._meta.model_name]):
return super().destroy(request, *args, **kwargs)
11 changes: 11 additions & 0 deletions netbox/netbox/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,19 @@
# When adding a new key, pick something arbitrary and unique so that it is easily searchable in
# query logs.
ADVISORY_LOCK_KEYS = {
# Available object locks
'available-prefixes': 100100,
'available-ips': 100200,
'available-vlans': 100300,
'available-asns': 100400,

# MPTT locks
'region': 105100,
'sitegroup': 105200,
'location': 105300,
'tenantgroup': 105400,
'contactgroup': 105500,
'wirelesslangroup': 105600,
'inventoryitem': 105700,
'inventoryitemtemplate': 105800,
}
6 changes: 3 additions & 3 deletions netbox/tenancy/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from circuits.models import Circuit
from dcim.models import Device, Rack, Site
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.models import *
from utilities.utils import count_related
Expand All @@ -23,7 +23,7 @@ def get_view_name(self):
# Tenants
#

class TenantGroupViewSet(NetBoxModelViewSet):
class TenantGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = TenantGroup.objects.add_related_count(
TenantGroup.objects.all(),
Tenant,
Expand Down Expand Up @@ -58,7 +58,7 @@ class TenantViewSet(NetBoxModelViewSet):
# Contacts
#

class ContactGroupViewSet(NetBoxModelViewSet):
class ContactGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = ContactGroup.objects.add_related_count(
ContactGroup.objects.all(),
Contact,
Expand Down
4 changes: 2 additions & 2 deletions netbox/wireless/api/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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.models import *
from . import serializers
Expand All @@ -14,7 +14,7 @@ def get_view_name(self):
return 'Wireless'


class WirelessLANGroupViewSet(NetBoxModelViewSet):
class WirelessLANGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = WirelessLANGroup.objects.add_related_count(
WirelessLANGroup.objects.all(),
WirelessLAN,
Expand Down
1 change: 0 additions & 1 deletion netbox/wireless/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from mptt.models import MPTTModel

from dcim.choices import LinkStatusChoices
from dcim.constants import WIRELESS_IFACE_TYPES
Expand Down