This commit is contained in:
its.kstyagi@gmail.com
2026-09-04 20:56:18 +00:00
commit 1022f24c34
43 changed files with 6160 additions and 0 deletions
+153
View File
@@ -0,0 +1,153 @@
from __future__ import annotations
import unittest
from ipaddress import IPv4Address, IPv4Network
from uvm.config import Settings
from uvm.domain import VmRecord
from uvm.errors import UvmError, ValidationError
from uvm.network import NetworkManager
from uvm.system import CommandResult
class FakeRunner:
def __init__(self) -> None:
self.calls: list[tuple[str, ...]] = []
self.existing_links: set[str] = set()
self.link_details: dict[str, str] = {}
def run(self, command, *, check=True, capture=False, timeout=None) -> CommandResult:
del check, capture, timeout
args = tuple(str(part) for part in command)
self.calls.append(args)
if args[:3] == ("ip", "link", "show") and args[3] in self.existing_links:
return CommandResult(args=args, returncode=0)
if args[:6] == ("ip", "-j", "-d", "link", "show", "dev"):
return CommandResult(args=args, returncode=0, stdout=self.link_details[args[6]])
if args[:4] == ("ip", "link", "show", "uvm0"):
return CommandResult(args=args, returncode=1)
if args == ("ip", "route", "show", "default"):
return CommandResult(args=args, returncode=0, stdout="default via 192.0.2.1 dev eth0\n")
if len(args) > 3 and args[0] == "iptables" and "-C" in args:
return CommandResult(args=args, returncode=1)
return CommandResult(args=args, returncode=0)
class NetworkManagerTests(unittest.TestCase):
def setUp(self) -> None:
self.runner = FakeRunner()
self.network = NetworkManager(Settings(), runner=self.runner) # type: ignore[arg-type]
def test_allocates_first_available_guest_address(self) -> None:
self.assertEqual(self.network.allocate_ip([], None), IPv4Address("10.42.0.2"))
def test_rejects_gateway_and_used_requested_addresses(self) -> None:
vm = VmRecord(
id="vm-test",
cpu=1,
ram_mib=512,
guest_ip="10.42.0.2",
gateway="10.42.0.1",
tap="uvm-test",
mac="02:fc:00:00:00:01",
socket="/tmp/firecracker.sock",
config="/tmp/config.json",
log="/tmp/firecracker.log",
)
with self.assertRaises(ValidationError):
self.network.allocate_ip([vm], IPv4Address("10.42.0.1"))
with self.assertRaises(ValidationError):
self.network.allocate_ip([vm], IPv4Address("10.42.0.2"))
with self.assertRaises(ValidationError):
self.network.allocate_ip([], IPv4Address("10.42.0.0"))
with self.assertRaises(ValidationError):
self.network.allocate_ip([], IPv4Address("10.42.0.255"))
def test_mac_and_tap_names_are_bounded_and_deterministic(self) -> None:
self.assertEqual(NetworkManager.mac_for(1), "02:fc:00:00:00:01")
tap = NetworkManager.tap_name("vm-0123456789abcdef")
self.assertLessEqual(len(tap), 15)
self.assertTrue(tap.startswith("uvm-"))
def test_bridge_setup_adds_a_missing_bridge_and_one_nat_rule(self) -> None:
self.network.ensure_bridge()
self.assertIn(("ip", "link", "add", "uvm0", "type", "bridge"), self.runner.calls)
self.assertIn(
("ip", "addr", "replace", "10.42.0.1/24", "dev", "uvm0"),
self.runner.calls,
)
self.assertIn(
(
"iptables",
"-A",
"FORWARD",
"-i",
"uvm0",
"-o",
"eth0",
"-s",
"10.42.0.0/24",
"-j",
"ACCEPT",
),
self.runner.calls,
)
checks = [
call
for call in self.runner.calls
if call[:5] == ("iptables", "-t", "nat", "-C", "POSTROUTING")
]
self.assertEqual(len(checks), 1)
self.assertIn(
(
"iptables",
"-t",
"nat",
"-A",
"POSTROUTING",
"-s",
"10.42.0.0/24",
"-o",
"eth0",
"-j",
"MASQUERADE",
),
self.runner.calls,
)
def test_bridge_and_guest_network_support_non_default_prefixes(self) -> None:
settings = Settings(
network=IPv4Network("10.50.0.0/16"),
gateway=IPv4Address("10.50.0.1"),
)
runner = FakeRunner()
NetworkManager(settings, runner=runner).ensure_bridge() # type: ignore[arg-type]
self.assertIn(
("ip", "addr", "replace", "10.50.0.1/16", "dev", "uvm0"),
runner.calls,
)
def test_refuses_to_adopt_an_existing_tap_device(self) -> None:
self.runner.existing_links.add("uvm-existing")
with self.assertRaises(UvmError):
self.network.create_tap("uvm-existing")
self.assertNotIn(
("ip", "tuntap", "add", "dev", "uvm-existing", "mode", "tap"),
self.runner.calls,
)
def test_refuses_to_reconfigure_an_existing_non_bridge_interface(self) -> None:
self.runner.existing_links.add("uvm0")
self.runner.link_details["uvm0"] = '[{"linkinfo": {"info_kind": "dummy"}}]'
with self.assertRaises(UvmError):
self.network.ensure_bridge()
self.assertNotIn(
("ip", "addr", "replace", "10.42.0.1/24", "dev", "uvm0"),
self.runner.calls,
)