nixpkgs/nixos/lib/test-driver/test_driver/vlan.py
Jörg Thalheim ef9502a009 nixos/test-driver: fix resource cleanup of vlan/qmp objects
Using __del__ is somewhat unsound resource cleanup in our clase the
logger already closed its logfile and therefor fails with exception
before the rest of the resources can be cleaned up.
2024-10-16 19:46:38 +03:00

66 lines
2.0 KiB
Python

import io
import os
import pty
import subprocess
from pathlib import Path
from test_driver.logger import AbstractLogger
class VLan:
"""This class handles a VLAN that the run-vm scripts identify via its
number handles. The network's lifetime equals the object's lifetime.
"""
nr: int
socket_dir: Path
process: subprocess.Popen
pid: int
fd: io.TextIOBase
logger: AbstractLogger
def __repr__(self) -> str:
return f"<Vlan Nr. {self.nr}>"
def __init__(self, nr: int, tmp_dir: Path, logger: AbstractLogger):
self.nr = nr
self.socket_dir = tmp_dir / f"vde{self.nr}.ctl"
self.logger = logger
# TODO: don't side-effect environment here
os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir)
self.logger.info("start vlan")
pty_master, pty_slave = pty.openpty()
# The --hub is required for the scenario determined by
# nixos/tests/networking.nix vlan-ping.
# VLAN Tagged traffic (802.1Q) seams to be blocked if a vde_switch is
# used without the hub mode (flood packets to all ports).
self.process = subprocess.Popen(
["vde_switch", "-s", self.socket_dir, "--dirmode", "0700", "--hub"],
stdin=pty_slave,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=False,
)
self.pid = self.process.pid
self.fd = os.fdopen(pty_master, "w")
self.fd.write("version\n")
# TODO: perl version checks if this can be read from
# an if not, dies. we could hang here forever. Fix it.
assert self.process.stdout is not None
self.process.stdout.readline()
if not (self.socket_dir / "ctl").exists():
self.logger.error("cannot start vde_switch")
self.logger.info(f"running vlan (pid {self.pid}; ctl {self.socket_dir})")
def stop(self) -> None:
self.logger.info(f"kill vlan (pid {self.pid})")
self.fd.close()
self.process.terminate()