Enhance documentation and validation for VM lifecycle and network management; add tests for legacy cleanup and address validation.

This commit is contained in:
2026-09-09 19:21:00 +05:30
parent ee26962902
commit 3d7af4adb8
9 changed files with 366 additions and 35 deletions
+74
View File
@@ -442,6 +442,80 @@ class FirewallManagerTests(unittest.TestCase):
with self.assertRaises(CommandError):
self.manager.cleanup_connections(self.vm)
def test_legacy_cleanup_outside_current_network_uses_only_recorded_ip(self):
record = dict(id="vm-legacy", cpu=1, ram_mib=128, guest_ip="203.0.113.7",
gateway="203.0.113.1", tap="tap-legacy", mac=self.vm.mac,
socket="", config="", log="", status="stopped")
for stored_network in (None, "203.0.113.0/24"):
with self.subTest(network=stored_network):
vm = VmRecord.from_dict({**record, **({"network": stored_network} if stored_network else {})})
self.assertIsNone(vm.ports)
self.runner.calls.clear()
self.manager.cleanup_connections(vm)
expected = [("ip", "-j", "-d", "link", "show")]
expected.extend(("conntrack", command, "--family", "ipv4", field, "203.0.113.7")
for field in ("--orig-src", "--orig-dst", "--reply-src", "--reply-dst")
for command in ("--delete", "--list"))
# No nft policy, publishing, or unrelated address/conntrack flush.
self.assertEqual([args for args, _ in self.runner.calls], expected)
def test_cleanup_host_boundaries_use_stored_network_not_current_settings(self):
cases = (
("10.77.8.2", "10.77.0.0/16"),
("100.64.3.4", "100.64.0.0/16"),
("10.42.0.1", None), # Current gateway is not a cleanup constraint.
("10.42.0.0", None), # Do not guess the old prefix from current settings.
("10.42.0.255", None),
("203.0.113.0", "203.0.0.0/16"),
("203.0.113.255", "203.0.0.0/16"),
("203.0.113.8", "203.0.113.8/31"),
("203.0.113.9", "203.0.113.8/31"),
("203.0.113.8", "203.0.113.8/32"),
)
for address, network in cases:
with self.subTest(address=address, network=network):
self.runner.calls.clear()
self.manager.cleanup_connections(vm_record(guest_ip=address, network=network, ports=None))
deletes = [args for args, _ in self.runner.calls if args[:2] == ("conntrack", "--delete")]
self.assertEqual(len(deletes), 4)
self.assertTrue(all(args[-1] == address for args in deletes))
def test_cleanup_rejects_invalid_or_non_host_persisted_addresses(self):
cases = [(address, None) for address in (
"not-an-ip", "203.0.113.999", "203.0.113.7/24", "2001:db8::7",
"::ffff:203.0.113.7", None, True, 3405803783,
"0.0.0.0", "127.0.0.1", "127.12.2.3", "169.254.1.2",
"224.0.0.1", "239.255.255.255", "255.255.255.255",
)]
cases.extend((
("203.0.113.0", "203.0.113.0/24"),
("203.0.113.255", "203.0.113.0/24"),
("203.0.113.7", "203.0.114.0/24"),
("203.0.113.7", "not-a-network"),
("203.0.113.7", ""),
("203.0.113.7", "2001:db8::/64"),
))
for address, network in cases:
with self.subTest(address=address, network=network):
self.runner.calls.clear()
with self.assertRaises(ValidationError):
self.manager.cleanup_connections(vm_record(guest_ip=address, network=network, ports=None))
self.assertEqual([args for args, _ in self.runner.calls], [("ip", "-j", "-d", "link", "show")])
def test_legacy_public_cleanup_still_requires_tap_absence(self):
self.runner.links = [{"ifname": "tap-legacy"}]
vm = vm_record(tap="tap-legacy", guest_ip="203.0.113.7", ports=None)
with self.assertRaisesRegex(UvmError, "still exists"):
self.manager.cleanup_connections(vm)
self.assertFalse(any(args[0] == "conntrack" for args, _ in self.runner.calls))
def test_cleanup_compatibility_does_not_allow_a_public_managed_policy(self):
vm = vm_record(guest_ip="203.0.113.7", network="203.0.113.0/24", ports=())
with self.assertRaisesRegex(ValidationError, "private guest IP"):
self.manager.apply(vm)
self.assertEqual(self.runner.calls, [])
self.manager.cleanup_connections(vm)
def test_availability_checks_kernel_and_full_policy_without_committing(self):
self.manager.check_available()
self.assertEqual(self.runner.tables, {})