mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
test(destroy): NVRAM deletion and the base of an overlay
Destroy deletes the NVRAM file only when asked (VIR_DOMAIN_UNDEFINE_NVRAM, otherwise KEEP_NVRAM): a unit test checks the flags, live tests check the file on the host both ways. A VM whose disk is an overlay with a snapshot goes with its own image and the snapshot metadata, and the base image stays, since other images may grow from it.
This commit is contained in:
parent
975b7f0baf
commit
f094982737
2 changed files with 83 additions and 3 deletions
|
|
@ -6,7 +6,7 @@ from django.contrib.auth import get_user_model
|
|||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from instances.models import Instance
|
||||
from libvirt import libvirtError
|
||||
from libvirt import VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, libvirtError
|
||||
|
||||
|
||||
class DestroyOrderTestCase(TestCase):
|
||||
|
|
@ -19,15 +19,29 @@ class DestroyOrderTestCase(TestCase):
|
|||
compute=compute, name="destroy-vm", uuid="11111111-2222-3333-4444-555555555555"
|
||||
)
|
||||
|
||||
def destroy(self, undefine_error=None):
|
||||
def destroy(self, undefine_error=None, data=None):
|
||||
with patch("instances.models.wvmInstance") as wvm:
|
||||
proxy = wvm.return_value
|
||||
proxy.instance.isActive.return_value = False
|
||||
proxy.split_disk_paths_by_use.return_value = (["/pool/own.qcow2"], ["/pool/shared.qcow2"])
|
||||
proxy.delete.side_effect = undefine_error
|
||||
self.client.post(reverse("instances:destroy", args=[self.instance.id]), {"delete_disk": "1"})
|
||||
self.client.post(reverse("instances:destroy", args=[self.instance.id]), data or {"delete_disk": "1"})
|
||||
return proxy
|
||||
|
||||
def test_the_nvram_goes_only_when_asked(self):
|
||||
for data, wanted, unwanted in (
|
||||
({"delete_nvram": "1"}, VIR_DOMAIN_UNDEFINE_NVRAM, VIR_DOMAIN_UNDEFINE_KEEP_NVRAM),
|
||||
({}, VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM),
|
||||
):
|
||||
with self.subTest(data=data):
|
||||
Instance.objects.get_or_create(
|
||||
compute=self.instance.compute, name="destroy-vm", uuid="11111111-2222-3333-4444-555555555555"
|
||||
)
|
||||
self.instance = Instance.objects.get(uuid="11111111-2222-3333-4444-555555555555")
|
||||
flags = self.destroy(data=data).delete.call_args[0][0]
|
||||
self.assertTrue(flags & wanted)
|
||||
self.assertFalse(flags & unwanted)
|
||||
|
||||
def test_disks_are_deleted_after_the_undefine(self):
|
||||
proxy = self.destroy()
|
||||
proxy.get_volume_by_path.assert_called_once_with("/pool/own.qcow2")
|
||||
|
|
|
|||
|
|
@ -210,6 +210,72 @@ class LiveDataLossTestCase(TestCase):
|
|||
|
||||
self.assertFalse(self.domain_exists(dom.UUIDString()), "paused VM is still running")
|
||||
|
||||
def nvram_files(self):
|
||||
"""The test VMs' files in libvirt's NVRAM directory, read through a
|
||||
transient pool (libvirt lists files only as volumes)."""
|
||||
pool = self.conn.storagePoolCreateXML(
|
||||
f"<pool type='dir'><name>{P}nvram</name><target><path>/var/lib/libvirt/qemu/nvram</path></target></pool>", 0
|
||||
)
|
||||
try:
|
||||
return {name for name in pool.listVolumes() if name.startswith(P)}
|
||||
finally:
|
||||
pool.destroy()
|
||||
|
||||
def _destroy_uefi_vm(self, data):
|
||||
dom = self.conn.defineXML(
|
||||
f"<domain type='kvm'><name>{P}r14-nvram</name><memory unit='MiB'>128</memory><vcpu>1</vcpu>"
|
||||
"<os firmware='efi'><type arch='x86_64' machine='q35'>hvm</type></os>"
|
||||
"<features><acpi/></features><devices/></domain>"
|
||||
)
|
||||
refr(self.compute)
|
||||
inst = Instance.objects.get(compute=self.compute, uuid=dom.UUIDString())
|
||||
dom.createWithFlags(libvirt.VIR_DOMAIN_START_PAUSED) # creates the NVRAM file
|
||||
dom.destroy()
|
||||
self.assertIn(f"{P}r14-nvram_VARS.fd", self.nvram_files())
|
||||
|
||||
self.post("destroy", inst, data)
|
||||
|
||||
self.assertFalse(self.domain_exists(dom.UUIDString()), "VM is still defined")
|
||||
return f"{P}r14-nvram_VARS.fd" in self.nvram_files()
|
||||
|
||||
def test_destroy_deletes_the_nvram_when_asked(self):
|
||||
self.assertFalse(self._destroy_uefi_vm({"delete_nvram": "1"}), "the NVRAM file is still there")
|
||||
|
||||
def test_destroy_keeps_the_nvram_otherwise(self):
|
||||
try:
|
||||
self.assertTrue(self._destroy_uefi_vm({}), "the NVRAM file was deleted")
|
||||
finally:
|
||||
pool = self.conn.storagePoolCreateXML(
|
||||
f"<pool type='dir'><name>{P}nvram</name><target><path>/var/lib/libvirt/qemu/nvram</path></target></pool>", 0
|
||||
)
|
||||
try:
|
||||
for name in pool.listVolumes():
|
||||
if name.startswith(P):
|
||||
pool.storageVolLookupByName(name).delete(0)
|
||||
finally:
|
||||
pool.destroy()
|
||||
|
||||
def test_destroy_of_an_overlay_keeps_its_base(self):
|
||||
# The base may be a template other images grow from; only the VM's
|
||||
# own top image goes, with the snapshot metadata.
|
||||
base = livetest.create_volume(self.conn, P + "r14-chain-base")
|
||||
pool = self.conn.storagePoolLookupByName(livetest.POOL)
|
||||
overlay = pool.createXML(
|
||||
f"<volume><name>{P}r14-chain.qcow2</name><capacity unit='MiB'>64</capacity>"
|
||||
f"<target><format type='qcow2'/></target><backingStore><path>{base}</path>"
|
||||
"<format type='qcow2'/></backingStore></volume>",
|
||||
0,
|
||||
).path()
|
||||
dom, inst = self.vm("r14-chain", [overlay])
|
||||
dom.snapshotCreateXML("<domainsnapshot><name>snap</name></domainsnapshot>", 0)
|
||||
|
||||
response = self.post("destroy", inst, {"delete_disk": "1"})
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertFalse(self.domain_exists(dom.UUIDString()), "VM is still defined")
|
||||
self.assertFalse(livetest.volume_exists(self.conn, overlay), "the VM's own image is still there")
|
||||
self.assertTrue(livetest.volume_exists(self.conn, base), "the base image was deleted")
|
||||
|
||||
# Delete a volume only after it is detached
|
||||
|
||||
def _delete_attached_volume(self, pause):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue