1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Initial work on #4721 (WIP)

This commit is contained in:
Jeremy Stretch
2020-06-22 13:10:56 -04:00
parent 181bcd70ad
commit 6cb31a274f
26 changed files with 481 additions and 215 deletions

View File

@ -5,11 +5,14 @@ from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.models import Device
from extras.models import ConfigContextModel, CustomFieldModel, TaggedItem
from dcim.choices import InterfaceModeChoices
from dcim.models import BaseInterface, Device
from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange, TaggedItem
from extras.utils import extras_features
from utilities.models import ChangeLoggedModel
from utilities.query_functions import CollateAsChar
from utilities.querysets import RestrictedQuerySet
from utilities.utils import serialize_object
from .choices import *
@ -17,6 +20,7 @@ __all__ = (
'Cluster',
'ClusterGroup',
'ClusterType',
'Interface',
'VirtualMachine',
)
@ -370,3 +374,109 @@ class VirtualMachine(ChangeLoggedModel, ConfigContextModel, CustomFieldModel):
@property
def site(self):
return self.cluster.site
#
# Interfaces
#
@extras_features('graphs', 'export_templates', 'webhooks')
class Interface(BaseInterface):
virtual_machine = models.ForeignKey(
to='virtualization.VirtualMachine',
on_delete=models.CASCADE,
related_name='interfaces'
)
description = models.CharField(
max_length=200,
blank=True
)
untagged_vlan = models.ForeignKey(
to='ipam.VLAN',
on_delete=models.SET_NULL,
related_name='vm_interfaces_as_untagged',
null=True,
blank=True,
verbose_name='Untagged VLAN'
)
tagged_vlans = models.ManyToManyField(
to='ipam.VLAN',
related_name='vm_interfaces_as_tagged',
blank=True,
verbose_name='Tagged VLANs'
)
ipaddresses = GenericRelation(
to='ipam.IPAddress',
content_type_field='assigned_object_type',
object_id_field='assigned_object_id'
)
tags = TaggableManager(
through=TaggedItem,
related_name='vm_interface'
)
objects = RestrictedQuerySet.as_manager()
csv_headers = [
'virtual_machine', 'name', 'enabled', 'mac_address', 'mtu', 'description', 'mode',
]
class Meta:
ordering = ('virtual_machine', CollateAsChar('_name'))
unique_together = ('virtual_machine', 'name')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('virtualization:interface', kwargs={'pk': self.pk})
def to_csv(self):
return (
self.virtual_machine.name,
self.name,
self.enabled,
self.mac_address,
self.mtu,
self.description,
self.get_mode_display(),
)
def clean(self):
# Validate untagged VLAN
if self.untagged_vlan and self.untagged_vlan.site not in [self.parent.site, None]:
raise ValidationError({
'untagged_vlan': "The untagged VLAN ({}) must belong to the same site as the interface's parent "
"virtual machine, or it must be global".format(self.untagged_vlan)
})
def save(self, *args, **kwargs):
# Remove untagged VLAN assignment for non-802.1Q interfaces
if self.mode is None:
self.untagged_vlan = None
# Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.)
if self.pk and self.mode != InterfaceModeChoices.MODE_TAGGED:
self.tagged_vlans.clear()
return super().save(*args, **kwargs)
def to_objectchange(self, action):
# Annotate the parent VirtualMachine
return ObjectChange(
changed_object=self,
object_repr=str(self),
action=action,
related_object=self.virtual_machine,
object_data=serialize_object(self)
)
@property
def parent(self):
return self.virtual_machine
@property
def count_ipaddresses(self):
return self.ip_addresses.count()