mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-22 23:46:44 -06:00
Use existing disk field to store aggregate virtual disk size
This commit is contained in:
parent
f4aa2e9f62
commit
7eb6b2fc47
@ -145,12 +145,6 @@
|
||||
<td>
|
||||
{% if object.disk %}
|
||||
{{ 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 %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
|
@ -5,7 +5,7 @@ class VirtualizationConfig(AppConfig):
|
||||
name = 'virtualization'
|
||||
|
||||
def ready(self):
|
||||
from . import search
|
||||
from . import search, signals
|
||||
from .models import VirtualMachine
|
||||
from utilities.counters import connect_counters
|
||||
|
||||
|
@ -240,6 +240,11 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
|
||||
|
||||
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
|
||||
for family in [4, 6]:
|
||||
ip_choices = [(None, '---------')]
|
||||
|
@ -2,7 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import MinValueValidator
|
||||
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.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -120,12 +120,10 @@ class VirtualMachine(ContactsMixin, RenderConfigMixin, ConfigContextModel, Prima
|
||||
null=True,
|
||||
verbose_name=_('memory (MB)')
|
||||
)
|
||||
# TODO: Remove in v4.0
|
||||
disk = models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name=_('disk (GB)'),
|
||||
help_text=_('deprecated - use Virtual Disks')
|
||||
verbose_name=_('disk (GB)')
|
||||
)
|
||||
|
||||
# Counter fields
|
||||
@ -199,6 +197,17 @@ class VirtualMachine(ContactsMixin, RenderConfigMixin, ConfigContextModel, Prima
|
||||
).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
|
||||
interfaces = self.interfaces.all() if self.pk else None
|
||||
for family in (4, 6):
|
||||
|
16
netbox/virtualization/signals.py
Normal file
16
netbox/virtualization/signals.py
Normal 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']
|
||||
)
|
@ -90,3 +90,28 @@ class VirtualMachineTestCase(TestCase):
|
||||
# Uniqueness validation for name should ignore case
|
||||
with self.assertRaises(ValidationError):
|
||||
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()
|
||||
|
Loading…
Reference in New Issue
Block a user