1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/instances/test_template_flag.py
catborise 1fb74d6378 fix(instances): turning a template back into a VM is checked against the quota
Templates do not count towards a user's quota and cannot be started.
Staff owners may mark and unmark their VMs as templates, so a staff
user could mark a VM as a template, use the freed quota elsewhere, and
unmark it again: the VM came back without any check, over the quota.

For users with a quota (everyone but superusers), turning a template
back into a VM now passes check_user_quota with the VM's size (one VM,
its vCPUs, memory and disks). If the quota is reached or cannot be
verified, it stays a template and the user is told why. Marking a VM as
a template frees quota and is not checked. The view takes the
per-user quota lock like the other quota-checked changes.

The existing template-flag test gives its mocked VM a size. The new
tests fail on the previous code.
2026-10-05 22:19:34 +03:00

75 lines
3.1 KiB
Python

"""
Only superusers and staff may mark or unmark a VM as a template.
The UI only disables the checkbox for other users, and a disabled checkbox is
not submitted, so the server must not derive is_template from its absence for
them.
"""
from unittest.mock import patch
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from accounts.models import UserInstance
from computes.models import Compute
from instances.models import Instance
class TemplateFlagTestCase(TestCase):
def setUp(self):
User = get_user_model()
self.superuser = User.objects.create_superuser(
username="tpl_super", email="tpl_super@example.com", password="x"
)
self.owner = User.objects.create_user(username="tpl_owner", password="x")
self.staff_owner = User.objects.create_user(
username="tpl_staff_owner", password="x", is_staff=True
)
self.compute = Compute.objects.create(
name="tpl-compute", hostname="127.0.0.1:1", login="root", password="", type=1
)
self.instance = Instance.objects.create(
compute=self.compute,
name="tpl-vm",
uuid="dddddddd-eeee-ffff-0000-111111111111",
)
for user in (self.owner, self.staff_owner):
UserInstance.objects.create(instance=self.instance, user=user, is_change=True)
def _change_options(self, user, data):
self.client.force_login(user)
with patch("instances.models.wvmInstance") as wvm:
# unmarking a template checks the owner's quota with the VM's size
wvm.return_value.get_vcpu.return_value = 1
wvm.return_value.get_memory.return_value = 1024
wvm.return_value.get_disk_devices.return_value = []
res = self.client.post(
reverse("instances:change_options", args=[self.instance.id]), data
)
self.assertEqual(res.status_code, 302)
self.instance.refresh_from_db()
def _make_template(self):
self.instance.is_template = True
self.instance.save(update_fields=["is_template"])
def test_owner_cannot_mark_vm_as_template(self):
self._change_options(self.owner, {"title": "t", "is_template": "True"})
self.assertFalse(self.instance.is_template)
def test_owner_editing_title_does_not_unmark_template(self):
self._make_template()
self._change_options(self.owner, {"title": "new title", "description": ""})
self.assertTrue(self.instance.is_template)
def test_staff_owner_can_mark_and_unmark_template(self):
self._change_options(self.staff_owner, {"title": "t", "is_template": "True"})
self.assertTrue(self.instance.is_template)
# An unchecked checkbox is not submitted: for staff that means "not a template".
self._change_options(self.staff_owner, {"title": "t"})
self.assertFalse(self.instance.is_template)
def test_superuser_can_unmark_template(self):
self._make_template()
self._change_options(self.superuser, {"title": "t"})
self.assertFalse(self.instance.is_template)