-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from djothi/logicalinterface
feat: add LogicalInterface model
- Loading branch information
Showing
4 changed files
with
257 additions
and
0 deletions.
There are no files selected for viewing
39 changes: 39 additions & 0 deletions
39
netbox_cmdb/netbox_cmdb/migrations/0039_logicalinterface.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('ipam', '0060_alter_l2vpn_slug'), | ||
('netbox_cmdb', '0038_alter_vrf_unique_together_remove_vrf_device'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='LogicalInterface', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), | ||
('created', models.DateTimeField(auto_now_add=True, null=True)), | ||
('last_updated', models.DateTimeField(auto_now=True, null=True)), | ||
('index', models.PositiveSmallIntegerField()), | ||
('enabled', models.BooleanField(default=True)), | ||
('state', models.CharField(default='staging', max_length=50)), | ||
('monitoring_state', models.CharField(default='disabled', max_length=50)), | ||
('mtu', models.PositiveIntegerField(blank=True, null=True)), | ||
('type', models.CharField(default=None, max_length=2)), | ||
('mode', models.CharField(blank=True, default=None, max_length=20, null=True)), | ||
('description', models.CharField(blank=True, max_length=100, null=True)), | ||
('ipv4_address', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_ipv4_address', to='ipam.ipaddress')), | ||
('ipv6_address', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_ipv6_address', to='ipam.ipaddress')), | ||
('native_vlan', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_native_vlan', to='netbox_cmdb.vlan')), | ||
('parent_interface', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s', to='netbox_cmdb.deviceinterface')), | ||
('tagged_vlans', models.ManyToManyField(blank=True, default=None, related_name='%(class)s_tagged_vlans', to='netbox_cmdb.vlan')), | ||
('untagged_vlan', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_untagged_vlan', to='netbox_cmdb.vlan')), | ||
('vrf', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_vrf', to='netbox_cmdb.vrf')), | ||
], | ||
options={ | ||
'unique_together': {('index', 'parent_interface')}, | ||
}, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
114 changes: 114 additions & 0 deletions
114
netbox_cmdb/netbox_cmdb/tests/interface/test_logical_interface_models.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site | ||
from django.forms import ValidationError | ||
from django.test import TestCase | ||
|
||
from netbox_cmdb.models import VLAN, DeviceInterface, LogicalInterface | ||
|
||
|
||
class BaseTestCase(TestCase): | ||
def setUp(self): | ||
site = Site.objects.create(name="SiteTest", slug="site-test") | ||
manufacturer = Manufacturer.objects.create(name="test", slug="test") | ||
device_type = DeviceType.objects.create( | ||
manufacturer=manufacturer, model="model-test", slug="model-test" | ||
) | ||
device_role = DeviceRole.objects.create(name="role-test", slug="role-test") | ||
device = Device.objects.create( | ||
name="router-test", | ||
device_role=device_role, | ||
device_type=device_type, | ||
site=site, | ||
) | ||
|
||
DeviceInterface.objects.create( | ||
name="etp1", | ||
enabled=True, | ||
state="staging", | ||
monitoring_state="warning", | ||
device=device, | ||
autonegotiation=True, | ||
speed=100000, | ||
fec="rs", | ||
description="My device interface", | ||
) | ||
VLAN.objects.create(vid=1, name="VLAN 1", description="First VLAN") | ||
|
||
def test_valid_logical_interface(self): | ||
"""Test that a logical interface can be created.""" | ||
vlan = VLAN.objects.get(vid=1) | ||
device_interface = DeviceInterface.objects.get(name="etp1") | ||
|
||
logical_interface = LogicalInterface.objects.create( | ||
index=1, | ||
enabled=True, | ||
state="staging", | ||
monitoring_state="disabled", | ||
parent_interface=device_interface, | ||
mtu=1500, | ||
type="l3", | ||
description="My logical interface", | ||
) | ||
|
||
logical_interface.tagged_vlans.add(vlan) | ||
logical_interface.save() | ||
|
||
def test_invalid_logical_interface_untagged_and_tagged_vlans(self): | ||
"""Test that a logical interface cannot have both tagged and untagged VLANs.""" | ||
device_interface = DeviceInterface.objects.get(name="etp1") | ||
|
||
# Create VLAN instances | ||
vlan1 = VLAN.objects.create(vid=100, name="VLAN 100", description="First VLAN") | ||
vlan2 = VLAN.objects.create(vid=200, name="VLAN 200", description="Second VLAN") | ||
|
||
# Create a working LogicalInterface | ||
logical_interface = LogicalInterface.objects.create( | ||
index=2, | ||
enabled=True, | ||
state="staging", | ||
monitoring_state="disabled", | ||
parent_interface=device_interface, | ||
mtu=1500, | ||
type="l3", | ||
description="My logical interface", | ||
) | ||
|
||
# Set an untagged VLAN | ||
logical_interface.untagged_vlan = vlan1 | ||
logical_interface.save() | ||
|
||
with self.assertRaisesRegex( | ||
ValidationError, "Untagged VLAN cannot be combined with tagged VLANs or native VLAN." | ||
): | ||
# Add a tagged VLAN | ||
logical_interface.tagged_vlans.add(vlan2) | ||
logical_interface.save() | ||
|
||
def test_invalid_logical_interface_untagged_and_native_vlans(self): | ||
"""Test that a logical interface cannot have both untagged and native VLANs.""" | ||
device_interface = DeviceInterface.objects.get(name="etp1") | ||
|
||
vlan1 = VLAN.objects.create(vid=1000, name="VLAN 1000", description="First VLAN") | ||
vlan2 = VLAN.objects.create(vid=2000, name="VLAN 2000", description="Second VLAN") | ||
|
||
# Create a working LogicalInterface | ||
logical_interface = LogicalInterface.objects.create( | ||
index=3, | ||
enabled=True, | ||
state="staging", | ||
monitoring_state="disabled", | ||
parent_interface=device_interface, | ||
mtu=1500, | ||
type="l3", | ||
description="My logical interface", | ||
) | ||
|
||
# Set an untagged VLAN | ||
logical_interface.untagged_vlan = vlan1 | ||
logical_interface.save() | ||
|
||
with self.assertRaisesRegex( | ||
ValidationError, "Untagged VLAN cannot be combined with tagged VLANs or native VLAN." | ||
): | ||
# Set a native VLAN | ||
logical_interface.native_vlan = vlan2 | ||
logical_interface.save() |