diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py
index f682009ee..edd1867ed 100644
--- a/netbox/ipam/filtersets.py
+++ b/netbox/ipam/filtersets.py
@@ -930,8 +930,11 @@ class ServiceFilterSet(NetBoxModelFilterSet):
# L2VPN
#
-
class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
+ type = django_filters.MultipleChoiceFilter(
+ choices=L2VPNTypeChoices,
+ null_value=None
+ )
import_target_id = django_filters.ModelMultipleChoiceFilter(
field_name='import_targets',
queryset=RouteTarget.objects.all(),
@@ -972,10 +975,10 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
label='L2VPN (ID)',
)
l2vpn = django_filters.ModelMultipleChoiceFilter(
- field_name='l2vpn__name',
+ field_name='l2vpn__slug',
queryset=L2VPN.objects.all(),
- to_field_name='name',
- label='L2VPN (name)',
+ to_field_name='slug',
+ label='L2VPN (slug)',
)
device = MultiValueCharFilter(
method='filter_device',
@@ -987,17 +990,16 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
field_name='pk',
label='Device (ID)',
)
- interface = django_filters.ModelMultipleChoiceFilter(
- field_name='interface__name',
- queryset=Interface.objects.all(),
- to_field_name='name',
- label='Interface (name)',
- )
interface_id = django_filters.ModelMultipleChoiceFilter(
field_name='interface',
queryset=Interface.objects.all(),
label='Interface (ID)',
)
+ vminterface_id = django_filters.ModelMultipleChoiceFilter(
+ field_name='vminterface',
+ queryset=VMInterface.objects.all(),
+ label='VM Interface (ID)',
+ )
vlan = django_filters.ModelMultipleChoiceFilter(
field_name='vlan__name',
queryset=VLAN.objects.all(),
@@ -1013,10 +1015,11 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
queryset=VLAN.objects.all(),
label='VLAN (ID)',
)
+ assigned_object_type = ContentTypeFilter()
class Meta:
model = L2VPNTermination
- fields = ['id', ]
+ fields = ('id', 'assigned_object_type_id')
def search(self, queryset, name, value):
if not value.strip():
diff --git a/netbox/ipam/forms/bulk_edit.py b/netbox/ipam/forms/bulk_edit.py
index 50fc51522..5f579b07f 100644
--- a/netbox/ipam/forms/bulk_edit.py
+++ b/netbox/ipam/forms/bulk_edit.py
@@ -8,7 +8,7 @@ from ipam.models import ASN
from netbox.forms import NetBoxModelBulkEditForm
from tenancy.models import Tenant
from utilities.forms import (
- add_blank_choice, BulkEditNullBooleanSelect, DatePicker, DynamicModelChoiceField, NumericArrayField, StaticSelect,
+ add_blank_choice, BulkEditNullBooleanSelect, DynamicModelChoiceField, NumericArrayField, StaticSelect,
DynamicModelMultipleChoiceField,
)
@@ -445,6 +445,11 @@ class ServiceBulkEditForm(ServiceTemplateBulkEditForm):
class L2VPNBulkEditForm(NetBoxModelBulkEditForm):
+ type = forms.ChoiceField(
+ choices=add_blank_choice(L2VPNTypeChoices),
+ required=False,
+ widget=StaticSelect()
+ )
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
@@ -456,7 +461,7 @@ class L2VPNBulkEditForm(NetBoxModelBulkEditForm):
model = L2VPN
fieldsets = (
- (None, ('tenant', 'description')),
+ (None, ('type', 'description', 'tenant')),
)
nullable_fields = ('tenant', 'description',)
diff --git a/netbox/ipam/forms/bulk_import.py b/netbox/ipam/forms/bulk_import.py
index b8dd1c54c..880d2722f 100644
--- a/netbox/ipam/forms/bulk_import.py
+++ b/netbox/ipam/forms/bulk_import.py
@@ -438,7 +438,7 @@ class L2VPNCSVForm(NetBoxModelCSVForm):
)
type = CSVChoiceField(
choices=L2VPNTypeChoices,
- help_text='IP protocol'
+ help_text='L2VPN type'
)
class Meta:
diff --git a/netbox/ipam/forms/filtersets.py b/netbox/ipam/forms/filtersets.py
index 795cfe378..384a4da33 100644
--- a/netbox/ipam/forms/filtersets.py
+++ b/netbox/ipam/forms/filtersets.py
@@ -1,18 +1,19 @@
from django import forms
+from django.contrib.contenttypes.models import ContentType
+from django.db.models import Q
from django.utils.translation import gettext as _
from dcim.models import Location, Rack, Region, Site, SiteGroup, Device
-from virtualization.models import VirtualMachine
from ipam.choices import *
from ipam.constants import *
from ipam.models import *
-from ipam.models import ASN
from netbox.forms import NetBoxModelFilterSetForm
from tenancy.forms import TenancyFilterForm
from utilities.forms import (
- add_blank_choice, DynamicModelChoiceField, DynamicModelMultipleChoiceField, MultipleChoiceField, StaticSelect,
- TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
+ add_blank_choice, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
+ MultipleChoiceField, StaticSelect, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
)
+from virtualization.models import VirtualMachine
__all__ = (
'AggregateFilterForm',
@@ -482,7 +483,8 @@ class ServiceFilterForm(ServiceTemplateFilterForm):
class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
model = L2VPN
fieldsets = (
- (None, ('type', )),
+ (None, ('q', 'tag')),
+ ('Attributes', ('type', 'import_target_id', 'export_target_id')),
('Tenant', ('tenant_group_id', 'tenant_id')),
)
type = forms.ChoiceField(
@@ -490,17 +492,31 @@ class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
required=False,
widget=StaticSelect()
)
+ import_target_id = DynamicModelMultipleChoiceField(
+ queryset=RouteTarget.objects.all(),
+ required=False,
+ label=_('Import targets')
+ )
+ export_target_id = DynamicModelMultipleChoiceField(
+ queryset=RouteTarget.objects.all(),
+ required=False,
+ label=_('Export targets')
+ )
+ tag = TagFilterField(model)
class L2VPNTerminationFilterForm(NetBoxModelFilterSetForm):
model = L2VPNTermination
fieldsets = (
- (None, ('l2vpn', )),
+ (None, ('l2vpn_id', 'assigned_object_type_id')),
)
- l2vpn = DynamicModelChoiceField(
+ l2vpn_id = DynamicModelChoiceField(
queryset=L2VPN.objects.all(),
- required=True,
- query_params={},
- label='L2VPN',
- fetch_trigger='open'
+ required=False,
+ label='L2VPN'
+ )
+ assigned_object_type_id = ContentTypeMultipleChoiceField(
+ queryset=ContentType.objects.all(),
+ required=False,
+ label='Object type'
)
diff --git a/netbox/ipam/forms/models.py b/netbox/ipam/forms/models.py
index 3986eee32..415c952be 100644
--- a/netbox/ipam/forms/models.py
+++ b/netbox/ipam/forms/models.py
@@ -916,7 +916,8 @@ class L2VPNTerminationForm(NetBoxModelForm):
required=False,
query_params={
'available_on_device': '$device'
- }
+ },
+ label='VLAN'
)
interface = DynamicModelChoiceField(
queryset=Interface.objects.all(),
@@ -935,7 +936,8 @@ class L2VPNTerminationForm(NetBoxModelForm):
required=False,
query_params={
'virtual_machine_id': '$virtual_machine'
- }
+ },
+ label='Interface'
)
class Meta:
diff --git a/netbox/ipam/migrations/0059_l2vpn.py b/netbox/ipam/migrations/0059_l2vpn.py
index ef670ddea..7436989f7 100644
--- a/netbox/ipam/migrations/0059_l2vpn.py
+++ b/netbox/ipam/migrations/0059_l2vpn.py
@@ -27,7 +27,7 @@ class Migration(migrations.Migration):
('slug', models.SlugField()),
('type', models.CharField(max_length=50)),
('identifier', models.BigIntegerField(blank=True, null=True, unique=True)),
- ('description', models.TextField(blank=True, null=True)),
+ ('description', models.CharField(blank=True, max_length=200)),
('export_targets', models.ManyToManyField(blank=True, related_name='exporting_l2vpns', to='ipam.routetarget')),
('import_targets', models.ManyToManyField(blank=True, related_name='importing_l2vpns', to='ipam.routetarget')),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
@@ -35,7 +35,7 @@ class Migration(migrations.Migration):
],
options={
'verbose_name': 'L2VPN',
- 'ordering': ('identifier', 'name'),
+ 'ordering': ('name', 'identifier'),
},
),
migrations.CreateModel(
@@ -51,7 +51,7 @@ class Migration(migrations.Migration):
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
],
options={
- 'verbose_name': 'L2VPN Termination',
+ 'verbose_name': 'L2VPN termination',
'ordering': ('l2vpn',),
},
),
diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py
index 0bc0e2364..ee5de8cf4 100644
--- a/netbox/ipam/models/ip.py
+++ b/netbox/ipam/models/ip.py
@@ -931,7 +931,7 @@ class IPAddress(NetBoxModel):
# Populate the address field with the next available IP (if any)
if next_available_ip := self.get_next_available_ip():
- attrs['address'] = next_available_ip
+ attrs['address'] = f'{next_available_ip}/{self.address.prefixlen}'
return attrs
diff --git a/netbox/ipam/models/l2vpn.py b/netbox/ipam/models/l2vpn.py
index dd8c51984..5d85fe915 100644
--- a/netbox/ipam/models/l2vpn.py
+++ b/netbox/ipam/models/l2vpn.py
@@ -31,7 +31,10 @@ class L2VPN(NetBoxModel):
related_name='exporting_l2vpns',
blank=True
)
- description = models.TextField(null=True, blank=True)
+ description = models.CharField(
+ max_length=200,
+ blank=True
+ )
tenant = models.ForeignKey(
to='tenancy.Tenant',
on_delete=models.PROTECT,
@@ -44,7 +47,7 @@ class L2VPN(NetBoxModel):
)
class Meta:
- ordering = ('identifier', 'name')
+ ordering = ('name', 'identifier')
verbose_name = 'L2VPN'
def __str__(self):
@@ -76,7 +79,7 @@ class L2VPNTermination(NetBoxModel):
class Meta:
ordering = ('l2vpn',)
- verbose_name = 'L2VPN Termination'
+ verbose_name = 'L2VPN termination'
constraints = (
models.UniqueConstraint(
fields=('assigned_object_type', 'assigned_object_id'),
@@ -102,7 +105,7 @@ class L2VPNTermination(NetBoxModel):
raise ValidationError(f'L2VPN Termination already assigned ({self.assigned_object})')
# Only check if L2VPN is set and is of type P2P
- if self.l2vpn and self.l2vpn.type in L2VPNTypeChoices.P2P:
+ if hasattr(self, 'l2vpn') and self.l2vpn.type in L2VPNTypeChoices.P2P:
terminations_count = L2VPNTermination.objects.filter(l2vpn=self.l2vpn).exclude(pk=self.pk).count()
if terminations_count >= 2:
l2vpn_type = self.l2vpn.get_type_display()
diff --git a/netbox/ipam/tables/l2vpn.py b/netbox/ipam/tables/l2vpn.py
index a0e2f5d67..5be525343 100644
--- a/netbox/ipam/tables/l2vpn.py
+++ b/netbox/ipam/tables/l2vpn.py
@@ -1,8 +1,8 @@
import django_tables2 as tables
-from ipam.models import *
-from ipam.models.l2vpn import L2VPN, L2VPNTermination
+from ipam.models import L2VPN, L2VPNTermination
from netbox.tables import NetBoxTable, columns
+from tenancy.tables import TenancyColumnsMixin
__all__ = (
'L2VPNTable',
@@ -16,7 +16,7 @@ L2VPN_TARGETS = """
"""
-class L2VPNTable(NetBoxTable):
+class L2VPNTable(TenancyColumnsMixin, NetBoxTable):
pk = columns.ToggleColumn()
name = tables.Column(
linkify=True
@@ -32,7 +32,10 @@ class L2VPNTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = L2VPN
- fields = ('pk', 'name', 'slug', 'type', 'description', 'import_targets', 'export_targets', 'tenant', 'actions')
+ fields = (
+ 'pk', 'name', 'slug', 'type', 'description', 'import_targets', 'export_targets', 'tenant', 'tenant_group',
+ 'actions',
+ )
default_columns = ('pk', 'name', 'type', 'description', 'actions')
diff --git a/netbox/ipam/tests/test_api.py b/netbox/ipam/tests/test_api.py
index a5ebef2c7..3fef04194 100644
--- a/netbox/ipam/tests/test_api.py
+++ b/netbox/ipam/tests/test_api.py
@@ -970,7 +970,6 @@ class L2VPNTerminationTest(APIViewTestCases.APIViewTestCase):
VLAN(name='VLAN 6', vid=656),
VLAN(name='VLAN 7', vid=657)
)
-
VLAN.objects.bulk_create(vlans)
l2vpns = (
@@ -985,7 +984,6 @@ class L2VPNTerminationTest(APIViewTestCases.APIViewTestCase):
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vlans[1]),
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vlans[2])
)
-
L2VPNTermination.objects.bulk_create(l2vpnterminations)
cls.create_data = [
diff --git a/netbox/ipam/tests/test_filtersets.py b/netbox/ipam/tests/test_filtersets.py
index 2b5fb0759..9106a4965 100644
--- a/netbox/ipam/tests/test_filtersets.py
+++ b/netbox/ipam/tests/test_filtersets.py
@@ -1,6 +1,8 @@
+from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
from netaddr import IPNetwork
+from dcim.choices import InterfaceTypeChoices
from dcim.models import Device, DeviceRole, DeviceType, Interface, Location, Manufacturer, Rack, Region, Site, SiteGroup
from ipam.choices import *
from ipam.filtersets import *
@@ -1472,12 +1474,54 @@ class L2VPNTestCase(TestCase, ChangeLoggedFilterSetTests):
@classmethod
def setUpTestData(cls):
+ route_targets = (
+ RouteTarget(name='1:1'),
+ RouteTarget(name='1:2'),
+ RouteTarget(name='1:3'),
+ RouteTarget(name='2:1'),
+ RouteTarget(name='2:2'),
+ RouteTarget(name='2:3'),
+ )
+ RouteTarget.objects.bulk_create(route_targets)
+
l2vpns = (
- L2VPN(name='L2VPN 1', type='vxlan', identifier=650001),
- L2VPN(name='L2VPN 2', type='vpws', identifier=650002),
- L2VPN(name='L2VPN 3', type='vpls'), # No RD
+ L2VPN(name='L2VPN 1', type=L2VPNTypeChoices.TYPE_VXLAN, identifier=65001),
+ L2VPN(name='L2VPN 2', type=L2VPNTypeChoices.TYPE_VPWS, identifier=65002),
+ L2VPN(name='L2VPN 3', type=L2VPNTypeChoices.TYPE_VPLS),
)
L2VPN.objects.bulk_create(l2vpns)
+ l2vpns[0].import_targets.add(route_targets[0])
+ l2vpns[1].import_targets.add(route_targets[1])
+ l2vpns[2].import_targets.add(route_targets[2])
+ l2vpns[0].export_targets.add(route_targets[3])
+ l2vpns[1].export_targets.add(route_targets[4])
+ l2vpns[2].export_targets.add(route_targets[5])
+
+ def test_name(self):
+ params = {'name': ['L2VPN 1', 'L2VPN 2']}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+ def test_identifier(self):
+ params = {'identifier': ['65001', '65002']}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+ def test_type(self):
+ params = {'type': [L2VPNTypeChoices.TYPE_VXLAN, L2VPNTypeChoices.TYPE_VPWS]}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+ def test_import_targets(self):
+ route_targets = RouteTarget.objects.filter(name__in=['1:1', '1:2'])
+ params = {'import_target_id': [route_targets[0].pk, route_targets[1].pk]}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+ params = {'import_target': [route_targets[0].name, route_targets[1].name]}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+ def test_export_targets(self):
+ route_targets = RouteTarget.objects.filter(name__in=['2:1', '2:2'])
+ params = {'export_target_id': [route_targets[0].pk, route_targets[1].pk]}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+ params = {'export_target': [route_targets[0].name, route_targets[1].name]}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class L2VPNTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
@@ -1486,44 +1530,33 @@ class L2VPNTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
@classmethod
def setUpTestData(cls):
-
- site = Site.objects.create(name='Site 1')
- manufacturer = Manufacturer.objects.create(name='Manufacturer 1')
- device_type = DeviceType.objects.create(model='Device Type 1', manufacturer=manufacturer)
- device_role = DeviceRole.objects.create(name='Switch')
- device = Device.objects.create(
- name='Device 1',
- site=site,
- device_type=device_type,
- device_role=device_role,
- status='active'
- )
-
+ device = create_test_device('Device 1')
interfaces = (
- Interface(name='Interface 1', device=device, type='1000baset'),
- Interface(name='Interface 2', device=device, type='1000baset'),
- Interface(name='Interface 3', device=device, type='1000baset'),
- Interface(name='Interface 4', device=device, type='1000baset'),
- Interface(name='Interface 5', device=device, type='1000baset'),
- Interface(name='Interface 6', device=device, type='1000baset')
+ Interface(name='Interface 1', device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+ Interface(name='Interface 2', device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED),
+ Interface(name='Interface 3', device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED),
)
-
Interface.objects.bulk_create(interfaces)
- vlans = (
- VLAN(name='VLAN 1', vid=651),
- VLAN(name='VLAN 2', vid=652),
- VLAN(name='VLAN 3', vid=653),
- VLAN(name='VLAN 4', vid=654),
- VLAN(name='VLAN 5', vid=655)
+ vm = create_test_virtualmachine('Virtual Machine 1')
+ vminterfaces = (
+ VMInterface(name='Interface 1', virtual_machine=vm),
+ VMInterface(name='Interface 2', virtual_machine=vm),
+ VMInterface(name='Interface 3', virtual_machine=vm),
)
+ VMInterface.objects.bulk_create(vminterfaces)
+ vlans = (
+ VLAN(name='VLAN 1', vid=101),
+ VLAN(name='VLAN 2', vid=102),
+ VLAN(name='VLAN 3', vid=103),
+ )
VLAN.objects.bulk_create(vlans)
l2vpns = (
- L2VPN(name='L2VPN 1', type='vxlan', identifier=650001),
- L2VPN(name='L2VPN 2', type='vpws', identifier=650002),
- L2VPN(name='L2VPN 3', type='vpls'), # No RD,
+ L2VPN(name='L2VPN 1', slug='l2vpn-1', type='vxlan', identifier=65001),
+ L2VPN(name='L2VPN 2', slug='l2vpn-2', type='vpws', identifier=65002),
+ L2VPN(name='L2VPN 3', slug='l2vpn-3', type='vpls'), # No RD,
)
L2VPN.objects.bulk_create(l2vpns)
@@ -1534,27 +1567,34 @@ class L2VPNTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=interfaces[0]),
L2VPNTermination(l2vpn=l2vpns[1], assigned_object=interfaces[1]),
L2VPNTermination(l2vpn=l2vpns[2], assigned_object=interfaces[2]),
+ L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vminterfaces[0]),
+ L2VPNTermination(l2vpn=l2vpns[1], assigned_object=vminterfaces[1]),
+ L2VPNTermination(l2vpn=l2vpns[2], assigned_object=vminterfaces[2]),
)
-
L2VPNTermination.objects.bulk_create(l2vpnterminations)
- def test_l2vpns(self):
+ def test_l2vpn(self):
l2vpns = L2VPN.objects.all()[:2]
params = {'l2vpn_id': [l2vpns[0].pk, l2vpns[1].pk]}
- self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
- params = {'l2vpn': ['L2VPN 1', 'L2VPN 2']}
- self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
+ params = {'l2vpn': [l2vpns[0].slug, l2vpns[1].slug]}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
- def test_interfaces(self):
+ def test_content_type(self):
+ params = {'assigned_object_type_id': ContentType.objects.get(model='vlan').pk}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
+
+ def test_interface(self):
interfaces = Interface.objects.all()[:2]
params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]}
- qs = self.filterset(params, self.queryset).qs
- results = qs.all()
- self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
- params = {'interface': ['Interface 1', 'Interface 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
- def test_vlans(self):
+ def test_vminterface(self):
+ vminterfaces = VMInterface.objects.all()[:2]
+ params = {'vminterface_id': [vminterfaces[0].pk, vminterfaces[1].pk]}
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+ def test_vlan(self):
vlans = VLAN.objects.all()[:2]
params = {'vlan_id': [vlans[0].pk, vlans[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
diff --git a/netbox/ipam/tests/test_views.py b/netbox/ipam/tests/test_views.py
index 890c0eae3..27520229a 100644
--- a/netbox/ipam/tests/test_views.py
+++ b/netbox/ipam/tests/test_views.py
@@ -1,18 +1,14 @@
import datetime
-from django.contrib.contenttypes.models import ContentType
from django.test import override_settings
from django.urls import reverse
from netaddr import IPNetwork
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site, Interface
-from extras.choices import ObjectChangeActionChoices
-from extras.models import ObjectChange
from ipam.choices import *
from ipam.models import *
from tenancy.models import Tenant
-from users.models import ObjectPermission
-from utilities.testing import ViewTestCases, create_tags, post_data
+from utilities.testing import ViewTestCases, create_test_device, create_tags
class ASNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
@@ -772,9 +768,9 @@ class L2VPNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
RouteTarget.objects.bulk_create(rts)
l2vpns = (
- L2VPN(name='L2VPN 1', slug='l2vpn-1', type='vxlan', identifier='650001'),
- L2VPN(name='L2VPN 2', slug='l2vpn-2', type='vxlan', identifier='650002'),
- L2VPN(name='L2VPN 3', slug='l2vpn-3', type='vxlan', identifier='650003')
+ L2VPN(name='L2VPN 1', slug='l2vpn-1', type=L2VPNTypeChoices.TYPE_VXLAN, identifier='650001'),
+ L2VPN(name='L2VPN 2', slug='l2vpn-2', type=L2VPNTypeChoices.TYPE_VXLAN, identifier='650002'),
+ L2VPN(name='L2VPN 3', slug='l2vpn-3', type=L2VPNTypeChoices.TYPE_VXLAN, identifier='650003')
)
L2VPN.objects.bulk_create(l2vpns)
@@ -782,7 +778,7 @@ class L2VPNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
cls.form_data = {
'name': 'L2VPN 8',
'slug': 'l2vpn-8',
- 'type': 'vxlan',
+ 'type': L2VPNTypeChoices.TYPE_VXLAN,
'identifier': 123,
'description': 'Description',
'import_targets': [rts[0].pk],
@@ -805,21 +801,9 @@ class L2VPNTerminationTestCase(
@classmethod
def setUpTestData(cls):
- site = Site.objects.create(name='Site 1')
- manufacturer = Manufacturer.objects.create(name='Manufacturer 1')
- device_type = DeviceType.objects.create(model='Device Type 1', manufacturer=manufacturer)
- device_role = DeviceRole.objects.create(name='Switch')
- device = Device.objects.create(
- name='Device 1',
- site=site,
- device_type=device_type,
- device_role=device_role,
- status='active'
- )
-
+ device = create_test_device('Device 1')
interface = Interface.objects.create(name='Interface 1', device=device, type='1000baset')
- l2vpn = L2VPN.objects.create(name='L2VPN 1', type='vxlan', identifier=650001)
- l2vpn_vlans = L2VPN.objects.create(name='L2VPN 2', type='vxlan', identifier=650002)
+ l2vpn = L2VPN.objects.create(name='L2VPN 1', type=L2VPNTypeChoices.TYPE_VXLAN, identifier=650001)
vlans = (
VLAN(name='Vlan 1', vid=1001),
@@ -846,9 +830,9 @@ class L2VPNTerminationTestCase(
cls.csv_data = (
"l2vpn,vlan",
- "L2VPN 2,Vlan 4",
- "L2VPN 2,Vlan 5",
- "L2VPN 2,Vlan 6",
+ "L2VPN 1,Vlan 4",
+ "L2VPN 1,Vlan 5",
+ "L2VPN 1,Vlan 6",
)
cls.bulk_edit_data = {}
@@ -857,6 +841,7 @@ class L2VPNTerminationTestCase(
# Custom assertions
#
+ # TODO: Remove this
def assertInstanceEqual(self, instance, data, exclude=None, api=False):
"""
Override parent
diff --git a/netbox/templates/ipam/l2vpn.html b/netbox/templates/ipam/l2vpn.html
index 130940b02..44a1da818 100644
--- a/netbox/templates/ipam/l2vpn.html
+++ b/netbox/templates/ipam/l2vpn.html
@@ -6,46 +6,40 @@
{% block content %}
-
-
-
-
Name
- {{ object.name|placeholder }} |
-
-
- Slug |
- {{ object.slug|placeholder }} |
-
-
- Identifier |
- {{ object.identifier|placeholder }} |
-
-
- Type |
- {{ object.get_type_display }} |
-
-
- Description |
- {{ object.description|placeholder }} |
-
-
- Tenant |
- {{ object.tenant|placeholder }} |
-
-
-
-
- {% include 'inc/panels/contacts.html' %}
- {% plugin_left_page object %}
+
+
+
+
+
+ Name |
+ {{ object.name|placeholder }} |
+
+
+ Identifier |
+ {{ object.identifier|placeholder }} |
+
+
+ Type |
+ {{ object.get_type_display }} |
+
+
+ Description |
+ {{ object.description|placeholder }} |
+
+
+ Tenant |
+ {{ object.tenant|linkify|placeholder }} |
+
+
+
+
+ {% include 'inc/panels/tags.html' with tags=object.tags.all url='ipam:l2vpn_list' %}
+ {% plugin_left_page object %}
- {% include 'inc/panels/tags.html' with tags=object.tags.all url='circuits:circuit_list' %}
- {% include 'inc/panels/custom_fields.html' %}
- {% plugin_right_page object %}
+ {% include 'inc/panels/contacts.html' %}
+ {% include 'inc/panels/custom_fields.html' %}
+ {% plugin_right_page object %}
@@ -58,24 +52,24 @@
-
-
-
- {% render_table terminations_table 'inc/table.html' %}
-
- {% if perms.ipam.add_l2vpntermination %}
-
- {% endif %}
+
+
+
+ {% render_table terminations_table 'inc/table.html' %}
+
+ {% if perms.ipam.add_l2vpntermination %}
+
+ {% endif %}
+
-
- {% plugin_full_width_page object %}
+
+ {% plugin_full_width_page object %}
{% endblock %}
diff --git a/netbox/templates/ipam/l2vpntermination_edit.html b/netbox/templates/ipam/l2vpntermination_edit.html
index 4ba079eb5..7b4a9f50a 100644
--- a/netbox/templates/ipam/l2vpntermination_edit.html
+++ b/netbox/templates/ipam/l2vpntermination_edit.html
@@ -18,12 +18,12 @@