"""A pool a VM needs is not stopped or deleted: stopping one that holds a running VM's disk would take that disk away, deleting one a VM's definition names (a disk of type volume) would keep that VM from starting. A disk given by its file path keeps working without the pool's definition. Runs on a private libvirt test driver: "test:///default" is shared by the whole process.""" import tempfile from unittest.mock import patch import libvirt from computes.models import Compute from django.contrib.auth import get_user_model from django.contrib.messages import get_messages from django.test import TestCase from django.urls import reverse from rest_framework.test import APIClient NODE = "use-pool/use-pool" VOLUME = "v1.img1048576" def domain(name, disk): return (f"{name}1024hvm" f"") class PoolInUseTests(TestCase): def setUp(self): node = tempfile.NamedTemporaryFile("w", suffix=".xml") self.addCleanup(node.close) node.write(NODE) node.flush() self.conn = libvirt.open(f"test://{node.name}") self.addCleanup(self.conn.close) patcher = patch("vrtManager.connection.connection_manager.get_connection", return_value=self.conn) patcher.start() self.addCleanup(patcher.stop) self.pool = self.conn.storagePoolLookupByName("use-pool") self.path = self.pool.createXML(VOLUME, 0).path() self.compute = Compute.objects.create(name="pool-use", hostname="localhost", login="", password="", type=4) self.admin = get_user_model().objects.create_superuser("pool-use", "pu@example.com", "pw") self.client.force_login(self.admin) self.url = reverse("storage", args=[self.compute.id, "use-pool"]) def post(self, action): response = self.client.post(self.url, {action: ""}, HTTP_REFERER=f"http://testserver{self.url}") return [str(m) for m in get_messages(response.wsgi_request)] def test_a_pool_that_holds_a_running_vm_disk_is_not_stopped(self): self.conn.createXML(domain("disk-user", f"type='file'>"), 0) messages = self.post("stop") self.assertTrue(any(m.startswith("Pool use-pool holds disks of the running VMs disk-user") for m in messages), messages) self.assertTrue(self.pool.isActive()) self.conn.lookupByName("disk-user").destroy() self.post("stop") self.assertFalse(self.pool.isActive()) def test_the_api_does_not_stop_it_either(self): self.conn.createXML(domain("api-user", f"type='file'>"), 0) api = APIClient() api.force_login(self.admin) response = api.post(reverse("compute-storage-stop", kwargs={"compute_pk": self.compute.id, "pk": "use-pool"})) self.assertEqual(response.status_code, 400) self.assertIn("running VMs api-user", response.json()["detail"]) self.assertTrue(self.pool.isActive()) def test_a_pool_a_vm_definition_names_is_not_deleted(self): self.conn.defineXML(domain("by-name", "type='volume'>")) self.conn.defineXML(domain("by-path", f"type='file'>")) self.pool.destroy() messages = self.post("delete") self.assertTrue(any("by-name" in m and "would no longer start" in m for m in messages), messages) self.assertFalse(any("by-path" in m for m in messages), messages) self.assertIn("use-pool", self.conn.listDefinedStoragePools()) self.conn.lookupByName("by-name").undefine() self.post("delete") self.assertNotIn("use-pool", self.conn.listDefinedStoragePools())