Enable real guest networking and make demos network-first
This commit is contained in:
parent
c43c718c83
commit
b01efa6452
14 changed files with 618 additions and 72 deletions
|
|
@ -5,13 +5,13 @@ from __future__ import annotations
|
|||
import json
|
||||
import socket
|
||||
from dataclasses import dataclass
|
||||
from typing import Callable, Protocol
|
||||
from typing import Any, Callable, Protocol
|
||||
|
||||
|
||||
class SocketLike(Protocol):
|
||||
def settimeout(self, timeout: int) -> None: ...
|
||||
|
||||
def connect(self, address: tuple[int, int]) -> None: ...
|
||||
def connect(self, address: Any) -> None: ...
|
||||
|
||||
def sendall(self, data: bytes) -> None: ...
|
||||
|
||||
|
|
@ -38,19 +38,35 @@ class VsockExecClient:
|
|||
self._socket_factory = socket_factory or socket.socket
|
||||
|
||||
def exec(
|
||||
self, guest_cid: int, port: int, command: str, timeout_seconds: int
|
||||
self,
|
||||
guest_cid: int,
|
||||
port: int,
|
||||
command: str,
|
||||
timeout_seconds: int,
|
||||
*,
|
||||
uds_path: str | None = None,
|
||||
) -> GuestExecResponse:
|
||||
request = {
|
||||
"command": command,
|
||||
"timeout_seconds": timeout_seconds,
|
||||
}
|
||||
family = getattr(socket, "AF_VSOCK", None)
|
||||
if family is None:
|
||||
if family is not None:
|
||||
sock = self._socket_factory(family, socket.SOCK_STREAM)
|
||||
connect_address: Any = (guest_cid, port)
|
||||
elif uds_path is not None:
|
||||
sock = self._socket_factory(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
connect_address = uds_path
|
||||
else:
|
||||
raise RuntimeError("vsock sockets are not supported on this host Python runtime")
|
||||
sock = self._socket_factory(family, socket.SOCK_STREAM)
|
||||
try:
|
||||
sock.settimeout(timeout_seconds)
|
||||
sock.connect((guest_cid, port))
|
||||
sock.connect(connect_address)
|
||||
if family is None:
|
||||
sock.sendall(f"CONNECT {port}\n".encode("utf-8"))
|
||||
status = self._recv_line(sock)
|
||||
if not status.startswith("OK "):
|
||||
raise RuntimeError(f"vsock unix bridge rejected port {port}: {status.strip()}")
|
||||
sock.sendall((json.dumps(request) + "\n").encode("utf-8"))
|
||||
chunks: list[bytes] = []
|
||||
while True:
|
||||
|
|
@ -70,3 +86,15 @@ class VsockExecClient:
|
|||
exit_code=int(payload.get("exit_code", -1)),
|
||||
duration_ms=int(payload.get("duration_ms", 0)),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _recv_line(sock: SocketLike) -> str:
|
||||
chunks: list[bytes] = []
|
||||
while True:
|
||||
data = sock.recv(1)
|
||||
if data == b"":
|
||||
break
|
||||
chunks.append(data)
|
||||
if data == b"\n":
|
||||
break
|
||||
return b"".join(chunks).decode("utf-8", errors="replace")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue