mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 11:46:49 +00:00
Settings > Options was four forms under bold sentences, most of them disabled while the VM ran. The owner chose this layout from three rendered options: one list, each row a setting with its description on the left and its control on the right: VM details (title, description), Template, primary video model, QEMU guest agent. vCPU hot plug moved to Resize > CPU, next to the vCPU counts. Codex reviewed the four forms; these are fixed: - Title, description and the video model are saved while the VM runs: they are in the persistent definition, used at the next start. - The template flag has its own form and view, set_template, for superusers and staff, and only for a shut-off VM: a running VM made a template left the quota while it kept running. Turning a template back into a VM checks the quota there, and each change is audited. The title form no longer touches the flag. - A new video model stays the primary one; the old model's memory and head settings, which are its own, go with it. - The agent and vCPU hot plug forms show the persistent definition; they showed the running VM's, so a pending change looked undone. - Enabling the guest agent adds its channel only where it is missing: saving Enabled again failed, and a channel pending the next start kept a running VM from getting one. - The agent line tells a VM that is not running, one without a channel, and a connected or not connected agent apart.
75 lines
3.8 KiB
Python
75 lines
3.8 KiB
Python
"""Templates do not count towards the quota and cannot be started. Turning a
|
|
template back into a VM adds it to its owner's usage, so for users with a
|
|
quota it is checked like any other increase. Only a shut-off VM changes."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from accounts.models import UserInstance
|
|
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 instances.models import Instance
|
|
from instances.utils import QUOTA_UNVERIFIED
|
|
|
|
|
|
class TemplateFlagQuotaTests(TestCase):
|
|
def setUp(self):
|
|
User = get_user_model()
|
|
self.staff = User.objects.create_user("tq-staff", password="pw", is_staff=True)
|
|
compute = Compute.objects.create(name="tq", hostname="10.0.0.5", login="u", password="p", type=1)
|
|
self.vm = Instance.objects.create(compute=compute, name="tq-vm", uuid="12345678-0000-0000-0000-00000000aaaa")
|
|
UserInstance.objects.create(user=self.staff, instance=self.vm, is_change=True)
|
|
|
|
def post(self, user, is_template, quota="", status=5):
|
|
self.client.force_login(user)
|
|
data = {"is_template": "on"} if is_template else {}
|
|
with patch("instances.models.wvmInstance") as wvm, patch(
|
|
"instances.views.utils.check_user_quota", return_value=quota
|
|
) as check:
|
|
wvm.return_value.get_status.return_value = status
|
|
wvm.return_value.get_vcpu.return_value = 2
|
|
wvm.return_value.get_memory.return_value = 2048
|
|
wvm.return_value.get_disk_devices.return_value = [{"size": 10 << 30}]
|
|
response = self.client.post(reverse("instances:set_template", args=[self.vm.id]), data)
|
|
self.vm.refresh_from_db()
|
|
return check, [str(m) for m in get_messages(response.wsgi_request)]
|
|
|
|
def test_making_a_template_needs_no_quota(self):
|
|
check, _ = self.post(self.staff, is_template=True)
|
|
self.assertTrue(self.vm.is_template)
|
|
check.assert_not_called()
|
|
|
|
def test_turning_a_template_into_a_vm_is_checked(self):
|
|
Instance.objects.filter(pk=self.vm.pk).update(is_template=True)
|
|
check, _ = self.post(self.staff, is_template=False)
|
|
self.assertFalse(self.vm.is_template)
|
|
check.assert_called_once_with(self.staff, 1, 2, 2048, 10)
|
|
|
|
def test_over_quota_the_template_stays_a_template(self):
|
|
Instance.objects.filter(pk=self.vm.pk).update(is_template=True)
|
|
_, messages = self.post(self.staff, is_template=False, quota="cpu")
|
|
self.assertTrue(self.vm.is_template)
|
|
self.assertTrue(any("quota" in m for m in messages), messages)
|
|
|
|
def test_an_unverifiable_quota_keeps_it_a_template(self):
|
|
Instance.objects.filter(pk=self.vm.pk).update(is_template=True)
|
|
_, messages = self.post(self.staff, is_template=False, quota=QUOTA_UNVERIFIED)
|
|
self.assertTrue(self.vm.is_template)
|
|
self.assertTrue(any("cannot be reached" in m for m in messages), messages)
|
|
|
|
def test_a_vm_that_is_not_shut_off_stays_as_it_is(self):
|
|
# a running VM made a template would leave the quota while it runs
|
|
for status in (1, 3):
|
|
with self.subTest(status=status):
|
|
check, messages = self.post(self.staff, is_template=True, status=status)
|
|
self.assertFalse(self.vm.is_template)
|
|
self.assertIn("Shut the VM down to change whether it is a template.", messages)
|
|
|
|
def test_superusers_have_no_quota(self):
|
|
Instance.objects.filter(pk=self.vm.pk).update(is_template=True)
|
|
admin = get_user_model().objects.create_superuser("tq-admin", "tq@example.com", "pw")
|
|
check, _ = self.post(admin, is_template=False, quota="cpu")
|
|
self.assertFalse(self.vm.is_template)
|
|
check.assert_not_called()
|