6347 Cache the number of each component type assigned to devices/VMs (#12632)

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
Arthur Hanson
2023-07-25 20:39:05 +07:00
committed by GitHub
parent de3022f362
commit a77917b614
23 changed files with 623 additions and 35 deletions

View File

@@ -80,12 +80,15 @@ class VirtualMachineSerializer(NetBoxModelSerializer):
primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
# Counter fields
interface_count = serializers.IntegerField(read_only=True)
class Meta:
model = VirtualMachine
fields = [
'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'platform',
'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments',
'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', 'interface_count',
]
validators = []
@@ -98,6 +101,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'platform',
'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments',
'local_context_data', 'tags', 'custom_fields', 'config_context', 'created', 'last_updated',
'interface_count',
]
@extend_schema_field(serializers.JSONField(allow_null=True))

View File

@@ -6,3 +6,8 @@ class VirtualizationConfig(AppConfig):
def ready(self):
from . import search
from .models import VirtualMachine
from utilities.counters import connect_counters
# Register counters
connect_counters(VirtualMachine)

View File

@@ -0,0 +1,35 @@
from django.db import migrations
from django.db.models import Count
import utilities.fields
def populate_virtualmachine_counts(apps, schema_editor):
VirtualMachine = apps.get_model('virtualization', 'VirtualMachine')
vms = list(VirtualMachine.objects.annotate(_interface_count=Count('interfaces', distinct=True)))
for vm in vms:
vm.interface_count = vm._interface_count
VirtualMachine.objects.bulk_update(vms, ['interface_count'])
class Migration(migrations.Migration):
dependencies = [
('virtualization', '0034_standardize_description_comments'),
]
operations = [
migrations.AddField(
model_name='virtualmachine',
name='interface_count',
field=utilities.fields.CounterCacheField(
default=0, to_field='virtual_machine', to_model='virtualization.VMInterface'
),
),
migrations.RunPython(
code=populate_virtualmachine_counts,
reverse_code=migrations.RunPython.noop
),
]

View File

@@ -11,9 +11,10 @@ from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet
from netbox.config import get_config
from netbox.models import NetBoxModel, PrimaryModel
from utilities.fields import NaturalOrderingField
from utilities.fields import CounterCacheField, NaturalOrderingField
from utilities.ordering import naturalize_interface
from utilities.query_functions import CollateAsChar
from utilities.tracking import TrackingModelMixin
from virtualization.choices import *
__all__ = (
@@ -120,6 +121,12 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
verbose_name='Disk (GB)'
)
# Counter fields
interface_count = CounterCacheField(
to_model='virtualization.VMInterface',
to_field='virtual_machine'
)
# Generic relation
contacts = GenericRelation(
to='tenancy.ContactAssignment'
@@ -222,7 +229,7 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
return None
class VMInterface(NetBoxModel, BaseInterface):
class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
virtual_machine = models.ForeignKey(
to='virtualization.VirtualMachine',
on_delete=models.CASCADE,

View File

@@ -1,10 +1,11 @@
import django_tables2 as tables
from django.utils.translation import gettext as _
from dcim.tables.devices import BaseInterfaceTable
from netbox.tables import NetBoxTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from virtualization.models import VirtualMachine, VMInterface
from netbox.tables import NetBoxTable, columns
__all__ = (
'VirtualMachineTable',
'VirtualMachineVMInterfaceTable',
@@ -70,6 +71,9 @@ class VirtualMachineTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable)
tags = columns.TagColumn(
url_name='virtualization:virtualmachine_list'
)
interface_count = tables.Column(
verbose_name=_('Interfaces')
)
class Meta(NetBoxTable.Meta):
model = VirtualMachine

View File

@@ -349,7 +349,7 @@ class VirtualMachineInterfacesView(generic.ObjectChildrenView):
template_name = 'virtualization/virtualmachine/interfaces.html'
tab = ViewTab(
label=_('Interfaces'),
badge=lambda obj: obj.interfaces.count(),
badge=lambda obj: obj.interface_count,
permission='virtualization.view_vminterface',
weight=500
)