1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
webvirtcloud/instances/test_console_rule.py
catborise f1e83455e4 refactor(instances): one way to reach a VM, its console and its devices
The .vv console file is built from the VM found by its UUID, with the
console page's getters, instead of looking the VM up by name five times;
a console without a listen address or password now gives 127.0.0.1 and
an empty password instead of "None". Removed methods nothing calls: the
by-name getters and power methods of wvmInstances, managed save, the vCPU
mode getter (it read the wrong attribute), the old NIC editor and its
bridge lookup. CD-ROM media and NIC hotplug use _definitions() like the
other device edits, the disk editor takes the bus prefix from
util.vol_dev_type, and an unreadable disk is logged, not printed.
2026-10-09 18:13:32 +03:00

78 lines
3.6 KiB
Python

"""
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
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
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
from instances.utils import can_open_console
class CanOpenConsoleTestCase(TestCase):
def setUp(self):
User = get_user_model()
self.superuser = User.objects.create_superuser(
username="cons_super", email="cons_super@example.com", password="x"
)
self.owner = User.objects.create_user(username="cons_owner", password="x")
self.inactive_owner = User.objects.create_user(
username="cons_inactive", password="x", is_active=False
)
self.viewer = User.objects.create_user(username="cons_viewer", password="x")
self.viewer.user_permissions.add(Permission.objects.get(codename="view_instances"))
self.stranger = User.objects.create_user(username="cons_stranger", password="x")
self.compute = Compute.objects.create(
name="cons-compute", hostname="127.0.0.1:1", login="root", password="", type=1
)
self.instance = Instance.objects.create(
compute=self.compute,
name="cons-vm",
uuid="77777777-8888-9999-aaaa-bbbbbbbbbbbb",
)
UserInstance.objects.create(instance=self.instance, user=self.owner)
UserInstance.objects.create(instance=self.instance, user=self.inactive_owner)
def test_superuser_and_owner_may_open_console(self):
self.assertTrue(can_open_console(self.superuser, self.instance))
self.assertTrue(can_open_console(self.owner, self.instance))
def test_view_instances_stranger_and_inactive_owner_may_not(self):
self.assertFalse(can_open_console(self.viewer, self.instance))
self.assertFalse(can_open_console(self.stranger, self.instance))
self.assertFalse(can_open_console(self.inactive_owner, self.instance))
def test_owner_can_download_vv_file(self):
self.client.force_login(self.owner)
with patch("instances.models.wvmInstance") as wvm:
proxy = wvm.return_value.cached_reads.return_value.__enter__.return_value
proxy.instance.name.return_value = "cons-vm"
proxy.host = "192.0.2.7"
proxy.get_console_type.return_value = "vnc"
proxy.get_console_listener_addr.return_value = "0.0.0.0"
proxy.get_console_port.return_value = "5900"
proxy.get_console_passwd.return_value = "secret"
res = self.client.get(reverse("instances:getvvfile", args=[self.instance.id]))
self.assertEqual(res.status_code, 200)
self.assertIn(b"[virt-viewer]", res.content)
# the VM found by its UUID; a console on all addresses is reached through the host
for line in (b"type=vnc", b"host=192.0.2.7", b"port=5900", b"title=cons-vm", b"password=secret"):
self.assertIn(line + b"\n", res.content)
def test_owner_can_get_vdi_url(self):
self.client.force_login(self.owner)
with patch("datasource.views.wvmInstance", MagicMock()), patch(
"datasource.views.get_hostname_by_ip", return_value="host"
):
res = self.client.get(
reverse("vdi_url", args=[self.compute.id, self.instance.name])
)
self.assertEqual(res.status_code, 200)