Parcourir la source

#6732: Add asns relationship to SiteSerializer and extend tests

jeremystretch il y a 4 ans
Parent
commit
7a55832a22

+ 11 - 7
netbox/dcim/api/serializers.py

@@ -1,4 +1,3 @@
-from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from drf_yasg.utils import swagger_serializer_method
 from rest_framework import serializers
@@ -7,8 +6,8 @@ from timezone_field.rest_framework import TimeZoneSerializerField
 from dcim.choices import *
 from dcim.constants import *
 from dcim.models import *
-from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer, NestedASNSerializer
-from ipam.models import VLAN
+from ipam.api.nested_serializers import NestedASNSerializer, NestedIPAddressSerializer, NestedVLANSerializer
+from ipam.models import ASN, VLAN
 from netbox.api import ChoiceField, ContentTypeField, SerializedPKRelatedField
 from netbox.api.serializers import (
     NestedGroupModelSerializer, PrimaryModelSerializer, ValidatedModelSerializer, WritableNestedSerializer,
@@ -113,13 +112,19 @@ class SiteSerializer(PrimaryModelSerializer):
     region = NestedRegionSerializer(required=False, allow_null=True)
     group = NestedSiteGroupSerializer(required=False, allow_null=True)
     tenant = NestedTenantSerializer(required=False, allow_null=True)
-    asns = NestedASNSerializer(many=True, required=False, allow_null=True)
     time_zone = TimeZoneSerializerField(required=False)
+    asns = SerializedPKRelatedField(
+        queryset=ASN.objects.all(),
+        serializer=NestedASNSerializer,
+        required=False,
+        many=True
+    )
+
+    # Related object counts
     circuit_count = serializers.IntegerField(read_only=True)
     device_count = serializers.IntegerField(read_only=True)
     prefix_count = serializers.IntegerField(read_only=True)
     rack_count = serializers.IntegerField(read_only=True)
-    asn_count = serializers.IntegerField(read_only=True)
     virtualmachine_count = serializers.IntegerField(read_only=True)
     vlan_count = serializers.IntegerField(read_only=True)
 
@@ -129,8 +134,7 @@ class SiteSerializer(PrimaryModelSerializer):
             'id', 'url', 'display', 'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility', 'asn', 'asns',
             'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'contact_name',
             'contact_phone', 'contact_email', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
-            'asn_count', 'circuit_count', 'device_count', 'prefix_count', 'rack_count', 'virtualmachine_count',
-            'vlan_count',
+            'circuit_count', 'device_count', 'prefix_count', 'rack_count', 'virtualmachine_count', 'vlan_count',
         ]
 
 

+ 1 - 2
netbox/dcim/api/views.py

@@ -137,9 +137,8 @@ class SiteGroupViewSet(CustomFieldModelViewSet):
 
 class SiteViewSet(CustomFieldModelViewSet):
     queryset = Site.objects.prefetch_related(
-        'region', 'tenant', 'tags'
+        'region', 'tenant', 'asns', 'tags'
     ).annotate(
-        asn_count=count_related(ASN, 'sites'),
         device_count=count_related(Device, 'site'),
         rack_count=count_related(Rack, 'site'),
         prefix_count=count_related(Prefix, 'site'),

+ 11 - 1
netbox/dcim/tests/test_api.py

@@ -6,7 +6,7 @@ from rest_framework import status
 from dcim.choices import *
 from dcim.constants import *
 from dcim.models import *
-from ipam.models import VLAN
+from ipam.models import ASN, RIR, VLAN
 from utilities.testing import APITestCase, APIViewTestCases
 from virtualization.models import Cluster, ClusterType
 
@@ -143,6 +143,13 @@ class SiteTest(APIViewTestCases.APIViewTestCase):
         )
         Site.objects.bulk_create(sites)
 
+        rir = RIR.objects.create(name='RFC 6996', is_private=True)
+
+        asns = [
+            ASN(asn=65000 + i, rir=rir) for i in range(8)
+        ]
+        ASN.objects.bulk_create(asns)
+
         cls.create_data = [
             {
                 'name': 'Site 4',
@@ -150,6 +157,7 @@ class SiteTest(APIViewTestCases.APIViewTestCase):
                 'region': regions[1].pk,
                 'group': groups[1].pk,
                 'status': SiteStatusChoices.STATUS_ACTIVE,
+                'asns': [asns[0].pk, asns[1].pk],
             },
             {
                 'name': 'Site 5',
@@ -157,6 +165,7 @@ class SiteTest(APIViewTestCases.APIViewTestCase):
                 'region': regions[1].pk,
                 'group': groups[1].pk,
                 'status': SiteStatusChoices.STATUS_ACTIVE,
+                'asns': [asns[2].pk, asns[3].pk],
             },
             {
                 'name': 'Site 6',
@@ -164,6 +173,7 @@ class SiteTest(APIViewTestCases.APIViewTestCase):
                 'region': regions[1].pk,
                 'group': groups[1].pk,
                 'status': SiteStatusChoices.STATUS_ACTIVE,
+                'asns': [asns[4].pk, asns[5].pk],
             },
         ]
 

+ 12 - 28
netbox/dcim/tests/test_views.py

@@ -11,7 +11,7 @@ from netaddr import EUI
 from dcim.choices import *
 from dcim.constants import *
 from dcim.models import *
-from ipam.models import ASN, VLAN, RIR
+from ipam.models import ASN, RIR, VLAN
 from tenancy.models import Tenant
 from utilities.testing import ViewTestCases, create_tags, create_test_device
 
@@ -110,41 +110,24 @@ class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         for group in groups:
             group.save()
 
+        rir = RIR.objects.create(name='RFC 6996', is_private=True)
+
+        asns = [
+            ASN(asn=65000 + i, rir=rir) for i in range(8)
+        ]
+        ASN.objects.bulk_create(asns)
+
         sites = Site.objects.bulk_create([
             Site(name='Site 1', slug='site-1', region=regions[0], group=groups[1]),
             Site(name='Site 2', slug='site-2', region=regions[0], group=groups[1]),
             Site(name='Site 3', slug='site-3', region=regions[0], group=groups[1]),
         ])
+        sites[0].asns.set([asns[0], asns[1]])
+        sites[1].asns.set([asns[2], asns[3]])
+        sites[2].asns.set([asns[4], asns[5]])
 
         tags = create_tags('Alpha', 'Bravo', 'Charlie')
 
-        rir = RIR.objects.create(name='RFC 6996', is_private=True)
-
-        asns = [
-            ASN(asn=65000, rir=rir),
-            ASN(asn=65001, rir=rir),
-            ASN(asn=65002, rir=rir),
-            ASN(asn=65003, rir=rir),
-            ASN(asn=65004, rir=rir),
-            ASN(asn=65005, rir=rir),
-            ASN(asn=65006, rir=rir),
-            ASN(asn=65007, rir=rir),
-            ASN(asn=65008, rir=rir),
-            ASN(asn=65009, rir=rir),
-            ASN(asn=65010, rir=rir),
-        ]
-        ASN.objects.bulk_create(asns)
-
-        asns[0].sites.set([sites[0]])
-        asns[2].sites.set([sites[0]])
-        asns[3].sites.set([sites[1]])
-        asns[4].sites.set([sites[2]])
-        asns[5].sites.set([sites[1]])
-        asns[6].sites.set([sites[2]])
-        asns[7].sites.set([sites[2]])
-        asns[8].sites.set([sites[2]])
-        asns[10].sites.set([sites[0]])
-
         cls.form_data = {
             'name': 'Site X',
             'slug': 'site-x',
@@ -153,6 +136,7 @@ class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'group': groups[1].pk,
             'tenant': None,
             'facility': 'Facility X',
+            'asns': [asns[6].pk, asns[7].pk],
             'time_zone': pytz.UTC,
             'description': 'Site description',
             'physical_address': '742 Evergreen Terrace, Springfield, USA',

+ 0 - 1
netbox/ipam/api/serializers.py

@@ -23,7 +23,6 @@ from .nested_serializers import *
 class ASNSerializer(PrimaryModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail')
     tenant = NestedTenantSerializer(required=False, allow_null=True)
-
     site_count = serializers.IntegerField(read_only=True)
 
     class Meta:

+ 5 - 5
netbox/ipam/models/ip.py

@@ -73,11 +73,12 @@ class RIR(OrganizationalModel):
 
 @extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks')
 class ASN(PrimaryModel):
-
+    """
+    An autonomous system (AS) number is typically used to represent an independent routing domain. A site can have
+    one or more ASNs assigned to it.
+    """
     asn = ASNField(
         unique=True,
-        blank=False,
-        null=False,
         verbose_name='ASN',
         help_text='32-bit autonomous system number'
     )
@@ -89,8 +90,7 @@ class ASN(PrimaryModel):
         to='ipam.RIR',
         on_delete=models.PROTECT,
         related_name='asns',
-        blank=False,
-        null=False
+        verbose_name='RIR'
     )
     tenant = models.ForeignKey(
         to='tenancy.Tenant',