Compare commits

..

No commits in common. "add1c4f6bd15f4ccc626edd3eb71b3e7a2959067" and "db4e7809d142e757719b5f357505ade09ccfa56b" have entirely different histories.

7 changed files with 181 additions and 289 deletions

View file

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

View file

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

View file

@ -13,8 +13,6 @@
strace, strace,
util-linux, util-linux,
virtiofsd, virtiofsd,
python3Packages,
uvmslib,
taps, taps,
baseImage, baseImage,
@ -38,11 +36,7 @@ let
}; };
toolsClosure = writeClosure toolsFarm; toolsClosure = writeClosure toolsFarm;
in in
writers.writePython3Bin "uvms" writers.writePython3Bin "uvms" { } (
{
libraries = [ uvmslib ];
}
(
replaceVars ./uvms.py { replaceVars ./uvms.py {
BWRAP = "${lib.getExe bubblewrap}"; BWRAP = "${lib.getExe bubblewrap}";
TOOLS = "${toolsFarm}/bin"; TOOLS = "${toolsFarm}/bin";
@ -59,4 +53,4 @@ writers.writePython3Bin "uvms"
baseImage.config.system.build.ch baseImage.config.system.build.ch
]; ];
} }
) )

View file

@ -10,7 +10,6 @@ import os
import subprocess import subprocess
import socket import socket
import json import json
import re
from argparse import ArgumentParser from argparse import ArgumentParser
from contextlib import contextmanager, closing, ExitStack from contextlib import contextmanager, closing, ExitStack
@ -21,7 +20,6 @@ parser.add_argument("--prefix", default="$HOME/uvms/$VM")
parser.add_argument("--vm-config", default="@BASE_CONFIG@") # noqa: E501 parser.add_argument("--vm-config", default="@BASE_CONFIG@") # noqa: E501
parser.add_argument("--persist-home", action="store_true") parser.add_argument("--persist-home", action="store_true")
parser.add_argument("--run", action="append") parser.add_argument("--run", action="append")
parser.add_argument("--mem", default=None)
parser.add_argument("app", nargs="*", default=()) parser.add_argument("app", nargs="*", default=())
TOOLS_DIR = "@TOOLS@" # noqa: E501 TOOLS_DIR = "@TOOLS@" # noqa: E501
@ -299,7 +297,6 @@ class Processes:
# "-Z", # "-Z",
# "-ff", # "-ff",
CH, CH,
# "-v",
"--api-socket", "--api-socket",
"fd=0", "fd=0",
# f"fd={s.fileno()}" # f"fd={s.fileno()}"
@ -321,8 +318,6 @@ class Processes:
# ro_bind=["/nix/store"], # I give up # ro_bind=["/nix/store"], # I give up
unshare_net=False, unshare_net=False,
shell=False, shell=False,
stdout=None,
stderr=None,
# pass_fds=(s.fileno(),) # pass_fds=(s.fileno(),)
) )
) )
@ -343,23 +338,29 @@ class Processes:
): ):
sock_path = self.prefix + "/gpu.sock" sock_path = self.prefix + "/gpu.sock"
args = [ args = [
SOCKETBINDER,
"-b",
"1",
sock_path,
"s6-ipcserverd",
"-1c1",
# "@STRACE@", # noqa: E501
# "-Z",
# "-ff",
"@CROSVM@", # noqa: E501 "@CROSVM@", # noqa: E501
"--no-syslog", "--no-syslog",
"--log-level",
"debug",
"device", "device",
"gpu", "gpu",
"--socket-path", "--fd",
sock_path, "0",
"--wayland-sock", "--wayland-sock",
f'{PASSTHRU_ENV["XDG_RUNTIME_DIR"]}/{PASSTHRU_ENV["WAYLAND_DISPLAY"]}', # noqa: E501 f'{PASSTHRU_ENV["XDG_RUNTIME_DIR"]}/{PASSTHRU_ENV["WAYLAND_DISPLAY"]}', # noqa: E501
"--params", "--params",
'{ "context-types": "cross-domain" }', '{ "context-types": "cross-domain:virgl2:venus" }',
] ]
with self.popen( with self.popen(
*args, *args,
stderr=None, stderr=None,
stdout=None,
) as proc, removing(sock_path, sock_path + ".lock"): ) as proc, removing(sock_path, sock_path + ".lock"):
yield proc, sock_path yield proc, sock_path
@ -468,21 +469,6 @@ def connect_ch_vsock(
yield s yield s
BYTES_PATTERN = re.compile(r"^([0-9]+)([MmGgKk]?)$")
BYTES_UNITS = {
"k": 1024,
"m": 1048576,
"g": 1024 * 1048576,
}
def parse_bytes(s):
m = BYTES_PATTERN.match(s)
assert m, s
size, unit = m.groups()
return int(size) * BYTES_UNITS.get(unit.lower(), 1)
@contextmanager @contextmanager
def listen_ch_vsock( def listen_ch_vsock(
vsock_sock_path, vsock_sock_path,
@ -578,16 +564,6 @@ def main(args, args_next, cleanup, ps):
) )
virtiofs_socks.append(("home", sock_path)) virtiofs_socks.append(("home", sock_path))
config["payload"]["cmdline"] += " uvms.persist-home=1" config["payload"]["cmdline"] += " uvms.persist-home=1"
if args.mem is not None:
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()) gpud, gpud_path = cleanup.enter_context(ps.start_gpu())
@ -614,39 +590,21 @@ def main(args, args_next, cleanup, ps):
ps.exec(*ch_remote, "boot") ps.exec(*ch_remote, "boot")
ps.exec(*ch_remote, "info") ps.exec(*ch_remote, "info")
ready = False
with ready_sock: with ready_sock:
ready_sock.settimeout(8.0) ready_sock.settimeout(20.0)
for _ in range(1048576):
if ready:
break
try: try:
con, _ = ready_sock.accept() con, _ = ready_sock.accept()
except: # noqa: E722 except: # noqa: E722
print( print(
"WARNING: CH didn't try connecting to the readiness notification socket" # noqa: E501 "CH didn't try connecting to the readiness notification socket"
) ) # noqa: E501
ready = True
break
else: else:
with con: with con:
msg = con.recv(1024) msg = con.recv(128)
for ln in msg.split(b"\n"): assert msg.startswith(b"READY=1"), msg
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: with connect_ch_vsock(ps.prefix + "/vsock.sock", 24601) as guest:
for r in args.run: for r in args.run:
res = {}
for _ in range(1):
if "status" in res:
break
try: try:
guest.send( guest.send(
json.dumps( json.dumps(
@ -664,21 +622,16 @@ def main(args, args_next, cleanup, ps):
try: try:
res = json.loads(guest.recv(8192)) res = json.loads(guest.recv(8192))
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
print( print(f"Couldn't interpret --run {r} response: {e} {res}")
f"Couldn't interpret --run {r} response: {e} {res}" continue
) # 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 = ( adverb = (
"Successfully" "Successfully"
if res["status"] == "exec succeeded" if res["status"] == "exec succeeded"
else "Failed to" # noqa: E501 else "Failed to" # noqa: E501
) )
print(f"{adverb} --run {r}: {res}") print(f"{adverb} --run {r}: {res}")
except Exception as e:
print(f"Couldn't --run {r}: {repr(e)}")
try: try:
ch.wait() ch.wait()
except KeyboardInterrupt: except KeyboardInterrupt:

View file

@ -1,21 +0,0 @@
{
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

@ -1,10 +0,0 @@
[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

@ -42,7 +42,7 @@ in
_module.args.uvmsPkgs = lib.mkDefault (pkgs.callPackage ../pkgs { }); _module.args.uvmsPkgs = lib.mkDefault (pkgs.callPackage ../pkgs { });
# some.failure-handler.enable = true; # some.failure-handler.enable = true;
hardware.graphics.enable = true; hardware.graphics.enable = true;
# boot.kernelPackages = pkgs.linuxPackagesFor uvmsPkgs.linux-uvm; boot.kernelPackages = pkgs.linuxPackagesFor uvmsPkgs.linux-uvm;
# boot.isContainer = true; # boot.isContainer = true;
boot.initrd.kernelModules = [ boot.initrd.kernelModules = [
"drm" "drm"
@ -251,20 +251,19 @@ in
}; };
systemd.sockets."uvms-guest" = { systemd.sockets."uvms-guest" = {
requiredBy = [ "multi-user.target" ]; wantedBy = [ "default.target" ];
before = [ "multi-user.target" ];
listenStreams = [ listenStreams = [
"vsock::24601" "vsock::24601"
]; ];
partOf = [ "uvms-guest.service" ]; partOf = [ "uvms-guest.service" ];
}; };
systemd.services."uvms-guest" = { systemd.services."uvms-guest" = {
before = [ "multi-user.target" ]; requiredBy = [ "multi-user.target" ];
onFailure = [ "shutdown.service" ]; onFailure = [ "shutdown.service" ];
serviceConfig = { serviceConfig = {
User = "user"; User = "user";
Group = "users"; Group = "users";
ExecStart = "${lib.getExe' uvmsPkgs.uvmslib "uvms-guest"}"; ExecStart = "${lib.getExe uvmsPkgs.uvms-guest}";
ExecStop = [ ExecStop = [
"/run/current-system/sw/bin/echo GUEST DOWN" "/run/current-system/sw/bin/echo GUEST DOWN"
"/run/current-system/sw/bin/systemctl poweroff" "/run/current-system/sw/bin/systemctl poweroff"
@ -289,6 +288,7 @@ in
"console=ttyS0" "console=ttyS0"
"reboot=t" "reboot=t"
"panic=-1" "panic=-1"
"io.systemd.credential:vmm.notify_socket=vsock-stream:2:8888"
# "rootfstype=virtiofs" # "rootfstype=virtiofs"
# "root=rootstore" # "root=rootstore"
]; ];
@ -301,25 +301,20 @@ in
}; };
uvms.ch.settings = mkOption { uvms.ch.settings = mkOption {
default = { }; default = { };
type = types.submodule ( type = types.submodule {
let
osConfig = config;
in
{ config, ... }:
{
freeformType = jsonType; freeformType = jsonType;
options = { options = {
payload = { payload = {
cmdline = mkOption { cmdline = mkOption {
type = types.str; type = types.str;
default = concatStringsSep " " ( default = concatStringsSep " " (
osConfig.boot.kernelParams config.boot.kernelParams
++ [ ++ [
# "init=${lib.removePrefix "/nix/store" "${osConfig.system.build.toplevel}"}/init" # "init=${lib.removePrefix "/nix/store" "${config.system.build.toplevel}"}/init"
"init=${osConfig.system.build.toplevel}/init" "init=${config.system.build.toplevel}/init"
] ]
); );
defaultText = ''concatStringsSep " " ${osConfig.boot.kernelParams}''; defaultText = ''concatStringsSep " " ${config.boot.kernelParams}'';
}; };
kernel = mkOption { kernel = mkOption {
type = types.str; type = types.str;
@ -390,7 +385,7 @@ in
options = { options = {
size = mkOption { size = mkOption {
type = types.int; type = types.int;
default = 4 * 1024 * 1048576; default = 3 * 1024 * 1048576;
}; };
shared = mkOption { shared = mkOption {
type = types.bool; type = types.bool;
@ -400,25 +395,6 @@ in
type = types.bool; type = types.bool;
default = true; default = true;
}; };
hotplug_method = mkOption {
default = "VirtioMem";
type = types.enum [
"Acpi"
"VirtioMem"
];
};
hotplugged_size = mkOption {
type = types.int;
default = 512 * 1048576;
};
hotplug_size = mkOption {
type = types.int;
default = config.memory.size;
};
# hugepages = mkOption {
# type = types.bool;
# default = true;
# };
}; };
}; };
}; };
@ -439,8 +415,7 @@ in
}; };
}; };
}; };
} };
);
}; };
}; };
} }