Use existing disk field to store aggregate virtual disk size

This commit is contained in:
Jeremy Stretch 2023-11-14 15:14:19 -05:00
parent f4aa2e9f62
commit 7eb6b2fc47
6 changed files with 60 additions and 11 deletions

View File

@ -145,12 +145,6 @@
<td> <td>
{% if object.disk %} {% if object.disk %}
{{ object.disk }} {% trans "GB" context "Abbreviation for gigabyte" %} {{ object.disk }} {% trans "GB" context "Abbreviation for gigabyte" %}
<span class="text-warning">
<i class="mdi mdi-alert" title="{% trans "This field has been deprecated and will be removed in a future release." %}"></i>
</span>
{% elif object.disk_size %}
{{ object.disk_size }} {% trans "GB" context "Abbreviation for gigabyte" %}
({{ object.virtualdisks.count }} {% trans "disks" %})
{% else %} {% else %}
{{ ''|placeholder }} {{ ''|placeholder }}
{% endif %} {% endif %}

View File

@ -5,7 +5,7 @@ class VirtualizationConfig(AppConfig):
name = 'virtualization' name = 'virtualization'
def ready(self): def ready(self):
from . import search from . import search, signals
from .models import VirtualMachine from .models import VirtualMachine
from utilities.counters import connect_counters from utilities.counters import connect_counters

View File

@ -240,6 +240,11 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
if self.instance.pk: if self.instance.pk:
# Disable the disk field if one or more VirtualDisks have been created
if self.instance.virtualdisks.exists():
self.fields['disk'].widget.attrs['disabled'] = True
self.fields['disk'].help_text = _("Disk size is managed via the attachment of virtual disks.")
# Compile list of choices for primary IPv4 and IPv6 addresses # Compile list of choices for primary IPv4 and IPv6 addresses
for family in [4, 6]: for family in [4, 6]:
ip_choices = [(None, '---------')] ip_choices = [(None, '---------')]

View File

@ -2,7 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from django.db import models from django.db import models
from django.db.models import Q from django.db.models import Q, Sum
from django.db.models.functions import Lower from django.db.models.functions import Lower
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -120,12 +120,10 @@ class VirtualMachine(ContactsMixin, RenderConfigMixin, ConfigContextModel, Prima
null=True, null=True,
verbose_name=_('memory (MB)') verbose_name=_('memory (MB)')
) )
# TODO: Remove in v4.0
disk = models.PositiveIntegerField( disk = models.PositiveIntegerField(
blank=True, blank=True,
null=True, null=True,
verbose_name=_('disk (GB)'), verbose_name=_('disk (GB)')
help_text=_('deprecated - use Virtual Disks')
) )
# Counter fields # Counter fields
@ -199,6 +197,17 @@ class VirtualMachine(ContactsMixin, RenderConfigMixin, ConfigContextModel, Prima
).format(device=self.device, cluster=self.cluster) ).format(device=self.device, cluster=self.cluster)
}) })
# Validate aggregate disk size
if self.pk:
total_disk = self.virtualdisks.aggregate(Sum('size', default=0))['size__sum']
if total_disk and self.disk != total_disk:
raise ValidationError({
'disk': _(
"The specified disk size ({size}) must match the aggregate size of assigned virtual disks "
"({total_size})."
).format(size=self.disk, total_size=total_disk)
})
# Validate primary IP addresses # Validate primary IP addresses
interfaces = self.interfaces.all() if self.pk else None interfaces = self.interfaces.all() if self.pk else None
for family in (4, 6): for family in (4, 6):

View File

@ -0,0 +1,16 @@
from django.db.models import Sum
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from .models import VirtualDisk, VirtualMachine
@receiver((post_delete, post_save), sender=VirtualDisk)
def update_circuit(instance, **kwargs):
"""
When a VirtualDisk has been modified, update the aggregate disk_size value of its VM.
"""
vm = instance.virtual_machine
VirtualMachine.objects.filter(pk=vm.pk).update(
disk=vm.virtualdisks.aggregate(Sum('size'))['size__sum']
)

View File

@ -90,3 +90,28 @@ class VirtualMachineTestCase(TestCase):
# Uniqueness validation for name should ignore case # Uniqueness validation for name should ignore case
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
vm2.full_clean() vm2.full_clean()
def test_disk_size(self):
vm = VirtualMachine(
cluster=Cluster.objects.first(),
name='Virtual Machine 1'
)
vm.save()
vm.refresh_from_db()
self.assertEqual(vm.disk, None)
# Create two VirtualDisks
VirtualDisk.objects.create(virtual_machine=vm, name='Virtual Disk 1', size=10)
VirtualDisk.objects.create(virtual_machine=vm, name='Virtual Disk 2', size=10)
vm.refresh_from_db()
self.assertEqual(vm.disk, 20)
# Delete one VirtualDisk
VirtualDisk.objects.first().delete()
vm.refresh_from_db()
self.assertEqual(vm.disk, 10)
# Attempt to manually overwrite the aggregate disk size
vm.disk = 30
with self.assertRaises(ValidationError):
vm.full_clean()