Explorar o código

Closes #2805: Allow null route distinguisher for VRFs

Jeremy Stretch %!s(int64=7) %!d(string=hai) anos
pai
achega
bcfa760cf9

+ 1 - 0
CHANGELOG.md

@@ -2,6 +2,7 @@ v2.5.5 (FUTURE)
 
 
 ## Enhancements
 ## Enhancements
 
 
+* [#2805](https://github.com/digitalocean/netbox/issues/2805) - Allow null route distinguisher for VRFs
 * [#2809](https://github.com/digitalocean/netbox/issues/2809) - Remove VRF child prefixes table; link to main prefixes view
 * [#2809](https://github.com/digitalocean/netbox/issues/2809) - Remove VRF child prefixes table; link to main prefixes view
 * [#2825](https://github.com/digitalocean/netbox/issues/2825) - Include directly connected device for front/rear ports
 * [#2825](https://github.com/digitalocean/netbox/issues/2825) - Include directly connected device for front/rear ports
 
 

+ 1 - 1
docs/core-functionality/ipam.md

@@ -83,7 +83,7 @@ An IP address can be designated as the network address translation (NAT) inside
 
 
 A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space).
 A VRF object in NetBox represents a virtual routing and forwarding (VRF) domain. Each VRF is essentially a separate routing table. VRFs are commonly used to isolate customers or organizations from one another within a network, or to route overlapping address space (e.g. multiple instances of the 10.0.0.0/8 space).
 
 
-Each VRF is assigned a unique name and route distinguisher (RD). The RD is expected to take one of the forms prescribed in [RFC 4364](https://tools.ietf.org/html/rfc4364#section-4.2), however its formatting is not strictly enforced.
+Each VRF is assigned a unique name and an optional route distinguisher (RD). The RD is expected to take one of the forms prescribed in [RFC 4364](https://tools.ietf.org/html/rfc4364#section-4.2), however its formatting is not strictly enforced.
 
 
 Each prefix and IP address may be assigned to one (and only one) VRF. If you have a prefix or IP address which exists in multiple VRFs, you will need to create a separate instance of it in NetBox for each VRF. Any IP prefix or address not assigned to a VRF is said to belong to the "global" table.
 Each prefix and IP address may be assigned to one (and only one) VRF. If you have a prefix or IP address which exists in multiple VRFs, you will need to create a separate instance of it in NetBox for each VRF. Any IP prefix or address not assigned to a VRF is said to belong to the "global" table.
 
 

+ 18 - 0
netbox/ipam/migrations/0024_vrf_allow_null_rd.py

@@ -0,0 +1,18 @@
+# Generated by Django 2.1.5 on 2019-01-31 18:14
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('ipam', '0023_change_logging'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='vrf',
+            name='rd',
+            field=models.CharField(blank=True, max_length=21, null=True, unique=True),
+        ),
+    ]

+ 2 - 0
netbox/ipam/models.py

@@ -29,6 +29,8 @@ class VRF(ChangeLoggedModel, CustomFieldModel):
     rd = models.CharField(
     rd = models.CharField(
         max_length=21,
         max_length=21,
         unique=True,
         unique=True,
+        blank=True,
+        null=True,
         verbose_name='Route distinguisher'
         verbose_name='Route distinguisher'
     )
     )
     tenant = models.ForeignKey(
     tenant = models.ForeignKey(

+ 18 - 11
netbox/ipam/tests/test_api.py

@@ -16,7 +16,7 @@ class VRFTest(APITestCase):
 
 
         self.vrf1 = VRF.objects.create(name='Test VRF 1', rd='65000:1')
         self.vrf1 = VRF.objects.create(name='Test VRF 1', rd='65000:1')
         self.vrf2 = VRF.objects.create(name='Test VRF 2', rd='65000:2')
         self.vrf2 = VRF.objects.create(name='Test VRF 2', rd='65000:2')
-        self.vrf3 = VRF.objects.create(name='Test VRF 3', rd='65000:3')
+        self.vrf3 = VRF.objects.create(name='Test VRF 3')  # No RD
 
 
     def test_get_vrf(self):
     def test_get_vrf(self):
 
 
@@ -44,19 +44,26 @@ class VRFTest(APITestCase):
 
 
     def test_create_vrf(self):
     def test_create_vrf(self):
 
 
-        data = {
-            'name': 'Test VRF 4',
-            'rd': '65000:4',
-        }
+        data_list = [
+            # VRF with RD
+            {
+                'name': 'Test VRF 4',
+                'rd': '65000:4',
+            },
+            # VRF without RD
+            {
+                'name': 'Test VRF 5',
+            }
+        ]
 
 
         url = reverse('ipam-api:vrf-list')
         url = reverse('ipam-api:vrf-list')
-        response = self.client.post(url, data, format='json', **self.header)
 
 
-        self.assertHttpStatus(response, status.HTTP_201_CREATED)
-        self.assertEqual(VRF.objects.count(), 4)
-        vrf4 = VRF.objects.get(pk=response.data['id'])
-        self.assertEqual(vrf4.name, data['name'])
-        self.assertEqual(vrf4.rd, data['rd'])
+        for data in data_list:
+            response = self.client.post(url, data, format='json', **self.header)
+            self.assertHttpStatus(response, status.HTTP_201_CREATED)
+            vrf = VRF.objects.get(pk=response.data['id'])
+            self.assertEqual(vrf.name, data['name'])
+            self.assertEqual(vrf.rd, data['rd'] if 'rd' in data else None)
 
 
     def test_create_vrf_bulk(self):
     def test_create_vrf_bulk(self):