mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 17:38:37 -06:00
#8157: General cleanup & fix tests
This commit is contained in:
parent
1ddb219a0c
commit
53372a7471
@ -930,8 +930,11 @@ class ServiceFilterSet(NetBoxModelFilterSet):
|
|||||||
# L2VPN
|
# L2VPN
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||||
|
type = django_filters.MultipleChoiceFilter(
|
||||||
|
choices=L2VPNTypeChoices,
|
||||||
|
null_value=None
|
||||||
|
)
|
||||||
import_target_id = django_filters.ModelMultipleChoiceFilter(
|
import_target_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='import_targets',
|
field_name='import_targets',
|
||||||
queryset=RouteTarget.objects.all(),
|
queryset=RouteTarget.objects.all(),
|
||||||
@ -972,10 +975,10 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
|
|||||||
label='L2VPN (ID)',
|
label='L2VPN (ID)',
|
||||||
)
|
)
|
||||||
l2vpn = django_filters.ModelMultipleChoiceFilter(
|
l2vpn = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='l2vpn__name',
|
field_name='l2vpn__slug',
|
||||||
queryset=L2VPN.objects.all(),
|
queryset=L2VPN.objects.all(),
|
||||||
to_field_name='name',
|
to_field_name='slug',
|
||||||
label='L2VPN (name)',
|
label='L2VPN (slug)',
|
||||||
)
|
)
|
||||||
device = MultiValueCharFilter(
|
device = MultiValueCharFilter(
|
||||||
method='filter_device',
|
method='filter_device',
|
||||||
@ -987,17 +990,16 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
|
|||||||
field_name='pk',
|
field_name='pk',
|
||||||
label='Device (ID)',
|
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(
|
interface_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='interface',
|
field_name='interface',
|
||||||
queryset=Interface.objects.all(),
|
queryset=Interface.objects.all(),
|
||||||
label='Interface (ID)',
|
label='Interface (ID)',
|
||||||
)
|
)
|
||||||
|
vminterface_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='vminterface',
|
||||||
|
queryset=VMInterface.objects.all(),
|
||||||
|
label='VM Interface (ID)',
|
||||||
|
)
|
||||||
vlan = django_filters.ModelMultipleChoiceFilter(
|
vlan = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='vlan__name',
|
field_name='vlan__name',
|
||||||
queryset=VLAN.objects.all(),
|
queryset=VLAN.objects.all(),
|
||||||
@ -1013,10 +1015,11 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
|
|||||||
queryset=VLAN.objects.all(),
|
queryset=VLAN.objects.all(),
|
||||||
label='VLAN (ID)',
|
label='VLAN (ID)',
|
||||||
)
|
)
|
||||||
|
assigned_object_type = ContentTypeFilter()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = L2VPNTermination
|
model = L2VPNTermination
|
||||||
fields = ['id', ]
|
fields = ('id', 'assigned_object_type_id')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -8,7 +8,7 @@ from ipam.models import ASN
|
|||||||
from netbox.forms import NetBoxModelBulkEditForm
|
from netbox.forms import NetBoxModelBulkEditForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
add_blank_choice, BulkEditNullBooleanSelect, DatePicker, DynamicModelChoiceField, NumericArrayField, StaticSelect,
|
add_blank_choice, BulkEditNullBooleanSelect, DynamicModelChoiceField, NumericArrayField, StaticSelect,
|
||||||
DynamicModelMultipleChoiceField,
|
DynamicModelMultipleChoiceField,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -445,6 +445,11 @@ class ServiceBulkEditForm(ServiceTemplateBulkEditForm):
|
|||||||
|
|
||||||
|
|
||||||
class L2VPNBulkEditForm(NetBoxModelBulkEditForm):
|
class L2VPNBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
|
type = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(L2VPNTypeChoices),
|
||||||
|
required=False,
|
||||||
|
widget=StaticSelect()
|
||||||
|
)
|
||||||
tenant = DynamicModelChoiceField(
|
tenant = DynamicModelChoiceField(
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
@ -456,7 +461,7 @@ class L2VPNBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
|
|
||||||
model = L2VPN
|
model = L2VPN
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('tenant', 'description')),
|
(None, ('type', 'description', 'tenant')),
|
||||||
)
|
)
|
||||||
nullable_fields = ('tenant', 'description',)
|
nullable_fields = ('tenant', 'description',)
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ class L2VPNCSVForm(NetBoxModelCSVForm):
|
|||||||
)
|
)
|
||||||
type = CSVChoiceField(
|
type = CSVChoiceField(
|
||||||
choices=L2VPNTypeChoices,
|
choices=L2VPNTypeChoices,
|
||||||
help_text='IP protocol'
|
help_text='L2VPN type'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
from django import forms
|
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 django.utils.translation import gettext as _
|
||||||
|
|
||||||
from dcim.models import Location, Rack, Region, Site, SiteGroup, Device
|
from dcim.models import Location, Rack, Region, Site, SiteGroup, Device
|
||||||
from virtualization.models import VirtualMachine
|
|
||||||
from ipam.choices import *
|
from ipam.choices import *
|
||||||
from ipam.constants import *
|
from ipam.constants import *
|
||||||
from ipam.models import *
|
from ipam.models import *
|
||||||
from ipam.models import ASN
|
|
||||||
from netbox.forms import NetBoxModelFilterSetForm
|
from netbox.forms import NetBoxModelFilterSetForm
|
||||||
from tenancy.forms import TenancyFilterForm
|
from tenancy.forms import TenancyFilterForm
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
add_blank_choice, DynamicModelChoiceField, DynamicModelMultipleChoiceField, MultipleChoiceField, StaticSelect,
|
add_blank_choice, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
|
||||||
TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
|
MultipleChoiceField, StaticSelect, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
|
||||||
)
|
)
|
||||||
|
from virtualization.models import VirtualMachine
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'AggregateFilterForm',
|
'AggregateFilterForm',
|
||||||
@ -482,7 +483,8 @@ class ServiceFilterForm(ServiceTemplateFilterForm):
|
|||||||
class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = L2VPN
|
model = L2VPN
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('type', )),
|
(None, ('q', 'tag')),
|
||||||
|
('Attributes', ('type', 'import_target_id', 'export_target_id')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
)
|
)
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
@ -490,17 +492,31 @@ class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelect()
|
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):
|
class L2VPNTerminationFilterForm(NetBoxModelFilterSetForm):
|
||||||
model = L2VPNTermination
|
model = L2VPNTermination
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('l2vpn', )),
|
(None, ('l2vpn_id', 'assigned_object_type_id')),
|
||||||
)
|
)
|
||||||
l2vpn = DynamicModelChoiceField(
|
l2vpn_id = DynamicModelChoiceField(
|
||||||
queryset=L2VPN.objects.all(),
|
queryset=L2VPN.objects.all(),
|
||||||
required=True,
|
required=False,
|
||||||
query_params={},
|
label='L2VPN'
|
||||||
label='L2VPN',
|
)
|
||||||
fetch_trigger='open'
|
assigned_object_type_id = ContentTypeMultipleChoiceField(
|
||||||
|
queryset=ContentType.objects.all(),
|
||||||
|
required=False,
|
||||||
|
label='Object type'
|
||||||
)
|
)
|
||||||
|
@ -916,7 +916,8 @@ class L2VPNTerminationForm(NetBoxModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
query_params={
|
query_params={
|
||||||
'available_on_device': '$device'
|
'available_on_device': '$device'
|
||||||
}
|
},
|
||||||
|
label='VLAN'
|
||||||
)
|
)
|
||||||
interface = DynamicModelChoiceField(
|
interface = DynamicModelChoiceField(
|
||||||
queryset=Interface.objects.all(),
|
queryset=Interface.objects.all(),
|
||||||
@ -935,7 +936,8 @@ class L2VPNTerminationForm(NetBoxModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
query_params={
|
query_params={
|
||||||
'virtual_machine_id': '$virtual_machine'
|
'virtual_machine_id': '$virtual_machine'
|
||||||
}
|
},
|
||||||
|
label='Interface'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -27,7 +27,7 @@ class Migration(migrations.Migration):
|
|||||||
('slug', models.SlugField()),
|
('slug', models.SlugField()),
|
||||||
('type', models.CharField(max_length=50)),
|
('type', models.CharField(max_length=50)),
|
||||||
('identifier', models.BigIntegerField(blank=True, null=True, unique=True)),
|
('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')),
|
('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')),
|
('import_targets', models.ManyToManyField(blank=True, related_name='importing_l2vpns', to='ipam.routetarget')),
|
||||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
@ -35,7 +35,7 @@ class Migration(migrations.Migration):
|
|||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'L2VPN',
|
'verbose_name': 'L2VPN',
|
||||||
'ordering': ('identifier', 'name'),
|
'ordering': ('name', 'identifier'),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@ -51,7 +51,7 @@ class Migration(migrations.Migration):
|
|||||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'L2VPN Termination',
|
'verbose_name': 'L2VPN termination',
|
||||||
'ordering': ('l2vpn',),
|
'ordering': ('l2vpn',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -931,7 +931,7 @@ class IPAddress(NetBoxModel):
|
|||||||
|
|
||||||
# Populate the address field with the next available IP (if any)
|
# Populate the address field with the next available IP (if any)
|
||||||
if next_available_ip := self.get_next_available_ip():
|
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
|
return attrs
|
||||||
|
|
||||||
|
@ -31,7 +31,10 @@ class L2VPN(NetBoxModel):
|
|||||||
related_name='exporting_l2vpns',
|
related_name='exporting_l2vpns',
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
description = models.TextField(null=True, blank=True)
|
description = models.CharField(
|
||||||
|
max_length=200,
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
tenant = models.ForeignKey(
|
tenant = models.ForeignKey(
|
||||||
to='tenancy.Tenant',
|
to='tenancy.Tenant',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
@ -44,7 +47,7 @@ class L2VPN(NetBoxModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('identifier', 'name')
|
ordering = ('name', 'identifier')
|
||||||
verbose_name = 'L2VPN'
|
verbose_name = 'L2VPN'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -76,7 +79,7 @@ class L2VPNTermination(NetBoxModel):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('l2vpn',)
|
ordering = ('l2vpn',)
|
||||||
verbose_name = 'L2VPN Termination'
|
verbose_name = 'L2VPN termination'
|
||||||
constraints = (
|
constraints = (
|
||||||
models.UniqueConstraint(
|
models.UniqueConstraint(
|
||||||
fields=('assigned_object_type', 'assigned_object_id'),
|
fields=('assigned_object_type', 'assigned_object_id'),
|
||||||
@ -102,7 +105,7 @@ class L2VPNTermination(NetBoxModel):
|
|||||||
raise ValidationError(f'L2VPN Termination already assigned ({self.assigned_object})')
|
raise ValidationError(f'L2VPN Termination already assigned ({self.assigned_object})')
|
||||||
|
|
||||||
# Only check if L2VPN is set and is of type P2P
|
# 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()
|
terminations_count = L2VPNTermination.objects.filter(l2vpn=self.l2vpn).exclude(pk=self.pk).count()
|
||||||
if terminations_count >= 2:
|
if terminations_count >= 2:
|
||||||
l2vpn_type = self.l2vpn.get_type_display()
|
l2vpn_type = self.l2vpn.get_type_display()
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
|
|
||||||
from ipam.models import *
|
from ipam.models import L2VPN, L2VPNTermination
|
||||||
from ipam.models.l2vpn import L2VPN, L2VPNTermination
|
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
|
from tenancy.tables import TenancyColumnsMixin
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'L2VPNTable',
|
'L2VPNTable',
|
||||||
@ -16,7 +16,7 @@ L2VPN_TARGETS = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class L2VPNTable(NetBoxTable):
|
class L2VPNTable(TenancyColumnsMixin, NetBoxTable):
|
||||||
pk = columns.ToggleColumn()
|
pk = columns.ToggleColumn()
|
||||||
name = tables.Column(
|
name = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
@ -32,7 +32,10 @@ class L2VPNTable(NetBoxTable):
|
|||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = L2VPN
|
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')
|
default_columns = ('pk', 'name', 'type', 'description', 'actions')
|
||||||
|
|
||||||
|
|
||||||
|
@ -970,7 +970,6 @@ class L2VPNTerminationTest(APIViewTestCases.APIViewTestCase):
|
|||||||
VLAN(name='VLAN 6', vid=656),
|
VLAN(name='VLAN 6', vid=656),
|
||||||
VLAN(name='VLAN 7', vid=657)
|
VLAN(name='VLAN 7', vid=657)
|
||||||
)
|
)
|
||||||
|
|
||||||
VLAN.objects.bulk_create(vlans)
|
VLAN.objects.bulk_create(vlans)
|
||||||
|
|
||||||
l2vpns = (
|
l2vpns = (
|
||||||
@ -985,7 +984,6 @@ class L2VPNTerminationTest(APIViewTestCases.APIViewTestCase):
|
|||||||
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vlans[1]),
|
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vlans[1]),
|
||||||
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vlans[2])
|
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=vlans[2])
|
||||||
)
|
)
|
||||||
|
|
||||||
L2VPNTermination.objects.bulk_create(l2vpnterminations)
|
L2VPNTermination.objects.bulk_create(l2vpnterminations)
|
||||||
|
|
||||||
cls.create_data = [
|
cls.create_data = [
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from netaddr import IPNetwork
|
from netaddr import IPNetwork
|
||||||
|
|
||||||
|
from dcim.choices import InterfaceTypeChoices
|
||||||
from dcim.models import Device, DeviceRole, DeviceType, Interface, Location, Manufacturer, Rack, Region, Site, SiteGroup
|
from dcim.models import Device, DeviceRole, DeviceType, Interface, Location, Manufacturer, Rack, Region, Site, SiteGroup
|
||||||
from ipam.choices import *
|
from ipam.choices import *
|
||||||
from ipam.filtersets import *
|
from ipam.filtersets import *
|
||||||
@ -1472,12 +1474,54 @@ class L2VPNTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
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 = (
|
l2vpns = (
|
||||||
L2VPN(name='L2VPN 1', type='vxlan', identifier=650001),
|
L2VPN(name='L2VPN 1', type=L2VPNTypeChoices.TYPE_VXLAN, identifier=65001),
|
||||||
L2VPN(name='L2VPN 2', type='vpws', identifier=650002),
|
L2VPN(name='L2VPN 2', type=L2VPNTypeChoices.TYPE_VPWS, identifier=65002),
|
||||||
L2VPN(name='L2VPN 3', type='vpls'), # No RD
|
L2VPN(name='L2VPN 3', type=L2VPNTypeChoices.TYPE_VPLS),
|
||||||
)
|
)
|
||||||
L2VPN.objects.bulk_create(l2vpns)
|
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):
|
class L2VPNTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
@ -1486,44 +1530,33 @@ class L2VPNTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
device = create_test_device('Device 1')
|
||||||
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'
|
|
||||||
)
|
|
||||||
|
|
||||||
interfaces = (
|
interfaces = (
|
||||||
Interface(name='Interface 1', device=device, type='1000baset'),
|
Interface(name='Interface 1', device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED),
|
||||||
Interface(name='Interface 2', device=device, type='1000baset'),
|
Interface(name='Interface 2', device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED),
|
||||||
Interface(name='Interface 3', device=device, type='1000baset'),
|
Interface(name='Interface 3', device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED),
|
||||||
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.objects.bulk_create(interfaces)
|
Interface.objects.bulk_create(interfaces)
|
||||||
|
|
||||||
vlans = (
|
vm = create_test_virtualmachine('Virtual Machine 1')
|
||||||
VLAN(name='VLAN 1', vid=651),
|
vminterfaces = (
|
||||||
VLAN(name='VLAN 2', vid=652),
|
VMInterface(name='Interface 1', virtual_machine=vm),
|
||||||
VLAN(name='VLAN 3', vid=653),
|
VMInterface(name='Interface 2', virtual_machine=vm),
|
||||||
VLAN(name='VLAN 4', vid=654),
|
VMInterface(name='Interface 3', virtual_machine=vm),
|
||||||
VLAN(name='VLAN 5', vid=655)
|
|
||||||
)
|
)
|
||||||
|
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)
|
VLAN.objects.bulk_create(vlans)
|
||||||
|
|
||||||
l2vpns = (
|
l2vpns = (
|
||||||
L2VPN(name='L2VPN 1', type='vxlan', identifier=650001),
|
L2VPN(name='L2VPN 1', slug='l2vpn-1', type='vxlan', identifier=65001),
|
||||||
L2VPN(name='L2VPN 2', type='vpws', identifier=650002),
|
L2VPN(name='L2VPN 2', slug='l2vpn-2', type='vpws', identifier=65002),
|
||||||
L2VPN(name='L2VPN 3', type='vpls'), # No RD,
|
L2VPN(name='L2VPN 3', slug='l2vpn-3', type='vpls'), # No RD,
|
||||||
)
|
)
|
||||||
L2VPN.objects.bulk_create(l2vpns)
|
L2VPN.objects.bulk_create(l2vpns)
|
||||||
|
|
||||||
@ -1534,27 +1567,34 @@ class L2VPNTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=interfaces[0]),
|
L2VPNTermination(l2vpn=l2vpns[0], assigned_object=interfaces[0]),
|
||||||
L2VPNTermination(l2vpn=l2vpns[1], assigned_object=interfaces[1]),
|
L2VPNTermination(l2vpn=l2vpns[1], assigned_object=interfaces[1]),
|
||||||
L2VPNTermination(l2vpn=l2vpns[2], assigned_object=interfaces[2]),
|
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)
|
L2VPNTermination.objects.bulk_create(l2vpnterminations)
|
||||||
|
|
||||||
def test_l2vpns(self):
|
def test_l2vpn(self):
|
||||||
l2vpns = L2VPN.objects.all()[:2]
|
l2vpns = L2VPN.objects.all()[:2]
|
||||||
params = {'l2vpn_id': [l2vpns[0].pk, l2vpns[1].pk]}
|
params = {'l2vpn_id': [l2vpns[0].pk, l2vpns[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
|
||||||
params = {'l2vpn': ['L2VPN 1', 'L2VPN 2']}
|
params = {'l2vpn': [l2vpns[0].slug, l2vpns[1].slug]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
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]
|
interfaces = Interface.objects.all()[:2]
|
||||||
params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]}
|
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)
|
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]
|
vlans = VLAN.objects.all()[:2]
|
||||||
params = {'vlan_id': [vlans[0].pk, vlans[1].pk]}
|
params = {'vlan_id': [vlans[0].pk, vlans[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from netaddr import IPNetwork
|
from netaddr import IPNetwork
|
||||||
|
|
||||||
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site, Interface
|
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.choices import *
|
||||||
from ipam.models import *
|
from ipam.models import *
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from users.models import ObjectPermission
|
from utilities.testing import ViewTestCases, create_test_device, create_tags
|
||||||
from utilities.testing import ViewTestCases, create_tags, post_data
|
|
||||||
|
|
||||||
|
|
||||||
class ASNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
class ASNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
@ -772,9 +768,9 @@ class L2VPNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
RouteTarget.objects.bulk_create(rts)
|
RouteTarget.objects.bulk_create(rts)
|
||||||
|
|
||||||
l2vpns = (
|
l2vpns = (
|
||||||
L2VPN(name='L2VPN 1', slug='l2vpn-1', type='vxlan', identifier='650001'),
|
L2VPN(name='L2VPN 1', slug='l2vpn-1', type=L2VPNTypeChoices.TYPE_VXLAN, identifier='650001'),
|
||||||
L2VPN(name='L2VPN 2', slug='l2vpn-2', type='vxlan', identifier='650002'),
|
L2VPN(name='L2VPN 2', slug='l2vpn-2', type=L2VPNTypeChoices.TYPE_VXLAN, identifier='650002'),
|
||||||
L2VPN(name='L2VPN 3', slug='l2vpn-3', type='vxlan', identifier='650003')
|
L2VPN(name='L2VPN 3', slug='l2vpn-3', type=L2VPNTypeChoices.TYPE_VXLAN, identifier='650003')
|
||||||
)
|
)
|
||||||
|
|
||||||
L2VPN.objects.bulk_create(l2vpns)
|
L2VPN.objects.bulk_create(l2vpns)
|
||||||
@ -782,7 +778,7 @@ class L2VPNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
cls.form_data = {
|
cls.form_data = {
|
||||||
'name': 'L2VPN 8',
|
'name': 'L2VPN 8',
|
||||||
'slug': 'l2vpn-8',
|
'slug': 'l2vpn-8',
|
||||||
'type': 'vxlan',
|
'type': L2VPNTypeChoices.TYPE_VXLAN,
|
||||||
'identifier': 123,
|
'identifier': 123,
|
||||||
'description': 'Description',
|
'description': 'Description',
|
||||||
'import_targets': [rts[0].pk],
|
'import_targets': [rts[0].pk],
|
||||||
@ -805,21 +801,9 @@ class L2VPNTerminationTestCase(
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
site = Site.objects.create(name='Site 1')
|
device = create_test_device('Device 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'
|
|
||||||
)
|
|
||||||
|
|
||||||
interface = Interface.objects.create(name='Interface 1', device=device, type='1000baset')
|
interface = Interface.objects.create(name='Interface 1', device=device, type='1000baset')
|
||||||
l2vpn = L2VPN.objects.create(name='L2VPN 1', type='vxlan', identifier=650001)
|
l2vpn = L2VPN.objects.create(name='L2VPN 1', type=L2VPNTypeChoices.TYPE_VXLAN, identifier=650001)
|
||||||
l2vpn_vlans = L2VPN.objects.create(name='L2VPN 2', type='vxlan', identifier=650002)
|
|
||||||
|
|
||||||
vlans = (
|
vlans = (
|
||||||
VLAN(name='Vlan 1', vid=1001),
|
VLAN(name='Vlan 1', vid=1001),
|
||||||
@ -846,9 +830,9 @@ class L2VPNTerminationTestCase(
|
|||||||
|
|
||||||
cls.csv_data = (
|
cls.csv_data = (
|
||||||
"l2vpn,vlan",
|
"l2vpn,vlan",
|
||||||
"L2VPN 2,Vlan 4",
|
"L2VPN 1,Vlan 4",
|
||||||
"L2VPN 2,Vlan 5",
|
"L2VPN 1,Vlan 5",
|
||||||
"L2VPN 2,Vlan 6",
|
"L2VPN 1,Vlan 6",
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {}
|
cls.bulk_edit_data = {}
|
||||||
@ -857,6 +841,7 @@ class L2VPNTerminationTestCase(
|
|||||||
# Custom assertions
|
# Custom assertions
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# TODO: Remove this
|
||||||
def assertInstanceEqual(self, instance, data, exclude=None, api=False):
|
def assertInstanceEqual(self, instance, data, exclude=None, api=False):
|
||||||
"""
|
"""
|
||||||
Override parent
|
Override parent
|
||||||
|
@ -6,46 +6,40 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col col-md-6">
|
<div class="col col-md-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">
|
<h5 class="card-header">L2VPN Attributes</h5>
|
||||||
L2VPN Attributes
|
<div class="card-body">
|
||||||
</h5>
|
<table class="table table-hover attr-table">
|
||||||
<div class="card-body">
|
<tr>
|
||||||
<table class="table table-hover attr-table
|
<th scope="row">Name</th>
|
||||||
<tr>
|
<td>{{ object.name|placeholder }}</td>
|
||||||
<th scope="row">Name</th>
|
</tr>
|
||||||
<td>{{ object.name|placeholder }}</td>
|
<tr>
|
||||||
</tr>
|
<th scope="row">Identifier</th>
|
||||||
<tr>
|
<td>{{ object.identifier|placeholder }}</td>
|
||||||
<th scope="row">Slug</th>
|
</tr>
|
||||||
<td>{{ object.slug|placeholder }}</td>
|
<tr>
|
||||||
</tr>
|
<th scope="row">Type</th>
|
||||||
<tr>
|
<td>{{ object.get_type_display }}</td>
|
||||||
<th scope="row">Identifier</th>
|
</tr>
|
||||||
<td>{{ object.identifier|placeholder }}</td>
|
<tr>
|
||||||
</tr>
|
<th scope="row">Description</th>
|
||||||
<tr>
|
<td>{{ object.description|placeholder }}</td>
|
||||||
<th scope="row">Type</th>
|
</tr>
|
||||||
<td>{{ object.get_type_display }}</td>
|
<tr>
|
||||||
</tr>
|
<th scope="row">Tenant</th>
|
||||||
<tr>
|
<td>{{ object.tenant|linkify|placeholder }}</td>
|
||||||
<th scope="row">Description</th>
|
</tr>
|
||||||
<td>{{ object.description|placeholder }}</td>
|
</table>
|
||||||
</tr>
|
</div>
|
||||||
<tr>
|
</div>
|
||||||
<th scope="row">Tenant</th>
|
{% include 'inc/panels/tags.html' with tags=object.tags.all url='ipam:l2vpn_list' %}
|
||||||
<td>{{ object.tenant|placeholder }}</td>
|
{% plugin_left_page object %}
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/contacts.html' %}
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-md-6">
|
<div class="col col-md-6">
|
||||||
{% include 'inc/panels/tags.html' with tags=object.tags.all url='circuits:circuit_list' %}
|
{% include 'inc/panels/contacts.html' %}
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
{% include 'inc/panels/custom_fields.html' %}
|
||||||
{% plugin_right_page object %}
|
{% plugin_right_page object %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
@ -58,24 +52,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col col-md-12">
|
<div class="col col-md-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">Terminations</h5>
|
<h5 class="card-header">Terminations</h5>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% render_table terminations_table 'inc/table.html' %}
|
{% render_table terminations_table 'inc/table.html' %}
|
||||||
</div>
|
</div>
|
||||||
{% if perms.ipam.add_l2vpntermination %}
|
{% if perms.ipam.add_l2vpntermination %}
|
||||||
<div class="card-footer text-end noprint">
|
<div class="card-footer text-end noprint">
|
||||||
<a href="{% url 'ipam:l2vpntermination_add' %}?l2vpn={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
|
<a href="{% url 'ipam:l2vpntermination_add' %}?l2vpn={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
|
||||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a Termination
|
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a Termination
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col col-md-12">
|
<div class="col col-md-12">
|
||||||
{% plugin_full_width_page object %}
|
{% plugin_full_width_page object %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -18,12 +18,12 @@
|
|||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="nav-item">
|
<li role="presentation" class="nav-item">
|
||||||
<button role="tab" type="button" id="interface_tab" data-bs-toggle="tab" aria-controls="interface" data-bs-target="#interface" class="nav-link {% if form.initial.interface %}active{% endif %}">
|
<button role="tab" type="button" id="interface_tab" data-bs-toggle="tab" aria-controls="interface" data-bs-target="#interface" class="nav-link {% if form.initial.interface %}active{% endif %}">
|
||||||
Interface
|
Device
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="nav-item">
|
<li role="presentation" class="nav-item">
|
||||||
<button role="tab" type="button" id="vminterface_tab" data-bs-toggle="tab" aria-controls="vminterface" data-bs-target="#vminterface" class="nav-link {% if form.initial.vminterface %}active{% endif %}">
|
<button role="tab" type="button" id="vminterface_tab" data-bs-toggle="tab" aria-controls="vminterface" data-bs-target="#vminterface" class="nav-link {% if form.initial.vminterface %}active{% endif %}">
|
||||||
VM Interface
|
Virtual Machine
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
Loading…
Reference in New Issue
Block a user