mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 04:06:47 +00:00
feat(virtsecrets): the secrets page on Bootstrap's cards, tables and dialogs
- One searchable card: each secret's type, usage and UUID, whether it is kept on disk or in memory and private, and the VMs and pools that use it, linked. A row menu sets its value or deletes it; Delete is disabled while the secret is in use, and its confirmation says what is not checked. - One Set value dialog for every secret; its label and help follow the type (Ceph key, CHAP password, passphrase), and it says a new passphrase does not encrypt anew what the old one encrypted. - New secret dialog: the usage's and value's labels and help follow the type; the value is optional; Private and Ephemeral are switches with help.
This commit is contained in:
parent
a95ec40f69
commit
2a773f6ec0
5 changed files with 249 additions and 138 deletions
|
|
@ -1,5 +1,6 @@
|
|||
"""The secrets page never holds a secret's value: the edit dialog only
|
||||
writes a new one."""
|
||||
"""The secrets page never holds a secret's value: the Set value dialog only
|
||||
writes a new one. Each secret shows the VMs and pools that use it, and one in
|
||||
use is not offered for deletion."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
|
|
@ -7,29 +8,51 @@ from computes.models import Compute
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from instances.models import Instance
|
||||
from lxml import html
|
||||
|
||||
UUID = "0e5b1f0a-8f3e-4c1a-9d2b-5c6d7e8f9a0b"
|
||||
|
||||
|
||||
class SecretsPageTests(TestCase):
|
||||
def page(self, usage_type):
|
||||
def page(self, usage_type="ceph", users=None):
|
||||
compute = Compute.objects.create(name="secrets-page", hostname="localhost", login="", password="", type=4)
|
||||
Instance.objects.create(compute=compute, name="db-1", uuid="00000000-0000-4000-8000-0000000000d1")
|
||||
self.client.force_login(get_user_model().objects.create_superuser("page", "page@example.com", "pw"))
|
||||
with patch("virtsecrets.views.wvmSecrets") as conn:
|
||||
conn.return_value.get_secrets_info.return_value = [
|
||||
{"uuid": "0e5b1f0a-8f3e-4c1a-9d2b-5c6d7e8f9a0b", "usage_type": usage_type, "usage": "client.libvirt",
|
||||
"ephemeral": False, "private": False}]
|
||||
conn.return_value.get_users.return_value = {}
|
||||
conn.return_value.wvm.secretLookupByUUIDString.return_value.value.return_value = b"cephx key"
|
||||
{"uuid": UUID, "usage_type": usage_type, "usage": "client.libvirt", "ephemeral": False, "private": True}]
|
||||
conn.return_value.get_users.return_value = users or {}
|
||||
response = self.client.get(reverse("virtsecrets", args=[compute.id]))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
return response
|
||||
return html.fromstring(response.content)
|
||||
|
||||
def test_a_vtpm_secret_is_listed(self):
|
||||
self.assertContains(self.page("vtpm"), "vtpm")
|
||||
self.assertEqual(self.page("vtpm").xpath("//tbody/tr/td[1]/span/text()"), ["vTPM"])
|
||||
|
||||
def test_the_page_holds_no_secret_value(self):
|
||||
response = self.page("ceph")
|
||||
self.assertFalse(b"cephx key" in response.content, "the secret's value is on the page")
|
||||
field = html.fromstring(response.content).get_element_by_id("secret_value_0e5b1f0a-8f3e-4c1a-9d2b-5c6d7e8f9a0b")
|
||||
field = self.page().get_element_by_id("set_value")
|
||||
self.assertIsNone(field.get("value"))
|
||||
self.assertEqual(field.get("type"), "password")
|
||||
|
||||
def test_a_secret_in_use_shows_its_users_and_is_not_deleted(self):
|
||||
page = self.page(users={UUID: {"vms": ["db-1", "gone-1"], "pools": ["ceph-rbd"]}})
|
||||
instance = Instance.objects.get(name="db-1")
|
||||
self.assertEqual(page.xpath("//tbody/tr/td[4]//a/@href")[0], reverse("instances:instance", args=[instance.id]))
|
||||
self.assertIn("gone-1", page.xpath("string(//tbody/tr/td[4])"))
|
||||
self.assertTrue(page.xpath("//tbody/tr/td[4]//a[contains(., 'ceph-rbd')]"))
|
||||
self.assertIsNotNone(page.xpath("//button[@name='delete']")[0].get("disabled"))
|
||||
|
||||
def test_an_unused_secret_can_be_deleted(self):
|
||||
self.assertIsNone(self.page().xpath("//button[@name='delete']")[0].get("disabled"))
|
||||
|
||||
def test_a_secret_without_usage_is_named_by_its_uuid(self):
|
||||
compute = Compute.objects.create(name="secrets-none", hostname="localhost", login="", password="", type=4)
|
||||
self.client.force_login(get_user_model().objects.create_superuser("none", "none@example.com", "pw"))
|
||||
with patch("virtsecrets.views.wvmSecrets") as conn:
|
||||
conn.return_value.get_secrets_info.return_value = [
|
||||
{"uuid": UUID, "usage_type": "none", "usage": "", "ephemeral": True, "private": False}]
|
||||
conn.return_value.get_users.return_value = {}
|
||||
page = html.fromstring(self.client.get(reverse("virtsecrets", args=[compute.id])).content)
|
||||
self.assertEqual(page.xpath("//button[@data-bs-target='#SetSecretValue']/@data-usage"), [UUID])
|
||||
self.assertEqual(page.xpath("//tbody/tr/td[1]/span/text()"), ["none"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue