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

Closes #8356: Add virtual disk to Virtual Machines (#14087)

* 8356 add virtual disk model

* 8356 add supplemental forms

* 8356 add menu

* 8356 cleanup views

* 8356 virtual machine tab

* 8356 migrations

* 8356 vm disk tables

* 8356 cleanup

* 8356 graphql

* 8356 graphql

* 8356 add components button

* 8356 bulk add on virtualmachine

* 8356 bulk add fixes

* 8356 api tests

* 8356 news tests add rename

* 8356 VirtualDiskCreateForm

* 8356 fix test

* 8356 add todo to remove disk from vm

* 8356 review changes

* 8356 fix test

* 8356 deprecate disk field

* 8356 review changes

* 8356 fix test

* 8356 fix test

* Simplify view actions

* 8356 review changes

* 8356 split trans tag

* 8356 add total virtual disk size to api

* 8356 add virtual disk list to virtual machine detail view

* 8356 move virtual disk size to property

* 8356 revert property

* Tweak display of deprecated disk field

* 8356 render single disk field

* 8356 update serializer

* 8356 model property

* 8356 fix test

* 8356 review changes

* Revert disk space annotation

* Use existing disk field to store aggregate virtual disk size

* Introduce abstract ComponentModel for VM components

* Add search index for VirtualDisk

* Misc cleanup

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
Arthur Hanson
2023-11-17 12:02:56 -08:00
committed by GitHub
parent e13bf48a35
commit 549b0ea107
31 changed files with 804 additions and 63 deletions

View File

@@ -5,9 +5,9 @@ from dcim.choices import InterfaceModeChoices
from dcim.models import Site
from extras.models import ConfigTemplate
from ipam.models import VLAN, VRF
from utilities.testing import APITestCase, APIViewTestCases, create_test_device
from utilities.testing import APITestCase, APIViewTestCases, create_test_device, create_test_virtualmachine
from virtualization.choices import *
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
from virtualization.models import *
class AppTest(APITestCase):
@@ -256,10 +256,7 @@ class VMInterfaceTest(APIViewTestCases.APIViewTestCase):
@classmethod
def setUpTestData(cls):
clustertype = ClusterType.objects.create(name='Test Cluster Type 1', slug='test-cluster-type-1')
cluster = Cluster.objects.create(name='Test Cluster 1', type=clustertype)
virtualmachine = VirtualMachine.objects.create(cluster=cluster, name='Test VM 1')
virtualmachine = create_test_virtualmachine('Virtual Machine 1')
interfaces = (
VMInterface(virtual_machine=virtualmachine, name='Interface 1'),
@@ -336,3 +333,41 @@ class VMInterfaceTest(APIViewTestCases.APIViewTestCase):
]
self.client.delete(self._get_list_url(), data, format='json', **self.header)
self.assertEqual(virtual_machine.interfaces.count(), 2) # Child & parent were both deleted
class VirtualDiskTest(APIViewTestCases.APIViewTestCase):
model = VirtualDisk
brief_fields = ['display', 'id', 'name', 'size', 'url', 'virtual_machine']
bulk_update_data = {
'size': 888,
}
graphql_base_name = 'virtual_disk'
@classmethod
def setUpTestData(cls):
virtualmachine = create_test_virtualmachine('Virtual Machine 1')
disks = (
VirtualDisk(virtual_machine=virtualmachine, name='Disk 1', size=10),
VirtualDisk(virtual_machine=virtualmachine, name='Disk 2', size=20),
VirtualDisk(virtual_machine=virtualmachine, name='Disk 3', size=30),
)
VirtualDisk.objects.bulk_create(disks)
cls.create_data = [
{
'virtual_machine': virtualmachine.pk,
'name': 'Disk 4',
'size': 10,
},
{
'virtual_machine': virtualmachine.pk,
'name': 'Disk 5',
'size': 20,
},
{
'virtual_machine': virtualmachine.pk,
'name': 'Disk 6',
'size': 30,
},
]

View File

@@ -6,7 +6,7 @@ from tenancy.models import Tenant, TenantGroup
from utilities.testing import ChangeLoggedFilterSetTests, create_test_device
from virtualization.choices import *
from virtualization.filtersets import *
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
from virtualization.models import *
class ClusterTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
@@ -534,3 +534,46 @@ class VMInterfaceTestCase(TestCase, ChangeLoggedFilterSetTests):
def test_description(self):
params = {'description': ['foobar1', 'foobar2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class VirtualDiskTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VirtualDisk.objects.all()
filterset = VirtualDiskFilterSet
@classmethod
def setUpTestData(cls):
cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
cluster = Cluster.objects.create(name='Cluster 1', type=cluster_type)
vms = (
VirtualMachine(name='Virtual Machine 1', cluster=cluster),
VirtualMachine(name='Virtual Machine 2', cluster=cluster),
VirtualMachine(name='Virtual Machine 3', cluster=cluster),
)
VirtualMachine.objects.bulk_create(vms)
disks = (
VirtualDisk(virtual_machine=vms[0], name='Disk 1', size=1, description='A'),
VirtualDisk(virtual_machine=vms[1], name='Disk 2', size=2, description='B'),
VirtualDisk(virtual_machine=vms[2], name='Disk 3', size=3, description='C'),
)
VirtualDisk.objects.bulk_create(disks)
def test_virtual_machine(self):
vms = VirtualMachine.objects.all()[:2]
params = {'virtual_machine_id': [vms[0].pk, vms[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'virtual_machine': [vms[0].name, vms[1].name]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self):
params = {'name': ['Disk 1', 'Disk 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_size(self):
params = {'size': [1, 2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_description(self):
params = {'description': ['A', 'B']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@@ -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()

View File

@@ -5,9 +5,9 @@ from netaddr import EUI
from dcim.choices import InterfaceModeChoices
from dcim.models import DeviceRole, Platform, Site
from ipam.models import VLAN, VRF
from utilities.testing import ViewTestCases, create_tags, create_test_device
from utilities.testing import ViewTestCases, create_tags, create_test_device, create_test_virtualmachine
from virtualization.choices import *
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
from virtualization.models import *
class ClusterGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
@@ -403,3 +403,54 @@ class VMInterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
}
self.client.post(self._get_url('bulk_delete'), data)
self.assertEqual(virtual_machine.interfaces.count(), 2) # Child & parent were both deleted
class VirtualDiskTestCase(ViewTestCases.DeviceComponentViewTestCase):
model = VirtualDisk
validation_excluded_fields = ('name',)
@classmethod
def setUpTestData(cls):
virtualmachine = create_test_virtualmachine('Virtual Machine 1')
disks = VirtualDisk.objects.bulk_create([
VirtualDisk(virtual_machine=virtualmachine, name='Virtual Disk 1', size=10),
VirtualDisk(virtual_machine=virtualmachine, name='Virtual Disk 2', size=10),
VirtualDisk(virtual_machine=virtualmachine, name='Virtual Disk 3', size=10),
])
tags = create_tags('Alpha', 'Bravo', 'Charlie')
cls.form_data = {
'virtual_machine': virtualmachine.pk,
'name': 'Virtual Disk X',
'size': 20,
'description': 'New description',
'tags': [t.pk for t in tags],
}
cls.bulk_create_data = {
'virtual_machine': virtualmachine.pk,
'name': 'Virtual Disk [4-6]',
'size': 10,
'tags': [t.pk for t in tags],
}
cls.csv_data = (
f"virtual_machine,name,size,description",
f"Virtual Machine 1,Disk 4,20,Fourth",
f"Virtual Machine 1,Disk 5,20,Fifth",
f"Virtual Machine 1,Disk 6,20,Sixth",
)
cls.csv_update_data = (
f"id,name,size",
f"{disks[0].pk},disk1,20",
f"{disks[1].pk},disk2,20",
f"{disks[2].pk},disk3,20",
)
cls.bulk_edit_data = {
'size': 30,
'description': 'New description',
}