mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
- Totals above the list: hosts connected of all, VMs running of all, vCPUs given on the CPUs, memory given of the memory of the hosts the panel reads, as cards; the connected count is red while a host is not. - A host's name links its overview; its state is a Connected or Not connected badge (the dot goes), beside a badge of how the panel reaches it (TCP, SSH, TLS, Socket); its address in monospace. - A VMs column: the host's VMs, linked to its Instances, and how many run. - The vCPUs have a bar like the memory's: running VMs' and shut-off VMs' vCPUs against the CPUs, amber over 2:1 and red over 4:1 as the ratio is; the overview's vCPU card shares it. - The three coloured buttons of each row are one menu: Overview, Edit connection and Remove from panel (its popper fixed, as the table's scrolling box would cut it off). - The four green add buttons are one "Add host" menu that says what each kind of connection is. - The table is table-hover; a host the panel cannot reach has a table-warning row.
110 lines
5.9 KiB
Python
110 lines
5.9 KiB
Python
"""What each compute has given its VMs (Compute.capacity) and the Computes
|
|
page that shows it."""
|
|
|
|
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
|
|
from lxml import html
|
|
|
|
GIB = 1024 ** 3
|
|
VMS = {"running": 3, "paused": 1, "shutoff": 2, "other": 0}
|
|
|
|
|
|
class CapacityTests(TestCase):
|
|
def setUp(self):
|
|
self.compute = Compute(name="host-one", hostname="192.0.2.1", login="u", password="p", type=1)
|
|
self.compute.status = True
|
|
|
|
@patch("computes.models.wvmHostDetails")
|
|
def test_a_host_tells_what_it_gave(self, details):
|
|
details.return_value.get_capacity.return_value = {"cpus": 16, "vcpus": {"all": 24, "running": 8}}
|
|
self.assertEqual(self.compute.capacity, {"cpus": 16, "vcpus": {"all": 24, "running": 8}, "ratio": 1.5})
|
|
|
|
@patch("computes.models.wvmHostDetails")
|
|
def test_a_host_whose_read_fails_has_no_capacity(self, details):
|
|
# a VM that goes while the host is read, for one
|
|
details.return_value.get_capacity.side_effect = libvirtError("Domain not found")
|
|
self.assertIsNone(self.compute.capacity)
|
|
|
|
@patch("computes.models.wvmHostDetails")
|
|
def test_a_down_host_is_not_read(self, details):
|
|
self.compute.status = False
|
|
self.assertIsNone(self.compute.capacity)
|
|
details.assert_not_called()
|
|
|
|
|
|
class ComputesPageTests(TestCase):
|
|
def test_the_list_shows_what_each_compute_has_given(self):
|
|
admin = get_user_model().objects.create_superuser("cap-admin", "cap@example.com", "pw")
|
|
self.client.force_login(admin)
|
|
c1 = Compute.objects.create(name="host-one", hostname="192.0.2.1", login="u", password="p", type=1)
|
|
Compute.objects.create(name="host-two", hostname="192.0.2.2", login="u", password="p", type=1)
|
|
found = {c1.id: {"cpus": 16, "memory": 64 * GIB, "vcpus": {"all": 40, "running": 24},
|
|
"assigned": {"all": 48 * GIB, "running": 32 * GIB}, "ratio": 2.5, "vms": VMS}}
|
|
with patch.object(Compute, "capacity", new=property(lambda c: found.get(c.id))), \
|
|
patch.object(Compute, "status", new=True):
|
|
page = html.fromstring(self.client.get(reverse("computes")).content)
|
|
headers = [" ".join(th.text_content().split()) for th in page.xpath("//thead//th")]
|
|
# no pools: measuring their space scans each pool of each host (views.host_pools)
|
|
self.assertEqual(headers, ["Host", "VMs", "vCPUs", "Memory", "Actions"])
|
|
one, two = page.xpath("//tbody/tr")
|
|
cells = [" ".join(td.text_content().split()) for td in one.xpath("td")]
|
|
self.assertIn("host-one Connected TCP 192.0.2.1", cells[0])
|
|
self.assertEqual(cells[1], "6 3 running")
|
|
self.assertIn("2.5:1", cells[2])
|
|
self.assertIn("40 vCPUs on 16 CPUs", cells[2])
|
|
self.assertIn("24 running", cells[2])
|
|
self.assertIn("75 % 48.0 GB / 64.0 GB", cells[3])
|
|
self.assertIn("32.0 GB running", cells[3])
|
|
# the totals of the hosts read: host-two's capacity could not be
|
|
totals = [" ".join(card.text_content().split()) for card in page.xpath("//div[@class='card-body']")]
|
|
self.assertEqual(totals, ["Hosts 2 / 2 connected", "VMs 3 / 6 running", "vCPUs given 40 on 16 CPUs",
|
|
"Memory given 48.0 GB of 64.0 GB"])
|
|
# host-two could not be read: one cell says so
|
|
self.assertIn("capacity could not be read", " ".join(two.text_content().split()))
|
|
|
|
|
|
class SingularTests(TestCase):
|
|
def test_one_vcpu_on_one_cpu_is_singular(self):
|
|
admin = get_user_model().objects.create_superuser("cap-one", "one@example.com", "pw")
|
|
self.client.force_login(admin)
|
|
c = Compute.objects.create(name="host-one", hostname="192.0.2.1", login="u", password="p", type=1)
|
|
given = {"cpus": 1, "memory": 4 * GIB, "vcpus": {"all": 1, "running": 1},
|
|
"assigned": {"all": GIB, "running": GIB}, "ratio": 1.0, "vms": VMS}
|
|
with patch.object(Compute, "capacity", new=given), patch.object(Compute, "status", new=True):
|
|
page = html.fromstring(self.client.get(reverse("computes")).content)
|
|
line = self.client.get(reverse("compute_capacity", args=[c.id])).content.decode()
|
|
(cell,) = page.xpath("//tbody/tr/td[3]")
|
|
self.assertIn("1 vCPU on 1 CPU", " ".join(cell.text_content().split()))
|
|
self.assertEqual(" ".join(line.split()), "Given to VMs: 1 vCPU (1.0:1), 1.0 GB memory.")
|
|
|
|
|
|
class NewVmDialogLineTests(TestCase):
|
|
"""The new-VM dialog loads one line per host when it opens."""
|
|
|
|
def setUp(self):
|
|
admin = get_user_model().objects.create_superuser("cap-line", "line@example.com", "pw")
|
|
self.client.force_login(admin)
|
|
self.compute = Compute.objects.create(name="host-one", hostname="192.0.2.1", login="u", password="p", type=1)
|
|
|
|
def line(self, given):
|
|
with patch.object(Compute, "capacity", new=given):
|
|
response = self.client.get(reverse("compute_capacity", args=[self.compute.id]))
|
|
self.assertEqual(response["Content-Type"], "text/plain; charset=utf-8")
|
|
return " ".join(response.content.decode().split())
|
|
|
|
def test_the_line_tells_what_the_host_has_given(self):
|
|
given = {"cpus": 16, "memory": 64 * GIB, "vcpus": {"all": 24, "running": 8},
|
|
"assigned": {"all": 48 * GIB, "running": 32 * GIB}, "ratio": 1.5,
|
|
}
|
|
self.assertEqual(self.line(given), "Given to VMs: 24 vCPUs (1.5:1), 48.0 GB memory.")
|
|
|
|
def test_a_host_without_pools_or_capacity_says_so(self):
|
|
given = {"cpus": 2, "memory": 4 * GIB, "vcpus": {"all": 0, "running": 0},
|
|
"assigned": {"all": 0, "running": 0}, "ratio": 0}
|
|
self.assertEqual(self.line(given), "Given to VMs: 0 vCPUs (0.0:1), 0 bytes memory.")
|
|
self.assertEqual(self.line(None), "The capacity could not be read.")
|