mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 19:56:48 +00:00
fix(instances): change the edited NIC instead of adding a new one
The edit form posts net-*-<n> fields for NIC n and carries only the new MAC. The backend read index 0 and looked the NIC up by the new MAC, so editing a MAC detached nothing and attached a second NIC, and edits of any NIC but the first were applied with empty values. The form now also posts the current MAC (net-old-mac-<n>). The view reads the submitted NIC's fields, validates the new MAC and reports errors. The backend replaces the NIC with the old MAC, refuses an unknown one, and on a failed attach restores the old NIC and raises instead of reporting success. The view crashed with a TypeError without a Referer header; it now returns to the instance page, and a Referer from another site is ignored.
This commit is contained in:
parent
9e92d208db
commit
fbc6c4976f
6 changed files with 216 additions and 40 deletions
|
|
@ -1707,27 +1707,20 @@ class wvmInstance(wvmConnect):
|
|||
return new_xml
|
||||
return None
|
||||
|
||||
def change_network(self, network_data):
|
||||
net_mac = network_data.get("net-mac-0")
|
||||
net_source = network_data.get("net-source-0")
|
||||
net_source_type = network_data.get("net-source-0-type")
|
||||
net_filter = network_data.get("net-nwfilter-0")
|
||||
net_model = network_data.get("net-model-0")
|
||||
|
||||
# Remove interface first, but keep network interface XML definition
|
||||
# If there is an error happened while adding changed one, then add removed one to back.
|
||||
status = self.delete_network(net_mac)
|
||||
def change_network(self, old_mac, mac, source, source_type, model, nwfilter):
|
||||
"""Replace the NIC with old_mac; put it back if the new one cannot be added."""
|
||||
old_xml = self.delete_network(old_mac)
|
||||
if old_xml is None:
|
||||
raise libvirtError(f"No network interface with MAC {old_mac}")
|
||||
try:
|
||||
self.add_network(
|
||||
net_mac, net_source, net_source_type, net_model, net_filter
|
||||
)
|
||||
self.add_network(mac, source, source_type, model, nwfilter)
|
||||
except libvirtError:
|
||||
if status is not None:
|
||||
if self.get_status() == 1:
|
||||
self.instance.attachDeviceFlags(status, VIR_DOMAIN_AFFECT_LIVE)
|
||||
self.instance.attachDeviceFlags(status, VIR_DOMAIN_AFFECT_CONFIG)
|
||||
if self.get_status() == 5:
|
||||
self.instance.attachDeviceFlags(status, VIR_DOMAIN_AFFECT_CONFIG)
|
||||
if self.get_status() == 1:
|
||||
self.instance.attachDeviceFlags(old_xml, VIR_DOMAIN_AFFECT_LIVE)
|
||||
self.instance.attachDeviceFlags(old_xml, VIR_DOMAIN_AFFECT_CONFIG)
|
||||
if self.get_status() == 5:
|
||||
self.instance.attachDeviceFlags(old_xml, VIR_DOMAIN_AFFECT_CONFIG)
|
||||
raise
|
||||
|
||||
def change_network_oldway(self, network_data):
|
||||
"""
|
||||
|
|
|
|||
56
vrtManager/test_change_network.py
Normal file
56
vrtManager/test_change_network.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import unittest
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
if not settings.configured:
|
||||
settings.configure(MAC_OUI="52:54:10")
|
||||
|
||||
from libvirt import VIR_DOMAIN_AFFECT_CONFIG, libvirtError
|
||||
from vrtManager.instance import wvmInstance
|
||||
|
||||
DOMAIN_XML = """<domain><devices>
|
||||
<interface type='network'><mac address='52:54:00:00:00:01'/><source network='default'/><model type='virtio'/></interface>
|
||||
<interface type='network'><mac address='52:54:00:00:00:02'/><source network='default'/><model type='virtio'/></interface>
|
||||
</devices></domain>"""
|
||||
|
||||
|
||||
def stopped_instance():
|
||||
inst = wvmInstance.__new__(wvmInstance)
|
||||
inst.instance = MagicMock()
|
||||
inst._XMLDesc = MagicMock(return_value=DOMAIN_XML)
|
||||
inst.get_status = MagicMock(return_value=5)
|
||||
return inst
|
||||
|
||||
|
||||
class TestChangeNetwork(unittest.TestCase):
|
||||
def test_replaces_the_nic_with_the_old_mac(self):
|
||||
inst = stopped_instance()
|
||||
inst.change_network("52:54:00:00:00:02", "52:54:00:00:00:03", "default", "net", "e1000", "")
|
||||
|
||||
detached = inst.instance.detachDeviceFlags.call_args[0][0]
|
||||
self.assertIn("52:54:00:00:00:02", detached)
|
||||
attached = inst.instance.attachDeviceFlags.call_args[0][0]
|
||||
self.assertIn("52:54:00:00:00:03", attached)
|
||||
self.assertIn("e1000", attached)
|
||||
|
||||
def test_unknown_old_mac_adds_nothing(self):
|
||||
inst = stopped_instance()
|
||||
with self.assertRaises(libvirtError):
|
||||
inst.change_network("52:54:00:00:00:09", "52:54:00:00:00:03", "default", "net", "virtio", "")
|
||||
inst.instance.detachDeviceFlags.assert_not_called()
|
||||
inst.instance.attachDeviceFlags.assert_not_called()
|
||||
|
||||
def test_failed_add_restores_the_old_nic(self):
|
||||
inst = stopped_instance()
|
||||
inst.instance.attachDeviceFlags.side_effect = [libvirtError("bad source"), 0]
|
||||
with self.assertRaises(libvirtError):
|
||||
inst.change_network("52:54:00:00:00:01", "52:54:00:00:00:03", "missing", "net", "virtio", "")
|
||||
|
||||
restored, flags = inst.instance.attachDeviceFlags.call_args[0]
|
||||
self.assertIn("52:54:00:00:00:01", restored)
|
||||
self.assertEqual(flags, VIR_DOMAIN_AFFECT_CONFIG)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue