mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
fix(interfaces): deleting a bridge keeps the devices it held
With the netcf backend (RHEL/AlmaLinux 8), undefining a bridge also removes its members' configuration: the device came back without any after a reboot. Like virsh iface-unbridge, each member is now defined again on its own after the bridge is undefined, with the bridge's start mode and, when it is the only member, its addresses. A bond keeps its mode and devices. Checked on AlmaLinux 8 (libvirt 8.0, netcf): an ethernet and a bond member get their ifcfg back, and the bond comes up with the address after a reboot.
This commit is contained in:
parent
7526e9ab32
commit
28a73519d7
3 changed files with 53 additions and 0 deletions
|
|
@ -576,6 +576,7 @@ A version from before v3.0.0 has no worker: `systemctl disable --now webvirt-wor
|
|||
- A VM's stats are polled every 5 s like the host graph, the first point as soon as the tab opens; each point is the average since the previous one, disk rates in MB/s (they were MiB/s labelled Mb/s); a counter the host does not report shows a gap instead of 0.
|
||||
- An ISO uploads to an SSH compute about 3.5 times faster (SFTP writes no longer wait for each 32 KiB); a failed write still fails the upload.
|
||||
- On a host whose libvirt cannot change network interfaces (the udev backend: RHEL 9 and later, Debian 12), the interface pages offer no create, start, stop or delete; they only failed there.
|
||||
- Deleting a bridge on a host with the netcf backend (RHEL/AlmaLinux 8) keeps the devices it held: each is defined again on its own with the bridge's start mode and, for a single device, its addresses, as `virsh iface-unbridge` does. They lost their configuration and stayed down after a reboot.
|
||||
- On a running VM the disk list, its edit form, the QoS table, the title, description, CPU, boot order, video and console fields show the settings as they will be at the next start, so saving an edit no longer reverts another pending change. A boot order that names a device missing from that definition is refused instead of clearing the order. The settings tab of a running VM says so. A QoS edit keeps the inbound floor. Buttons shown as disabled while the VM runs can no longer be submitted with Enter.
|
||||
- A new disk or CD-ROM on a running VM gets a device name that neither the running VM nor its next-start settings use; it could take the name of a pending disk and stay attached until the next start only.
|
||||
- The OTP e-mail's QR code is drawn with segno; django-qr-code is no longer required. A `settings.py` kept from an older version still lists `"qr_code"` in `INSTALLED_APPS`: delete that line, or the app does not start in a venv without django-qr-code.
|
||||
|
|
|
|||
44
interfaces/tests/test_delete.py
Normal file
44
interfaces/tests/test_delete.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
"""Deleting a host interface: netcf removes a bridge's members with the
|
||||
bridge, so they are defined again on their own (as virsh iface-unbridge)."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
from lxml import etree
|
||||
from vrtManager.interface import wvmInterface
|
||||
|
||||
ADDRESS = "<protocol family='ipv4'><ip address='192.0.2.10' prefix='24'/></protocol>"
|
||||
BOND = "<interface type='bond' name='bond0'><bond mode='active-backup'><interface type='ethernet' name='eth1'/></bond></interface>"
|
||||
|
||||
|
||||
def delete(xml):
|
||||
conn = wvmInterface.__new__(wvmInterface)
|
||||
conn.iface = MagicMock()
|
||||
conn.iface.XMLDesc.return_value = xml
|
||||
conn.wvm = MagicMock()
|
||||
conn.delete_iface()
|
||||
conn.iface.undefine.assert_called_once_with()
|
||||
return [etree.fromstring(call.args[0]) for call in conn.wvm.interfaceDefineXML.call_args_list]
|
||||
|
||||
|
||||
class DeleteInterfaceTestCase(SimpleTestCase):
|
||||
def test_the_only_member_takes_the_bridge_start_mode_and_addresses(self):
|
||||
(bond,) = delete(f"<interface type='bridge' name='br1'><start mode='onboot'/>{ADDRESS}<bridge>{BOND}</bridge></interface>")
|
||||
self.assertEqual(bond.get("name"), "bond0")
|
||||
self.assertEqual(bond.xpath("bond/@mode"), ["active-backup"])
|
||||
self.assertEqual(bond.xpath("bond/interface/@name"), ["eth1"])
|
||||
self.assertEqual(bond.xpath("start/@mode"), ["onboot"])
|
||||
self.assertEqual(bond.xpath("protocol/ip/@address"), ["192.0.2.10"])
|
||||
|
||||
def test_several_members_take_the_start_mode_but_no_address(self):
|
||||
members = delete(
|
||||
f"<interface type='bridge' name='br1'><start mode='onboot'/>{ADDRESS}<bridge>"
|
||||
"<interface type='ethernet' name='eth1'/><interface type='ethernet' name='eth2'/></bridge></interface>"
|
||||
)
|
||||
self.assertEqual([m.get("name") for m in members], ["eth1", "eth2"])
|
||||
for member in members:
|
||||
self.assertEqual(member.xpath("start/@mode"), ["onboot"])
|
||||
self.assertEqual(member.xpath("protocol"), [])
|
||||
|
||||
def test_an_interface_that_is_not_a_bridge_is_only_undefined(self):
|
||||
self.assertEqual(delete(f"<interface type='ethernet' name='eth1'><start mode='onboot'/>{ADDRESS}</interface>"), [])
|
||||
|
|
@ -198,4 +198,12 @@ class wvmInterface(wvmConnect):
|
|||
self.iface.create()
|
||||
|
||||
def delete_iface(self):
|
||||
"""Undefine the interface. netcf removes a bridge's members with it, so
|
||||
each member is defined again on its own, as virsh iface-unbridge does:
|
||||
with the bridge's start mode and, when it is the only one, addresses."""
|
||||
tree = ElementTree.fromstring(self._XMLDesc(VIR_INTERFACE_XML_INACTIVE))
|
||||
members = tree.findall("bridge/interface")
|
||||
self.iface.undefine()
|
||||
for member in members:
|
||||
member.extend(tree.findall("start") + (tree.findall("protocol") if len(members) == 1 else []))
|
||||
self.wvm.interfaceDefineXML(ElementTree.tostring(member, encoding="unicode"), 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue