uvms: churn

This commit is contained in:
Else Someone 2026-03-10 02:01:54 +02:00
parent cf95fd33b0
commit add1c4f6bd
7 changed files with 143 additions and 80 deletions

View file

@ -1,5 +0,0 @@
{
lib,
writers,
}:
writers.writePython3Bin "uvms-guest" { } ./guest.py

View file

@ -13,6 +13,8 @@
strace,
util-linux,
virtiofsd,
python3Packages,
uvmslib,
taps,
baseImage,
@ -36,21 +38,25 @@ let
};
toolsClosure = writeClosure toolsFarm;
in
writers.writePython3Bin "uvms" { } (
replaceVars ./uvms.py {
BWRAP = "${lib.getExe bubblewrap}";
TOOLS = "${toolsFarm}/bin";
TOOLS_CLOSURE = toolsClosure;
CROSVM = lib.getExe crosvm;
STRACE = lib.getExe strace;
TAPS = "${lib.getExe taps}";
VIRTIOFSD = "${lib.getExe virtiofsd}";
BASE_CONFIG = baseImage.config.system.build.ch;
SYSTEM = baseImage.config.system.build.toplevel;
SYSTEM_CLOSURE = writeClosure [
baseImage.config.system.build.toplevel
baseImage.config.system.build.ch
];
writers.writePython3Bin "uvms"
{
libraries = [ uvmslib ];
}
)
(
replaceVars ./uvms.py {
BWRAP = "${lib.getExe bubblewrap}";
TOOLS = "${toolsFarm}/bin";
TOOLS_CLOSURE = toolsClosure;
CROSVM = lib.getExe crosvm;
STRACE = lib.getExe strace;
TAPS = "${lib.getExe taps}";
VIRTIOFSD = "${lib.getExe virtiofsd}";
BASE_CONFIG = baseImage.config.system.build.ch;
SYSTEM = baseImage.config.system.build.toplevel;
SYSTEM_CLOSURE = writeClosure [
baseImage.config.system.build.toplevel
baseImage.config.system.build.ch
];
}
)

View file

@ -299,6 +299,7 @@ class Processes:
# "-Z",
# "-ff",
CH,
# "-v",
"--api-socket",
"fd=0",
# f"fd={s.fileno()}"
@ -320,6 +321,8 @@ class Processes:
# ro_bind=["/nix/store"], # I give up
unshare_net=False,
shell=False,
stdout=None,
stderr=None,
# pass_fds=(s.fileno(),)
)
)
@ -340,29 +343,23 @@ class Processes:
):
sock_path = self.prefix + "/gpu.sock"
args = [
SOCKETBINDER,
"-b",
"1",
sock_path,
"s6-ipcserverd",
"-1c1",
# "@STRACE@", # noqa: E501
# "-Z",
# "-ff",
"@CROSVM@", # noqa: E501
"--no-syslog",
"--log-level",
"debug",
"device",
"gpu",
"--fd",
"0",
"--socket-path",
sock_path,
"--wayland-sock",
f'{PASSTHRU_ENV["XDG_RUNTIME_DIR"]}/{PASSTHRU_ENV["WAYLAND_DISPLAY"]}', # noqa: E501
"--params",
'{ "context-types": "cross-domain:virgl2:venus" }',
'{ "context-types": "cross-domain" }',
]
with self.popen(
*args,
stderr=None,
stdout=None,
) as proc, removing(sock_path, sock_path + ".lock"):
yield proc, sock_path
@ -585,6 +582,13 @@ def main(args, args_next, cleanup, ps):
config["memory"]["size"] = parse_bytes(args.mem)
config["memory"]["hotplug_size"] = parse_bytes(args.mem)
if "platform" not in config:
config["platform"] = {}
config["platform"]["oem_strings"] = [
"io.systemd.credential:vmm.notify_socket=vsock-stream:2:8888",
*config["platform"].get("oem_strings", []),
]
gpud, gpud_path = cleanup.enter_context(ps.start_gpu())
ch = cleanup.enter_context(ps.run_ch())
@ -610,48 +614,71 @@ def main(args, args_next, cleanup, ps):
ps.exec(*ch_remote, "boot")
ps.exec(*ch_remote, "info")
ready = False
with ready_sock:
ready_sock.settimeout(20.0)
try:
con, _ = ready_sock.accept()
except: # noqa: E722
print(
"CH didn't try connecting to the readiness notification socket"
) # noqa: E501
else:
with con:
msg = con.recv(128)
assert msg.startswith(b"READY=1"), msg
ready_sock.settimeout(8.0)
for _ in range(1048576):
if ready:
break
try:
con, _ = ready_sock.accept()
except: # noqa: E722
print(
"WARNING: CH didn't try connecting to the readiness notification socket" # noqa: E501
)
ready = True
break
else:
with con:
msg = con.recv(1024)
for ln in msg.split(b"\n"):
ln = ln.strip()
print(ln)
# if ln.startswith(b"X_SYSTEMD_UNIT_ACTIVE=uvms-guest.service"): # noqa: E501
if ln.startswith(b"READY=1"): # noqa: E501
ready = True
break
assert ready
with connect_ch_vsock(ps.prefix + "/vsock.sock", 24601) as guest:
for r in args.run:
try:
guest.send(
json.dumps(
{
"run": {
"argv": [r],
"EXTRA_PATH": [
f"{a}/bin" for a in app_paths
], # noqa: E501
}
}
).encode("utf8")
)
res = guest.recv(8192)
res = {}
for _ in range(1):
if "status" in res:
break
try:
res = json.loads(guest.recv(8192))
except json.JSONDecodeError as e:
print(f"Couldn't interpret --run {r} response: {e} {res}")
continue
adverb = (
"Successfully"
if res["status"] == "exec succeeded"
else "Failed to" # noqa: E501
)
print(f"{adverb} --run {r}: {res}")
except Exception as e:
print(f"Couldn't --run {r}: {repr(e)}")
guest.send(
json.dumps(
{
"run": {
"argv": [r],
"EXTRA_PATH": [
f"{a}/bin" for a in app_paths
], # noqa: E501
}
}
).encode("utf8")
)
res = guest.recv(8192)
try:
res = json.loads(guest.recv(8192))
except json.JSONDecodeError as e:
print(
f"Couldn't interpret --run {r} response: {e} {res}"
) # noqa: E501
res = {}
# res = {"status": "failed"}
except Exception as e:
print(f"Couldn't --run {r}: {repr(e)}")
if "status" not in res:
res["status"] = "fail"
adverb = (
"Successfully"
if res["status"] == "exec succeeded"
else "Failed to" # noqa: E501
)
print(f"{adverb} --run {r}: {res}")
try:
ch.wait()
except KeyboardInterrupt:

21
pkgs/uvmslib/package.nix Normal file
View file

@ -0,0 +1,21 @@
{
lib,
python3Packages,
}:
python3Packages.buildPythonPackage {
pname = "uvmslib";
version = "0.0.0";
pyproject = true;
src =
let
fs = lib.fileset;
in
fs.toSource {
root = ./.;
fileset = fs.unions [
./pyproject.toml
./uvmslib.py
];
};
build-system = [ python3Packages.setuptools ];
}

View file

@ -0,0 +1,10 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = [ "setuptools" ]
[project]
name = "uvms"
version = "0.0.0"
[project.scripts]
"uvms-guest" = "uvmslib:guest_main"

View file

@ -59,7 +59,7 @@ class Processes:
proc = None
try:
proc = self.popen(
req["run"]["argv"],
run["argv"],
text=text,
env=env,
cwd="/home/user",
@ -82,14 +82,14 @@ class Processes:
return res, proc
def accept_vsock(self, s):
con, (cid, port) = serv.accept()
con, (cid, port) = s.accept()
assert cid == 2, cid
self.sources.append(con)
self.client_fds.add(con.fileno())
return con, (cid, port)
if __name__ == "__main__":
def guest_main():
ps = Processes()
serv = socket.fromfd(3, socket.AF_VSOCK, socket.SOCK_STREAM)
ps.sources.append(serv)
@ -134,3 +134,7 @@ if __name__ == "__main__":
con.send(res)
else:
assert False, con.fileno()
if __name__ == "__main__":
guest_main()

View file

@ -42,7 +42,7 @@ in
_module.args.uvmsPkgs = lib.mkDefault (pkgs.callPackage ../pkgs { });
# some.failure-handler.enable = true;
hardware.graphics.enable = true;
boot.kernelPackages = pkgs.linuxPackagesFor uvmsPkgs.linux-uvm;
# boot.kernelPackages = pkgs.linuxPackagesFor uvmsPkgs.linux-uvm;
# boot.isContainer = true;
boot.initrd.kernelModules = [
"drm"
@ -251,19 +251,20 @@ in
};
systemd.sockets."uvms-guest" = {
wantedBy = [ "default.target" ];
requiredBy = [ "multi-user.target" ];
before = [ "multi-user.target" ];
listenStreams = [
"vsock::24601"
];
partOf = [ "uvms-guest.service" ];
};
systemd.services."uvms-guest" = {
requiredBy = [ "multi-user.target" ];
before = [ "multi-user.target" ];
onFailure = [ "shutdown.service" ];
serviceConfig = {
User = "user";
Group = "users";
ExecStart = "${lib.getExe uvmsPkgs.uvms-guest}";
ExecStart = "${lib.getExe' uvmsPkgs.uvmslib "uvms-guest"}";
ExecStop = [
"/run/current-system/sw/bin/echo GUEST DOWN"
"/run/current-system/sw/bin/systemctl poweroff"
@ -288,7 +289,6 @@ in
"console=ttyS0"
"reboot=t"
"panic=-1"
"io.systemd.credential:vmm.notify_socket=vsock-stream:2:8888"
# "rootfstype=virtiofs"
# "root=rootstore"
];
@ -390,7 +390,7 @@ in
options = {
size = mkOption {
type = types.int;
default = 2 * 1024 * 1048576;
default = 4 * 1024 * 1048576;
};
shared = mkOption {
type = types.bool;