mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-11 12:46:49 +00:00
fix(instances): a failed VM creation leaves no volumes behind
Web form: the cache mode and the UEFI firmware value were checked only after the disk volume had been created; an invalid one answered 500 and left the volume. All checks now run before any allocation. Volumes the request creates are removed on any failure up to the definition; ones that cannot be removed are reported. After the definition the VM uses them, so a later failure keeps them. API: the new volume was never removed when the definition failed, and the error was a 500. It is removed now and a libvirt error returns 400.
This commit is contained in:
parent
5def4e41fd
commit
abdd229a1f
4 changed files with 337 additions and 158 deletions
48
instances/test_create_rollback.py
Normal file
48
instances/test_create_rollback.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
from unittest.mock import patch
|
||||
|
||||
from computes.models import Compute
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from libvirt import libvirtError
|
||||
|
||||
FORM = {
|
||||
"name": "rb-vm", "firmware": "BIOS", "vcpu": 1, "vcpu_mode": "host-model", "memory": 128,
|
||||
"hdd_size": 1, "storage": "default", "mac": "52:54:00:aa:04:01", "networks": "default",
|
||||
"nwfilter": "", "net_model": "virtio", "cache_mode": "none", "video": "vga",
|
||||
"listener_addr": "0.0.0.0", "console_pass": "", "add_cdrom": "None", "add_input": "None",
|
||||
"create": True,
|
||||
}
|
||||
|
||||
|
||||
class CreateRollbackTestCase(TestCase):
|
||||
"""R-08: volumes are removed only while the VM is not defined yet."""
|
||||
|
||||
def setUp(self):
|
||||
admin = get_user_model().objects.create_superuser("rb_admin", "r@example.com", "pw")
|
||||
self.client.force_login(admin)
|
||||
self.client.raise_request_exception = False
|
||||
self.compute = Compute.objects.create(name="rb", hostname="127.0.0.1", login="", password="", type=4)
|
||||
|
||||
def post(self, **conn_setup):
|
||||
with patch("instances.views.wvmCreate") as wvm:
|
||||
conn = wvm.return_value
|
||||
conn.get_cache_modes.return_value = {"none": "Disable cache"}
|
||||
conn.get_instances.return_value = []
|
||||
conn.get_storages.return_value = ["default"]
|
||||
conn.get_networks.return_value = ["default"]
|
||||
conn.create_volume.return_value = "/pool/rb-vm.qcow2"
|
||||
for attr, value in conn_setup.items():
|
||||
getattr(conn, attr).side_effect = value
|
||||
self.client.post(reverse("instances:create_instance", args=[self.compute.id, "x86_64", "q35"]), FORM)
|
||||
return conn
|
||||
|
||||
def test_failed_definition_removes_the_new_volume(self):
|
||||
conn = self.post(create_instance=libvirtError("rejected"))
|
||||
conn.delete_volume.assert_called_once_with("/pool/rb-vm.qcow2")
|
||||
|
||||
def test_failure_after_the_definition_keeps_the_volume(self):
|
||||
with patch("instances.views.Instance.objects.get_or_create", side_effect=RuntimeError("db down")):
|
||||
conn = self.post()
|
||||
conn.create_instance.assert_called_once()
|
||||
conn.delete_volume.assert_not_called()
|
||||
Loading…
Add table
Add a link
Reference in a new issue