Loading nixos/lib/test-driver/src/test_driver/logger.py +26 −3 Original line number Diff line number Diff line Loading @@ -18,9 +18,10 @@ from junit_xml import TestCase, TestSuite class LogLevel(IntEnum): INFO = 1 WARNING = 2 ERROR = 3 DEBUG = 1 INFO = 2 WARNING = 3 ERROR = 4 class AbstractLogger(ABC): Loading @@ -38,6 +39,10 @@ class AbstractLogger(ABC): def nested(self, message: str, attributes: dict[str, str] = {}) -> Iterator[None]: pass @abstractmethod def debug(self, *args, **kwargs) -> None: pass @abstractmethod def info(self, *args, **kwargs) -> None: pass Loading Loading @@ -102,6 +107,10 @@ class JunitXMLLogger(AbstractLogger): self.log(message) yield def debug(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.DEBUG: self.tests[self.currentSubtest].stdout += args[0] + os.linesep def info(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.INFO: self.tests[self.currentSubtest].stdout += args[0] + os.linesep Loading Loading @@ -171,6 +180,10 @@ class CompositeLogger(AbstractLogger): stack.enter_context(logger.nested(message, attributes)) yield def debug(self, *args, **kwargs) -> None: for logger in self.logger_list: logger.debug(*args, **kwargs) def info(self, *args, **kwargs) -> None: for logger in self.logger_list: logger.info(*args, **kwargs) Loading Loading @@ -237,6 +250,12 @@ class TerminalLogger(AbstractLogger): toc = time.time() self.log(f"(finished: {message}, in {toc - tic:.2f} seconds)", attributes) def debug(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.DEBUG: self._eprint( Style.DIM + self.maybe_prefix(args[0], kwargs) + Style.RESET_ALL # ty: ignore[unsupported-operator] ) def info(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.INFO: self.log(*args, **kwargs) Loading Loading @@ -296,6 +315,10 @@ class XMLLogger(AbstractLogger): self.xml.characters(message) self.xml.endElement("line") def debug(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.DEBUG: self.log(*args, **kwargs) def info(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.INFO: self.log(*args, **kwargs) Loading nixos/lib/test-driver/src/test_driver/vlan.py +29 −5 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import io import os import select import subprocess import threading import typing from pathlib import Path Loading Loading @@ -57,6 +58,11 @@ class VLan: def __repr__(self) -> str: return f"<Vlan Nr. {self.nr}>" def _log_stream(self, stream: typing.IO[str], prefix: str) -> None: """Read lines from a stream and log via debug().""" for line in stream: self.logger.debug(f"{prefix}: {line.rstrip()}") def __init__(self, nr: int, tmp_dir: Path, logger: AbstractLogger): self.nr = nr self.socket_dir = tmp_dir / f"vde{self.nr}.ctl" Loading @@ -66,7 +72,7 @@ class VLan: # TODO: don't side-effect environment here os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir) self.logger.info("start vlan") self.logger.debug("start vlan") self.process = subprocess.Popen( [ Loading @@ -84,7 +90,7 @@ class VLan: bufsize=1, # Line buffered. stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, # Do not swallow stderr. stderr=subprocess.STDOUT, text=True, ) self.pid = self.process.pid Loading Loading @@ -117,19 +123,37 @@ class VLan: if "1000 Success" in line: break self._stdout_thread = threading.Thread( target=self._log_stream, args=(self.process.stdout, f"vde_switch[{self.nr}]"), daemon=True, ) self._stdout_thread.start() # This is needed to allow systemd-nspawn containers to communicate # with VMs connected to the VLAN. self.logger.info(f"creating tap interface {self.tap_name}") self.logger.debug(f"creating tap interface {self.tap_name}") self.plug_process = subprocess.Popen( ["vde_plug2tap", "-s", self.socket_dir, self.tap_name], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, ) assert self.plug_process.stdout is not None self._plug_stdout_thread = threading.Thread( target=self._log_stream, args=(self.plug_process.stdout, f"vde_plug2tap[{self.nr}]"), daemon=True, ) self._plug_stdout_thread.start() assert (self.socket_dir / "ctl").exists(), "cannot start vde_switch" self.logger.info(f"running vlan (pid {self.pid}; ctl {self.socket_dir})") self.logger.debug(f"running vlan (pid {self.pid}; ctl {self.socket_dir})") def stop(self) -> None: self.logger.info(f"kill vlan (pid {self.pid})") self.logger.debug(f"kill vlan (pid {self.pid})") assert self.process.stdin is not None self.process.stdin.close() if self.plug_process: Loading nixos/lib/testing/driver.nix +1 −0 Original line number Diff line number Diff line Loading @@ -236,6 +236,7 @@ in logLevel = mkOption { description = "Log level for the test driver."; type = types.enum [ "debug" "info" "warning" "error" Loading Loading
nixos/lib/test-driver/src/test_driver/logger.py +26 −3 Original line number Diff line number Diff line Loading @@ -18,9 +18,10 @@ from junit_xml import TestCase, TestSuite class LogLevel(IntEnum): INFO = 1 WARNING = 2 ERROR = 3 DEBUG = 1 INFO = 2 WARNING = 3 ERROR = 4 class AbstractLogger(ABC): Loading @@ -38,6 +39,10 @@ class AbstractLogger(ABC): def nested(self, message: str, attributes: dict[str, str] = {}) -> Iterator[None]: pass @abstractmethod def debug(self, *args, **kwargs) -> None: pass @abstractmethod def info(self, *args, **kwargs) -> None: pass Loading Loading @@ -102,6 +107,10 @@ class JunitXMLLogger(AbstractLogger): self.log(message) yield def debug(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.DEBUG: self.tests[self.currentSubtest].stdout += args[0] + os.linesep def info(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.INFO: self.tests[self.currentSubtest].stdout += args[0] + os.linesep Loading Loading @@ -171,6 +180,10 @@ class CompositeLogger(AbstractLogger): stack.enter_context(logger.nested(message, attributes)) yield def debug(self, *args, **kwargs) -> None: for logger in self.logger_list: logger.debug(*args, **kwargs) def info(self, *args, **kwargs) -> None: for logger in self.logger_list: logger.info(*args, **kwargs) Loading Loading @@ -237,6 +250,12 @@ class TerminalLogger(AbstractLogger): toc = time.time() self.log(f"(finished: {message}, in {toc - tic:.2f} seconds)", attributes) def debug(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.DEBUG: self._eprint( Style.DIM + self.maybe_prefix(args[0], kwargs) + Style.RESET_ALL # ty: ignore[unsupported-operator] ) def info(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.INFO: self.log(*args, **kwargs) Loading Loading @@ -296,6 +315,10 @@ class XMLLogger(AbstractLogger): self.xml.characters(message) self.xml.endElement("line") def debug(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.DEBUG: self.log(*args, **kwargs) def info(self, *args, **kwargs) -> None: if self._log_level <= LogLevel.INFO: self.log(*args, **kwargs) Loading
nixos/lib/test-driver/src/test_driver/vlan.py +29 −5 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import io import os import select import subprocess import threading import typing from pathlib import Path Loading Loading @@ -57,6 +58,11 @@ class VLan: def __repr__(self) -> str: return f"<Vlan Nr. {self.nr}>" def _log_stream(self, stream: typing.IO[str], prefix: str) -> None: """Read lines from a stream and log via debug().""" for line in stream: self.logger.debug(f"{prefix}: {line.rstrip()}") def __init__(self, nr: int, tmp_dir: Path, logger: AbstractLogger): self.nr = nr self.socket_dir = tmp_dir / f"vde{self.nr}.ctl" Loading @@ -66,7 +72,7 @@ class VLan: # TODO: don't side-effect environment here os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir) self.logger.info("start vlan") self.logger.debug("start vlan") self.process = subprocess.Popen( [ Loading @@ -84,7 +90,7 @@ class VLan: bufsize=1, # Line buffered. stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, # Do not swallow stderr. stderr=subprocess.STDOUT, text=True, ) self.pid = self.process.pid Loading Loading @@ -117,19 +123,37 @@ class VLan: if "1000 Success" in line: break self._stdout_thread = threading.Thread( target=self._log_stream, args=(self.process.stdout, f"vde_switch[{self.nr}]"), daemon=True, ) self._stdout_thread.start() # This is needed to allow systemd-nspawn containers to communicate # with VMs connected to the VLAN. self.logger.info(f"creating tap interface {self.tap_name}") self.logger.debug(f"creating tap interface {self.tap_name}") self.plug_process = subprocess.Popen( ["vde_plug2tap", "-s", self.socket_dir, self.tap_name], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, ) assert self.plug_process.stdout is not None self._plug_stdout_thread = threading.Thread( target=self._log_stream, args=(self.plug_process.stdout, f"vde_plug2tap[{self.nr}]"), daemon=True, ) self._plug_stdout_thread.start() assert (self.socket_dir / "ctl").exists(), "cannot start vde_switch" self.logger.info(f"running vlan (pid {self.pid}; ctl {self.socket_dir})") self.logger.debug(f"running vlan (pid {self.pid}; ctl {self.socket_dir})") def stop(self) -> None: self.logger.info(f"kill vlan (pid {self.pid})") self.logger.debug(f"kill vlan (pid {self.pid})") assert self.process.stdin is not None self.process.stdin.close() if self.plug_process: Loading
nixos/lib/testing/driver.nix +1 −0 Original line number Diff line number Diff line Loading @@ -236,6 +236,7 @@ in logLevel = mkOption { description = "Log level for the test driver."; type = types.enum [ "debug" "info" "warning" "error" Loading