Closes #13086: Virtual circuits (#17933)

* WIP

* Add API tests

* Add remaining tests

* Add model docs

* Show virtual circuit connections on interfaces

* Misc cleanup per PR feedback

* Renumber migration

* Support nested terminations for virtual circuit bulk import
This commit is contained in:
Jeremy Stretch
2024-11-19 10:58:39 -05:00
committed by GitHub
parent 7376314821
commit d2168b107f
36 changed files with 2164 additions and 15 deletions

View File

@@ -2,7 +2,8 @@ from django.urls import reverse
from circuits.choices import *
from circuits.models import *
from dcim.models import Site
from dcim.choices import InterfaceTypeChoices
from dcim.models import Device, DeviceRole, DeviceType, Interface, Manufacturer, Site
from ipam.models import ASN, RIR
from utilities.testing import APITestCase, APIViewTestCases
@@ -397,3 +398,240 @@ class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
'provider': providers[1].pk,
'description': 'New description',
}
class VirtualCircuitTest(APIViewTestCases.APIViewTestCase):
model = VirtualCircuit
brief_fields = ['cid', 'description', 'display', 'id', 'provider_network', 'url']
bulk_update_data = {
'status': 'planned',
}
@classmethod
def setUpTestData(cls):
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
virtual_circuits = (
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 1'
),
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 2'
),
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 3'
),
)
VirtualCircuit.objects.bulk_create(virtual_circuits)
cls.create_data = [
{
'cid': 'Virtual Circuit 4',
'provider_network': provider_network.pk,
'provider_account': provider_account.pk,
'status': CircuitStatusChoices.STATUS_PLANNED,
},
{
'cid': 'Virtual Circuit 5',
'provider_network': provider_network.pk,
'provider_account': provider_account.pk,
'status': CircuitStatusChoices.STATUS_PLANNED,
},
{
'cid': 'Virtual Circuit 6',
'provider_network': provider_network.pk,
'provider_account': provider_account.pk,
'status': CircuitStatusChoices.STATUS_PLANNED,
},
]
class VirtualCircuitTerminationTest(APIViewTestCases.APIViewTestCase):
model = VirtualCircuitTermination
brief_fields = ['description', 'display', 'id', 'interface', 'role', 'url', 'virtual_circuit']
bulk_update_data = {
'description': 'New description',
}
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1')
device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
site = Site.objects.create(name='Site 1', slug='site-1')
devices = (
Device(site=site, name='hub', device_type=device_type, role=device_role),
Device(site=site, name='spoke1', device_type=device_type, role=device_role),
Device(site=site, name='spoke2', device_type=device_type, role=device_role),
Device(site=site, name='spoke3', device_type=device_type, role=device_role),
)
Device.objects.bulk_create(devices)
physical_interfaces = (
Interface(device=devices[0], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
Interface(device=devices[1], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
Interface(device=devices[2], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
Interface(device=devices[3], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
)
Interface.objects.bulk_create(physical_interfaces)
virtual_interfaces = (
# Point-to-point VCs
Interface(
device=devices[0],
name='eth0.1',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[0],
name='eth0.2',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[0],
name='eth0.3',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[1],
name='eth0.1',
parent=physical_interfaces[1],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[2],
name='eth0.1',
parent=physical_interfaces[2],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[3],
name='eth0.1',
parent=physical_interfaces[3],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
# Hub and spoke VCs
Interface(
device=devices[0],
name='eth0.9',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[1],
name='eth0.9',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[2],
name='eth0.9',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[3],
name='eth0.9',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
)
Interface.objects.bulk_create(virtual_interfaces)
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
virtual_circuits = (
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 1'
),
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 2'
),
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 3'
),
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 4'
),
)
VirtualCircuit.objects.bulk_create(virtual_circuits)
virtual_circuit_terminations = (
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[0],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[0]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[0],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[3]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[1],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[1]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[1],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[4]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[2],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[2]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[2],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[5]
),
)
VirtualCircuitTermination.objects.bulk_create(virtual_circuit_terminations)
cls.create_data = [
{
'virtual_circuit': virtual_circuits[3].pk,
'role': VirtualCircuitTerminationRoleChoices.ROLE_HUB,
'interface': virtual_interfaces[6].pk
},
{
'virtual_circuit': virtual_circuits[3].pk,
'role': VirtualCircuitTerminationRoleChoices.ROLE_SPOKE,
'interface': virtual_interfaces[7].pk
},
{
'virtual_circuit': virtual_circuits[3].pk,
'role': VirtualCircuitTerminationRoleChoices.ROLE_SPOKE,
'interface': virtual_interfaces[8].pk
},
{
'virtual_circuit': virtual_circuits[3].pk,
'role': VirtualCircuitTerminationRoleChoices.ROLE_SPOKE,
'interface': virtual_interfaces[9].pk
},
]

View File

@@ -3,7 +3,8 @@ from django.test import TestCase
from circuits.choices import *
from circuits.filtersets import *
from circuits.models import *
from dcim.models import Cable, Region, Site, SiteGroup
from dcim.choices import InterfaceTypeChoices
from dcim.models import Cable, Device, DeviceRole, DeviceType, Interface, Manufacturer, Region, Site, SiteGroup
from ipam.models import ASN, RIR
from netbox.choices import DistanceUnitChoices
from tenancy.models import Tenant, TenantGroup
@@ -678,3 +679,293 @@ class ProviderAccountTestCase(TestCase, ChangeLoggedFilterSetTests):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'provider': [providers[0].slug, providers[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class VirtualCircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VirtualCircuit.objects.all()
filterset = VirtualCircuitFilterSet
@classmethod
def setUpTestData(cls):
tenant_groups = (
TenantGroup(name='Tenant group 1', slug='tenant-group-1'),
TenantGroup(name='Tenant group 2', slug='tenant-group-2'),
TenantGroup(name='Tenant group 3', slug='tenant-group-3'),
)
for tenantgroup in tenant_groups:
tenantgroup.save()
tenants = (
Tenant(name='Tenant 1', slug='tenant-1', group=tenant_groups[0]),
Tenant(name='Tenant 2', slug='tenant-2', group=tenant_groups[1]),
Tenant(name='Tenant 3', slug='tenant-3', group=tenant_groups[2]),
)
Tenant.objects.bulk_create(tenants)
providers = (
Provider(name='Provider 1', slug='provider-1'),
Provider(name='Provider 2', slug='provider-2'),
Provider(name='Provider 3', slug='provider-3'),
)
Provider.objects.bulk_create(providers)
provider_accounts = (
ProviderAccount(name='Provider Account 1', provider=providers[0], account='A'),
ProviderAccount(name='Provider Account 2', provider=providers[1], account='B'),
ProviderAccount(name='Provider Account 3', provider=providers[2], account='C'),
)
ProviderAccount.objects.bulk_create(provider_accounts)
provider_networks = (
ProviderNetwork(name='Provider Network 1', provider=providers[0]),
ProviderNetwork(name='Provider Network 2', provider=providers[1]),
ProviderNetwork(name='Provider Network 3', provider=providers[2]),
)
ProviderNetwork.objects.bulk_create(provider_networks)
virutal_circuits = (
VirtualCircuit(
provider_network=provider_networks[0],
provider_account=provider_accounts[0],
tenant=tenants[0],
cid='Virtual Circuit 1',
status=CircuitStatusChoices.STATUS_PLANNED,
description='virtualcircuit1',
),
VirtualCircuit(
provider_network=provider_networks[1],
provider_account=provider_accounts[1],
tenant=tenants[1],
cid='Virtual Circuit 2',
status=CircuitStatusChoices.STATUS_ACTIVE,
description='virtualcircuit2',
),
VirtualCircuit(
provider_network=provider_networks[2],
provider_account=provider_accounts[2],
tenant=tenants[2],
cid='Virtual Circuit 3',
status=CircuitStatusChoices.STATUS_DEPROVISIONING,
description='virtualcircuit3',
),
)
VirtualCircuit.objects.bulk_create(virutal_circuits)
def test_q(self):
params = {'q': 'virtualcircuit1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_cid(self):
params = {'cid': ['Virtual Circuit 1', 'Virtual Circuit 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_provider(self):
providers = Provider.objects.all()[:2]
params = {'provider_id': [providers[0].pk, providers[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'provider': [providers[0].slug, providers[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_provider_account(self):
provider_accounts = ProviderAccount.objects.all()[:2]
params = {'provider_account_id': [provider_accounts[0].pk, provider_accounts[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_provider_network(self):
provider_networks = ProviderNetwork.objects.all()[:2]
params = {'provider_network_id': [provider_networks[0].pk, provider_networks[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_status(self):
params = {'status': [CircuitStatusChoices.STATUS_ACTIVE, CircuitStatusChoices.STATUS_PLANNED]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_description(self):
params = {'description': ['virtualcircuit1', 'virtualcircuit2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_tenant(self):
tenants = Tenant.objects.all()[:2]
params = {'tenant_id': [tenants[0].pk, tenants[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'tenant': [tenants[0].slug, tenants[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_tenant_group(self):
tenant_groups = TenantGroup.objects.all()[:2]
params = {'tenant_group_id': [tenant_groups[0].pk, tenant_groups[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class VirtualCircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VirtualCircuitTermination.objects.all()
filterset = VirtualCircuitTerminationFilterSet
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1')
device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
site = Site.objects.create(name='Site 1', slug='site-1')
devices = (
Device(site=site, name='Device 1', device_type=device_type, role=device_role),
Device(site=site, name='Device 2', device_type=device_type, role=device_role),
Device(site=site, name='Device 3', device_type=device_type, role=device_role),
)
Device.objects.bulk_create(devices)
virtual_interfaces = (
# Device 1
Interface(
device=devices[0],
name='eth0.1',
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[0],
name='eth0.2',
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
# Device 2
Interface(
device=devices[1],
name='eth0.1',
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[1],
name='eth0.2',
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
# Device 3
Interface(
device=devices[2],
name='eth0.1',
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[2],
name='eth0.2',
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
)
Interface.objects.bulk_create(virtual_interfaces)
providers = (
Provider(name='Provider 1', slug='provider-1'),
Provider(name='Provider 2', slug='provider-2'),
Provider(name='Provider 3', slug='provider-3'),
)
Provider.objects.bulk_create(providers)
provider_networks = (
ProviderNetwork(provider=providers[0], name='Provider Network 1'),
ProviderNetwork(provider=providers[1], name='Provider Network 2'),
ProviderNetwork(provider=providers[2], name='Provider Network 3'),
)
ProviderNetwork.objects.bulk_create(provider_networks)
provider_accounts = (
ProviderAccount(provider=providers[0], account='Provider Account 1'),
ProviderAccount(provider=providers[1], account='Provider Account 2'),
ProviderAccount(provider=providers[2], account='Provider Account 3'),
)
ProviderAccount.objects.bulk_create(provider_accounts)
virtual_circuits = (
VirtualCircuit(
provider_network=provider_networks[0],
provider_account=provider_accounts[0],
cid='Virtual Circuit 1'
),
VirtualCircuit(
provider_network=provider_networks[1],
provider_account=provider_accounts[1],
cid='Virtual Circuit 2'
),
VirtualCircuit(
provider_network=provider_networks[2],
provider_account=provider_accounts[2],
cid='Virtual Circuit 3'
),
)
VirtualCircuit.objects.bulk_create(virtual_circuits)
virtual_circuit_terminations = (
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[0],
role=VirtualCircuitTerminationRoleChoices.ROLE_HUB,
interface=virtual_interfaces[0],
description='termination1'
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[0],
role=VirtualCircuitTerminationRoleChoices.ROLE_SPOKE,
interface=virtual_interfaces[3],
description='termination2'
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[1],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[1],
description='termination3'
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[1],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[4],
description='termination4'
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[2],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[2],
description='termination5'
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[2],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[5],
description='termination6'
),
)
VirtualCircuitTermination.objects.bulk_create(virtual_circuit_terminations)
def test_q(self):
params = {'q': 'termination1'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_description(self):
params = {'description': ['termination1', 'termination2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_virtual_circuit_id(self):
virtual_circuits = VirtualCircuit.objects.filter()[:2]
params = {'virtual_circuit_id': [virtual_circuits[0].pk, virtual_circuits[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
def test_provider(self):
providers = Provider.objects.all()[:2]
params = {'provider_id': [providers[0].pk, providers[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
params = {'provider': [providers[0].slug, providers[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
def test_provider_network(self):
provider_networks = ProviderNetwork.objects.all()[:2]
params = {'provider_network_id': [provider_networks[0].pk, provider_networks[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
def test_provider_account(self):
provider_accounts = ProviderAccount.objects.all()[:2]
params = {'provider_account_id': [provider_accounts[0].pk, provider_accounts[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
params = {'provider_account': [provider_accounts[0].account, provider_accounts[1].account]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
def test_interface(self):
interfaces = Interface.objects.all()[:2]
params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@@ -7,7 +7,8 @@ from django.urls import reverse
from circuits.choices import *
from circuits.models import *
from core.models import ObjectType
from dcim.models import Cable, Interface, Site
from dcim.choices import InterfaceTypeChoices
from dcim.models import Cable, Device, DeviceRole, DeviceType, Interface, Manufacturer, Site
from ipam.models import ASN, RIR
from netbox.choices import ImportFormatChoices
from users.models import ObjectPermission
@@ -341,7 +342,7 @@ class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
}
class TestCase(ViewTestCases.PrimaryObjectViewTestCase):
class CircuitTerminationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = CircuitTermination
@classmethod
@@ -518,3 +519,319 @@ class CircuitGroupAssignmentTestCase(
cls.bulk_edit_data = {
'priority': CircuitPriorityChoices.PRIORITY_INACTIVE,
}
class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = VirtualCircuit
def setUp(self):
super().setUp()
self.add_permissions(
'circuits.add_virtualcircuittermination',
)
@classmethod
def setUpTestData(cls):
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
provider_networks = (
ProviderNetwork(provider=provider, name='Provider Network 1'),
ProviderNetwork(provider=provider, name='Provider Network 2'),
)
ProviderNetwork.objects.bulk_create(provider_networks)
provider_accounts = (
ProviderAccount(provider=provider, account='Provider Account 1'),
ProviderAccount(provider=provider, account='Provider Account 2'),
)
ProviderAccount.objects.bulk_create(provider_accounts)
virtual_circuits = (
VirtualCircuit(
provider_network=provider_networks[0],
provider_account=provider_accounts[0],
cid='Virtual Circuit 1'
),
VirtualCircuit(
provider_network=provider_networks[0],
provider_account=provider_accounts[0],
cid='Virtual Circuit 2'
),
VirtualCircuit(
provider_network=provider_networks[0],
provider_account=provider_accounts[0],
cid='Virtual Circuit 3'
),
)
VirtualCircuit.objects.bulk_create(virtual_circuits)
device = create_test_device('Device 1')
interfaces = (
Interface(device=device, name='Interface 1', type=InterfaceTypeChoices.TYPE_VIRTUAL),
Interface(device=device, name='Interface 2', type=InterfaceTypeChoices.TYPE_VIRTUAL),
Interface(device=device, name='Interface 3', type=InterfaceTypeChoices.TYPE_VIRTUAL),
)
Interface.objects.bulk_create(interfaces)
tags = create_tags('Alpha', 'Bravo', 'Charlie')
cls.form_data = {
'cid': 'Virtual Circuit X',
'provider_network': provider_networks[1].pk,
'provider_account': provider_accounts[1].pk,
'status': CircuitStatusChoices.STATUS_PLANNED,
'description': 'A new virtual circuit',
'comments': 'Some comments',
'tags': [t.pk for t in tags],
}
cls.csv_data = (
"cid,provider_network,provider_account,status",
f"Virtual Circuit 4,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}",
f"Virtual Circuit 5,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}",
f"Virtual Circuit 6,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}",
)
cls.csv_update_data = (
"id,cid,description,status",
f"{virtual_circuits[0].pk},Virtual Circuit A,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
f"{virtual_circuits[1].pk},Virtual Circuit B,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
f"{virtual_circuits[2].pk},Virtual Circuit C,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
)
cls.bulk_edit_data = {
'provider_network': provider_networks[1].pk,
'provider_account': provider_accounts[1].pk,
'status': CircuitStatusChoices.STATUS_DECOMMISSIONED,
'description': 'New description',
'comments': 'New comments',
}
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[])
def test_bulk_import_objects_with_terminations(self):
interfaces = Interface.objects.filter(type=InterfaceTypeChoices.TYPE_VIRTUAL)
json_data = f"""
[
{{
"cid": "Virtual Circuit 7",
"provider_network": "Provider Network 1",
"status": "active",
"terminations": [
{{
"role": "hub",
"interface": {interfaces[0].pk}
}},
{{
"role": "spoke",
"interface": {interfaces[1].pk}
}},
{{
"role": "spoke",
"interface": {interfaces[2].pk}
}}
]
}}
]
"""
initial_count = self._get_queryset().count()
data = {
'data': json_data,
'format': ImportFormatChoices.JSON,
}
# Assign model-level permission
obj_perm = ObjectPermission(
name='Test permission',
actions=['add']
)
obj_perm.save()
obj_perm.users.add(self.user)
obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model))
# Try GET with model-level permission
self.assertHttpStatus(self.client.get(self._get_url('import')), 200)
# Test POST with permission
self.assertHttpStatus(self.client.post(self._get_url('import'), data), 302)
self.assertEqual(self._get_queryset().count(), initial_count + 1)
class VirtualCircuitTerminationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = VirtualCircuitTermination
@classmethod
def setUpTestData(cls):
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1')
device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
site = Site.objects.create(name='Site 1', slug='site-1')
devices = (
Device(site=site, name='hub', device_type=device_type, role=device_role),
Device(site=site, name='spoke1', device_type=device_type, role=device_role),
Device(site=site, name='spoke2', device_type=device_type, role=device_role),
Device(site=site, name='spoke3', device_type=device_type, role=device_role),
)
Device.objects.bulk_create(devices)
physical_interfaces = (
Interface(device=devices[0], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
Interface(device=devices[1], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
Interface(device=devices[2], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
Interface(device=devices[3], name='eth0', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
)
Interface.objects.bulk_create(physical_interfaces)
virtual_interfaces = (
# Point-to-point VCs
Interface(
device=devices[0],
name='eth0.1',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[0],
name='eth0.2',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[0],
name='eth0.3',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[1],
name='eth0.1',
parent=physical_interfaces[1],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[2],
name='eth0.1',
parent=physical_interfaces[2],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[3],
name='eth0.1',
parent=physical_interfaces[3],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
# Hub and spoke VCs
Interface(
device=devices[0],
name='eth0.9',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[1],
name='eth0.9',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[2],
name='eth0.9',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
Interface(
device=devices[3],
name='eth0.9',
parent=physical_interfaces[0],
type=InterfaceTypeChoices.TYPE_VIRTUAL
),
)
Interface.objects.bulk_create(virtual_interfaces)
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
virtual_circuits = (
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 1'
),
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 2'
),
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 3'
),
VirtualCircuit(
provider_network=provider_network,
provider_account=provider_account,
cid='Virtual Circuit 4'
),
)
VirtualCircuit.objects.bulk_create(virtual_circuits)
virtual_circuit_terminations = (
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[0],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[0]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[0],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[3]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[1],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[1]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[1],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[4]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[2],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[2]
),
VirtualCircuitTermination(
virtual_circuit=virtual_circuits[2],
role=VirtualCircuitTerminationRoleChoices.ROLE_PEER,
interface=virtual_interfaces[5]
),
)
VirtualCircuitTermination.objects.bulk_create(virtual_circuit_terminations)
cls.form_data = {
'virtual_circuit': virtual_circuits[3].pk,
'role': VirtualCircuitTerminationRoleChoices.ROLE_HUB,
'interface': virtual_interfaces[6].pk
}
cls.csv_data = (
"virtual_circuit,role,interface,description",
f"Virtual Circuit 4,{VirtualCircuitTerminationRoleChoices.ROLE_HUB},{virtual_interfaces[6].pk},Hub",
f"Virtual Circuit 4,{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},{virtual_interfaces[7].pk},Spoke 1",
f"Virtual Circuit 4,{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},{virtual_interfaces[8].pk},Spoke 2",
f"Virtual Circuit 4,{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},{virtual_interfaces[9].pk},Spoke 3",
)
cls.csv_update_data = (
"id,role,description",
f"{virtual_circuit_terminations[0].pk},{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},New description",
f"{virtual_circuit_terminations[1].pk},{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},New description",
f"{virtual_circuit_terminations[2].pk},{VirtualCircuitTerminationRoleChoices.ROLE_SPOKE},New description",
)
cls.bulk_edit_data = {
'description': 'New description',
}