Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 22c6f70

Browse files
authored
Merge pull request #402 from jumpstarter-dev/hostfwd
Qemu Driver: implement hostfwd
2 parents 14bf451 + f5660b8 commit 22c6f70

1 file changed

Lines changed: 25 additions & 3 deletions

File tree

  • packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu

packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@
1111
from secrets import randbits
1212
from subprocess import PIPE, CalledProcessError, Popen, TimeoutExpired
1313
from tempfile import TemporaryDirectory
14+
from typing import Literal
1415

1516
import yaml
1617
from anyio import fail_after, run_process, sleep
1718
from anyio.streams.file import FileReadStream, FileWriteStream
18-
from jumpstarter_driver_network.driver import UnixNetwork, VsockNetwork
19+
from jumpstarter_driver_network.driver import TcpNetwork, UnixNetwork, VsockNetwork
1920
from jumpstarter_driver_opendal.driver import FlasherInterface
2021
from jumpstarter_driver_power.driver import PowerInterface, PowerReading
2122
from jumpstarter_driver_pyserial.driver import PySerial
22-
from pydantic import validate_call
23+
from pydantic import BaseModel, Field, validate_call
2324
from qemu.qmp import QMPClient
2425
from qemu.qmp.protocol import ConnectError, Runstate
2526

@@ -113,7 +114,13 @@ async def on(self) -> None: # noqa: C901
113114
"-serial",
114115
"pty",
115116
"-netdev",
116-
"user,id=eth0",
117+
",".join(
118+
["user", "id=eth0"]
119+
+ [
120+
"hostfwd={}:{}:{}-:{}".format(v.protocol, v.hostaddr, v.hostport, v.guestport)
121+
for k, v in self.parent.hostfwd.items()
122+
]
123+
),
117124
]
118125

119126
devices = [
@@ -219,6 +226,13 @@ def close(self):
219226
self.off()
220227

221228

229+
class Hostfwd(BaseModel):
230+
protocol: Literal["tcp"] = "tcp"
231+
hostaddr: str = "127.0.0.1"
232+
hostport: int = Field(ge=1, le=65535)
233+
guestport: int = Field(ge=1, le=65535)
234+
235+
222236
@dataclass(kw_only=True)
223237
class Qemu(Driver):
224238
arch: str = field(default_factory=platform.machine)
@@ -233,6 +247,8 @@ class Qemu(Driver):
233247

234248
default_partitions: dict[str, Path] = field(default_factory=dict)
235249

250+
hostfwd: dict[str, Hostfwd] = field(default_factory=dict)
251+
236252
_tmp_dir: TemporaryDirectory = field(init=False, default_factory=TemporaryDirectory)
237253

238254
@classmethod
@@ -243,6 +259,7 @@ def __post_init__(self):
243259
if hasattr(super(), "__post_init__"):
244260
super().__post_init__()
245261

262+
self.hostfwd = {k: Hostfwd.model_validate(v) for k, v in self.hostfwd.items()}
246263
self.default_partitions = {k: Path(v) for k, v in self.default_partitions.items()}
247264

248265
self.children["power"] = QemuPower(parent=self)
@@ -251,6 +268,11 @@ def __post_init__(self):
251268
self.children["vnc"] = UnixNetwork(path=self._vnc)
252269
self.children["ssh"] = VsockNetwork(cid=self._cid, port=22)
253270

271+
for k, v in self.hostfwd.items():
272+
match v.protocol:
273+
case "tcp":
274+
self.children[k] = TcpNetwork(host=v.hostaddr, port=v.hostport)
275+
254276
@property
255277
def _pty(self) -> str:
256278
return str(Path(self._tmp_dir.name) / "pty")

0 commit comments

Comments
 (0)