1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/interfaces/tests/test_audit_rows.py
catborise 5b8793ad4c feat(logs): changes to networks, storage, interfaces, secrets and filters are logged
The Logs page now records every change an admin makes to a compute's
libvirt objects, with the compute's name in the host column:

- networks: add, start, stop, delete, autostart, DHCP range, fixed
  addresses, QoS and XML edits;
- storage pools: add, start, stop, delete, autostart, from web and
  API; volumes: add and delete (web and API), clone and ISO upload;
- host interfaces: add, start, stop, delete;
- secrets: add, set value (never the value), delete;
- network filters: add, clone, delete, XML edits, rules and
  references.

A refused or failed change is a failed row with its reason (libvirt
text through safe_text). The volume clone and upload jobs write their
row when they end; a refused submission is a failed row at once. A
volume row names the volume libvirt created (a dir pool adds .qcow2 or
.img). Volume create or delete through the API on an inactive pool
(409) is a failed row.

Network filters: the rows read "Network filter f1: add" instead of
"f1 network filter is created", and their host is the compute's name
instead of its hostname. A duplicate name or UUID no longer raises a
bare exception, and a filter XML that cannot be parsed no longer ends
in UnboundLocalError.
2026-10-23 13:30:21 +03:00

38 lines
1.8 KiB
Python

"""Host interface changes write rows on the Logs page."""
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 logs.models import Logs
class InterfaceRowTests(TestCase):
def setUp(self):
self.compute = Compute.objects.create(name="c1", hostname="localhost", login="", password="", type=4)
self.client.force_login(get_user_model().objects.create_superuser("audit-admin", "a@example.com", "pw"))
Logs.objects.all().delete() # the login's row
@patch("interfaces.views.wvmInterface")
@patch("interfaces.views.wvmInterfaces")
def test_interface_actions(self, ifaces, iface):
ifaces.return_value.can_change_interfaces.return_value = True
ifaces.return_value.get_net_devices.return_value = ["eth0"]
ifaces.return_value.get_ifaces.return_value = []
iface.return_value.can_change_interfaces.return_value = True
self.client.post(reverse("interfaces", args=[self.compute.id]), {
"create": "", "name": "br1", "itype": "bridge", "start_mode": "onboot", "netdev": "eth0",
"ipv4_type": "dhcp", "ipv6_type": "none", "stp": "on", "delay": "0"})
ifaces.return_value.create_iface.assert_called_once()
url = reverse("interface", args=[self.compute.id, "br1"])
for action in ("start", "stop", "delete"):
self.client.post(url, {action: ""})
self.assertEqual(list(Logs.objects.order_by("id").values_list("message", "success", "host")), [
("Interface br1: add", True, "c1"),
("Interface br1: start", True, "c1"),
("Interface br1: stop", True, "c1"),
("Interface br1: delete", True, "c1"),
])