clan_cli: Made qmp implementation lazy

This commit is contained in:
Qubasa
2024-02-13 15:15:43 +07:00
parent 4323e73517
commit a1afd05fcb
6 changed files with 110 additions and 51 deletions

View File

@@ -1,11 +1,11 @@
import json
import logging
from collections.abc import Generator
from contextlib import contextmanager
from os import path
from pathlib import Path
from tempfile import NamedTemporaryFile
from time import sleep
from tempfile import NamedTemporaryFile, TemporaryDirectory
from clan_cli.dirs import vm_state_dir
from qemu.qmp import QEMUMonitorProtocol
from ..cmd import run
@@ -16,6 +16,39 @@ from ..ssh import Host, parse_deployment_address
log = logging.getLogger(__name__)
class VMAttr:
def __init__(self, machine_name: str) -> None:
self.temp_dir = TemporaryDirectory(prefix="clan_vm-", suffix=f"-{machine_name}")
self._qmp_socket: Path = Path(self.temp_dir.name) / "qmp.sock"
self._qga_socket: Path = Path(self.temp_dir.name) / "qga.sock"
self._qmp: QEMUMonitorProtocol | None = None
@contextmanager
def qmp(self) -> Generator[QEMUMonitorProtocol, None, None]:
if self._qmp is None:
log.debug(f"qmp_socket: {self._qmp_socket}")
self._qmp = QEMUMonitorProtocol(path.realpath(self._qmp_socket))
self._qmp.connect()
try:
yield self._qmp
finally:
self._qmp.close()
@property
def qmp_socket(self) -> Path:
if self._qmp is None:
log.debug(f"qmp_socket: {self._qmp_socket}")
self._qmp = QEMUMonitorProtocol(path.realpath(self._qmp_socket))
return self._qmp_socket
@property
def qga_socket(self) -> Path:
if self._qmp is None:
log.debug(f"qmp_socket: {self.qga_socket}")
self._qmp = QEMUMonitorProtocol(path.realpath(self._qmp_socket))
return self._qga_socket
class Machine:
def __init__(
self,
@@ -36,14 +69,8 @@ class Machine:
self.build_cache: dict[str, Path] = {}
self._deployment_info: None | dict[str, str] = deployment_info
state_dir = vm_state_dir(flake_url=str(self.flake), vm_name=self.name)
self.qmp_socket: Path = state_dir / "qmp.sock"
self.qga_socket: Path = state_dir / "qga.sock"
log.debug(f"qmp_socket: {self.qmp_socket}")
self._qmp = QEMUMonitorProtocol(path.realpath(self.qmp_socket))
self._qmp_connected = False
self.vm: VMAttr = VMAttr(name)
def __str__(self) -> str:
return f"Machine(name={self.name}, flake={self.flake})"
@@ -60,28 +87,6 @@ class Machine:
)
return self._deployment_info
def qmp_connect(self) -> None:
if not self._qmp_connected:
tries = 100
for num in range(tries):
try:
# the socket file link might be outdated, therefore re-init the qmp object
self._qmp = QEMUMonitorProtocol(path.realpath(self.qmp_socket))
self._qmp.connect()
self._qmp_connected = True
log.debug("QMP Connected")
return
except FileNotFoundError:
if num < 99:
sleep(0.1)
continue
else:
raise
def qmp_command(self, command: str) -> dict:
self.qmp_connect()
return self._qmp.command(command)
@property
def target_host_address(self) -> str:
# deploymentAddress is deprecated.

View File

@@ -146,7 +146,9 @@ def qemu_command(
# TODO move this to the Machines class
def build_vm(machine: Machine, vm: VmConfig, nix_options: list[str]) -> dict[str, str]:
def build_vm(
machine: Machine, vm: VmConfig, nix_options: list[str] = []
) -> dict[str, str]:
config = nix_config()
system = config["system"]