mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 12:16:49 +00:00
chore: drop references to the local roadmap from code and tests
Comments, docstrings and live test names cited item IDs of a roadmap that is not part of the repository. They now say what is meant, or nothing where the sentence stands without them. Test assertions and behavior are unchanged.
This commit is contained in:
parent
39feb373ed
commit
f94b3cee7a
37 changed files with 87 additions and 89 deletions
|
|
@ -313,7 +313,7 @@ class CreateInstanceViewSet(viewsets.ViewSet):
|
|||
qemu_ga=serializer.validated_data["qemu_ga"],
|
||||
)
|
||||
except Exception as err:
|
||||
# R-08: a failed definition must not leave the new disk behind
|
||||
# A failed definition must not leave the new disk behind
|
||||
if path:
|
||||
try:
|
||||
conn.delete_volume(path)
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ class CreateInstance(models.Model):
|
|||
|
||||
|
||||
class InstanceTombstone(models.Model):
|
||||
"""Ownership of a VM that disappeared from its compute (R-05).
|
||||
"""Ownership of a VM that disappeared from its compute.
|
||||
|
||||
Kept for INSTANCE_OWNERSHIP_RETENTION_DAYS so that the owners come back
|
||||
when the same UUID shows up again, on this or another compute.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
"""
|
||||
Regression tests for ROADMAP Wave 0 item 4 (S-05): cloning another user's VM
|
||||
must require change permission on it (templates excepted), and the clone
|
||||
data must not be taken blindly from the POST body.
|
||||
Cloning another user's VM must require change permission on it (templates
|
||||
excepted), and the clone data must not be taken blindly from the POST body.
|
||||
"""
|
||||
from contextlib import contextmanager
|
||||
from unittest.mock import patch
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
ROADMAP Wave 0 item 5 (S-09): one rule decides who may open a VM's console
|
||||
(noVNC page, novncd, the virt-viewer .vv file, the VDI URL): a superuser or
|
||||
an owner of the VM. The global view_instances permission is read-only.
|
||||
One rule decides who may open a VM's console (noVNC page, novncd, the
|
||||
virt-viewer .vv file, the VDI URL): a superuser or an owner of the VM. The
|
||||
global view_instances permission is read-only.
|
||||
"""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ FORM = {
|
|||
|
||||
|
||||
class CreateRollbackTestCase(TestCase):
|
||||
"""R-08: volumes are removed only while the VM is not defined yet."""
|
||||
"""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")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
"""
|
||||
Regression tests for ROADMAP Wave 0 item 1 (S-02, S-03, S-04):
|
||||
disk and media mutation views must be superuser-only (matching the UI, where
|
||||
Disk and media mutation views must be superuser-only (matching the UI, where
|
||||
the Disk tab is only rendered for superusers), and even for superusers the
|
||||
views must not act on volumes or option values taken blindly from the client.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ def free_port(family=socket.AF_INET, host="127.0.0.1"):
|
|||
|
||||
|
||||
class GstfsdTestCase(unittest.TestCase):
|
||||
"""ROADMAP S-08: gstfsd hardening."""
|
||||
"""gstfsd hardening."""
|
||||
|
||||
def setUp(self):
|
||||
# novncd (imported by other tests) sets SIGCHLD to SIG_IGN, which hides exit codes.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Live checks for cloning (R-08). Runs only with TEST_LIBVIRT_HOST set."""
|
||||
"""Live checks for cloning. Runs only with TEST_LIBVIRT_HOST set."""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Live checks that a failed VM creation leaves no volumes behind (R-08).
|
||||
"""Live checks that a failed VM creation leaves no volumes behind.
|
||||
|
||||
Runs only with TEST_LIBVIRT_HOST set (see instances/livetest.py).
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
"""Live reproductions of the Wave 1a data-loss findings.
|
||||
"""Live tests for cases that lost disks or changed the wrong VM.
|
||||
|
||||
Each test asserts the safe behavior and is marked expectedFailure until
|
||||
its finding is fixed; a fix turns it into an unexpected success, which
|
||||
fails the run until the marker is removed. Runs only with
|
||||
Each test asserts the safe behavior. Known unfixed cases are marked
|
||||
expectedFailure; a fix turns them into unexpected successes, which fail
|
||||
the run until the marker is removed. Runs only with
|
||||
TEST_LIBVIRT_HOST set (see instances/livetest.py).
|
||||
"""
|
||||
|
||||
|
|
@ -90,10 +90,10 @@ class LiveDataLossTestCase(TestCase):
|
|||
except libvirt.libvirtError:
|
||||
return False
|
||||
|
||||
# R-03: external snapshots
|
||||
# External snapshots
|
||||
|
||||
@unittest.expectedFailure
|
||||
def test_r03_revert_external_snapshot_keeps_disk_added_later(self):
|
||||
def test_revert_external_snapshot_keeps_disk_added_later(self):
|
||||
base = livetest.create_volume(self.conn, P + "r03-a")
|
||||
dom, inst = self.vm("r03-a", [base])
|
||||
self.post("create_external_snapshot", inst, {"name": "snap"})
|
||||
|
|
@ -109,7 +109,7 @@ class LiveDataLossTestCase(TestCase):
|
|||
self.assertTrue(livetest.volume_exists(self.conn, later), "revert deleted a disk the snapshot never had")
|
||||
|
||||
@unittest.expectedFailure
|
||||
def test_r03_delete_older_external_snapshot_keeps_newer_snapshot_files(self):
|
||||
def test_delete_older_external_snapshot_keeps_newer_snapshot_files(self):
|
||||
base = livetest.create_volume(self.conn, P + "r03-b")
|
||||
dom, inst = self.vm("r03-b", [base])
|
||||
self.post("create_external_snapshot", inst, {"name": "older"})
|
||||
|
|
@ -122,7 +122,7 @@ class LiveDataLossTestCase(TestCase):
|
|||
self.assertTrue(livetest.volume_exists(self.conn, path), f"{path} was deleted")
|
||||
self.assertIn("s1.newer", dom.snapshotListNames(0))
|
||||
|
||||
# R-13: internal snapshots of UEFI VMs
|
||||
# Internal snapshots of UEFI VMs
|
||||
|
||||
def _uefi_internal_snapshot(self, running):
|
||||
base = livetest.create_volume(self.conn, P + "r13")
|
||||
|
|
@ -145,15 +145,15 @@ class LiveDataLossTestCase(TestCase):
|
|||
|
||||
return etree.tostring(etree.fromstring(dom.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)).find("os"))
|
||||
|
||||
def test_r13_uefi_internal_snapshot_of_a_stopped_vm(self):
|
||||
def test_uefi_internal_snapshot_of_a_stopped_vm(self):
|
||||
self._uefi_internal_snapshot(running=False)
|
||||
|
||||
def test_r13_uefi_internal_snapshot_of_a_running_vm(self):
|
||||
def test_uefi_internal_snapshot_of_a_running_vm(self):
|
||||
self._uefi_internal_snapshot(running=True)
|
||||
|
||||
# R-14: destroy
|
||||
# Destroy
|
||||
|
||||
def test_r14_destroy_keeps_a_volume_another_vm_uses(self):
|
||||
def test_destroy_keeps_a_volume_another_vm_uses(self):
|
||||
shared = livetest.create_volume(self.conn, P + "r14-shared")
|
||||
_, inst = self.vm("r14-a", [shared])
|
||||
self.vm("r14-b", [shared])
|
||||
|
|
@ -182,13 +182,13 @@ class LiveDataLossTestCase(TestCase):
|
|||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(livetest.volume_exists(self.conn, base), "deleted the backing file of another VM's disk")
|
||||
|
||||
def test_r14_destroy_keeps_the_backing_file_of_a_stopped_vm(self):
|
||||
def test_destroy_keeps_the_backing_file_of_a_stopped_vm(self):
|
||||
self._destroy_base_of_another_vms_overlay(running=False)
|
||||
|
||||
def test_r14_destroy_keeps_the_backing_file_of_a_running_vm(self):
|
||||
def test_destroy_keeps_the_backing_file_of_a_running_vm(self):
|
||||
self._destroy_base_of_another_vms_overlay(running=True)
|
||||
|
||||
def test_r14_destroy_with_managed_save_removes_the_vm(self):
|
||||
def test_destroy_with_managed_save_removes_the_vm(self):
|
||||
base = livetest.create_volume(self.conn, P + "r14-save")
|
||||
dom, inst = self.vm("r14-save", [base])
|
||||
dom.create()
|
||||
|
|
@ -200,7 +200,7 @@ class LiveDataLossTestCase(TestCase):
|
|||
self.assertFalse(self.domain_exists(uuid), "VM is still defined")
|
||||
self.assertFalse(Instance.objects.filter(uuid=uuid).exists())
|
||||
|
||||
def test_r14_destroy_of_a_paused_vm_removes_it(self):
|
||||
def test_destroy_of_a_paused_vm_removes_it(self):
|
||||
base = livetest.create_volume(self.conn, P + "r14-paused")
|
||||
dom, inst = self.vm("r14-paused", [base])
|
||||
dom.create()
|
||||
|
|
@ -210,7 +210,7 @@ class LiveDataLossTestCase(TestCase):
|
|||
|
||||
self.assertFalse(self.domain_exists(dom.UUIDString()), "paused VM is still running")
|
||||
|
||||
# S-02: delete a volume only after it is detached
|
||||
# Delete a volume only after it is detached
|
||||
|
||||
def _delete_attached_volume(self, pause):
|
||||
base = livetest.create_volume(self.conn, P + "s02")
|
||||
|
|
@ -229,13 +229,13 @@ class LiveDataLossTestCase(TestCase):
|
|||
self.assertIn("vdb", self.disk_sources(dom))
|
||||
self.assertTrue(livetest.volume_exists(self.conn, data), "volume deleted while the VM still uses it")
|
||||
|
||||
def test_s02_delete_volume_of_a_paused_vm(self):
|
||||
def test_delete_volume_of_a_paused_vm(self):
|
||||
self._delete_attached_volume(pause=True)
|
||||
|
||||
def test_s02_delete_volume_of_a_running_vm_without_guest_ack(self):
|
||||
def test_delete_volume_of_a_running_vm_without_guest_ack(self):
|
||||
self._delete_attached_volume(pause=False)
|
||||
|
||||
def test_s02_delete_volume_another_vm_uses_is_refused(self):
|
||||
def test_delete_volume_another_vm_uses_is_refused(self):
|
||||
base = livetest.create_volume(self.conn, P + "s02-own")
|
||||
shared = livetest.create_volume(self.conn, P + "s02-shared")
|
||||
_, inst = self.vm("s02-a", [base, shared])
|
||||
|
|
@ -246,9 +246,9 @@ class LiveDataLossTestCase(TestCase):
|
|||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(livetest.volume_exists(self.conn, shared), "deleted another VM's disk")
|
||||
|
||||
# R-06: operations follow the VM's UUID, not its name
|
||||
# Operations follow the VM's UUID, not its name
|
||||
|
||||
def test_r06_mutation_follows_uuid_after_names_are_swapped(self):
|
||||
def test_mutation_follows_uuid_after_names_are_swapped(self):
|
||||
dom_a, inst_a = self.vm("r06-a", [])
|
||||
dom_b, _ = self.vm("r06-b", [])
|
||||
dom_a.rename(P + "r06-tmp", 0)
|
||||
|
|
@ -260,7 +260,7 @@ class LiveDataLossTestCase(TestCase):
|
|||
self.assertIn("<title>for-a</title>", dom_a.XMLDesc(0))
|
||||
self.assertNotIn("<title>for-a</title>", dom_b.XMLDesc(0))
|
||||
|
||||
def test_r06_vm_replaced_under_the_same_name_is_not_touched(self):
|
||||
def test_vm_replaced_under_the_same_name_is_not_touched(self):
|
||||
dom_old, inst = self.vm("r06-c", [])
|
||||
dom_old.undefine()
|
||||
dom_new = livetest.define_vm(self.conn, P + "r06-c", [])
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Live checks for ISO mount/unmount (R-12). Runs only with TEST_LIBVIRT_HOST set."""
|
||||
"""Live checks for ISO mount/unmount. Runs only with TEST_LIBVIRT_HOST set."""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Live checks that persistent edits keep secrets and pending changes (R-01, R-02).
|
||||
"""Live checks that persistent edits keep secrets and pending changes.
|
||||
|
||||
Every edit that redefines the domain must start from the persistent
|
||||
definition with secrets (VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE).
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class SetRootPassTestCase(TestCase):
|
|||
@patch("socket.socket")
|
||||
@patch.object(Instance, "proxy")
|
||||
def test_set_root_pass_post(self, mock_proxy, mock_socket_cls):
|
||||
# Renamed on the host: gstfsd must get the name of this UUID's domain (R-06)
|
||||
# Renamed on the host: gstfsd must get the name of this UUID's domain
|
||||
mock_proxy.instance.name.return_value = "renamed-on-host"
|
||||
mock_proxy.get_status.return_value = 5 # status: running
|
||||
mock_sock = MagicMock()
|
||||
|
|
@ -46,7 +46,7 @@ class SetRootPassTestCase(TestCase):
|
|||
data = json.loads(sent_bytes.decode())
|
||||
self.assertEqual(data["action"], "password")
|
||||
self.assertEqual(data["vname"], "renamed-on-host")
|
||||
# SHA-512 crypt with a random salt (ROADMAP S-08), not the old fixed one
|
||||
# SHA-512 crypt with a random salt, not the old fixed one
|
||||
self.assertTrue(data["passwd"].startswith("$6$"))
|
||||
self.assertFalse(data["passwd"].startswith("$6$kgPoiREy$"))
|
||||
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ class InstanceSecurityMutationsTestCase(TestCase):
|
|||
|
||||
def test_disk_mutation_denied_with_is_change(self):
|
||||
# change_user has is_change=True, is_delete=False. Disk views are
|
||||
# superuser-only (S-02/S-03/S-04), so is_change alone is not enough.
|
||||
# superuser-only, so is_change alone is not enough.
|
||||
self.client.force_login(self.change_user)
|
||||
with patch("instances.models.wvmInstance"), patch("instances.views.wvmStorage") as mock_storage:
|
||||
res = self.client.post(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
ROADMAP S-22: only superusers and staff may mark or unmark a VM as a template.
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Regression tests for ROADMAP Wave 0 item 3 (S-06, S-07): JSON endpoints must
|
||||
not be served as text/html (reflected XSS), and templates must not build HTML
|
||||
by concatenating server data that contains user-controlled names (stored XSS).
|
||||
JSON endpoints must not be served as text/html (reflected XSS), and
|
||||
templates must not build HTML by concatenating server data that contains
|
||||
user-controlled names (stored XSS).
|
||||
"""
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ def can_open_console(user, instance):
|
|||
The single rule for console access (noVNC page, novncd, the virt-viewer
|
||||
.vv file and the VDI URL): an active superuser or an active owner of the
|
||||
VM. The global view_instances permission is read-only and does not grant
|
||||
an interactive console (ROADMAP S-09).
|
||||
an interactive console.
|
||||
"""
|
||||
if not user.is_active:
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -1909,7 +1909,7 @@ def change_options(request, pk):
|
|||
userinstance = UserInstance(is_change=False)
|
||||
|
||||
if request.user.is_superuser or userinstance.is_change:
|
||||
# Only superusers and staff may (un)mark templates (ROADMAP S-22). The
|
||||
# Only superusers and staff may (un)mark templates. The
|
||||
# checkbox is disabled for everyone else, and a disabled checkbox is
|
||||
# not submitted, so for them the flag must be left alone.
|
||||
if request.user.is_superuser or request.user.is_staff:
|
||||
|
|
@ -2111,7 +2111,7 @@ def create_instance(request, compute_id, arch, machine):
|
|||
data = form.cleaned_data
|
||||
meta_prealloc = bool(data["meta_prealloc"])
|
||||
|
||||
# Everything is checked before any storage is allocated (R-08).
|
||||
# Everything is checked before any storage is allocated.
|
||||
if data["name"] in instances:
|
||||
raise util.OperationError(_("A virtual machine with this name already exists"))
|
||||
if Instance.objects.filter(name__exact=data["name"]):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue