Compare commits

..

8 commits

Author SHA1 Message Date
Else Someone
8fb586c8b6 cloud-hypervisor: clean up the short-circuiting logic 2026-03-22 21:25:48 +02:00
Else Someone
42180096af baseImage: tinkering with overcommit 2026-03-22 16:19:11 +02:00
Else Someone
3540b5aba2 uvms: support .desktop applications 2026-03-15 02:16:16 +02:00
Else Someone
90614bdf74 uvms: do not rm vsock.sock until vmm is down 2026-03-15 02:15:41 +02:00
Else Someone
0692a20ae9 uvms: do not hang on communicate() 2026-03-15 01:30:27 +02:00
Else Someone
a13e9c9393 uvms: support args in app urls 2026-03-15 01:30:18 +02:00
Else Someone
42fca62474 uvms: init app urls, kinda 2026-03-11 17:39:00 +02:00
Else Someone
f8cc57f146 fixup! uvms: churn 2026-03-11 17:38:49 +02:00
4 changed files with 60 additions and 15 deletions

View file

@ -34,10 +34,10 @@ cloud-hypervisor.overrideAttrs (
patches = patchesFromDir (spectrum + "/pkgs/cloud-hypervisor"); patches = patchesFromDir (spectrum + "/pkgs/cloud-hypervisor");
vhostPatches = patchesFromDir (spectrum + "/pkgs/cloud-hypervisor/vhost"); vhostPatches = patchesFromDir (spectrum + "/pkgs/cloud-hypervisor/vhost");
}; };
previouslyPatched = oldAttrs ? spectrumPatches; oldPatchesStruct = oldAttrs.passthru.spectrumPatches or { };
patchPhases = !previouslyPatched; missingPatchPhases = previouslyPatched != { };
isNewer = lib.versionOlder oldAttrs.spectrumPatches.version or "2000-00-00" spectrumPatches.version; isNewer = lib.versionOlder oldAttrs.spectrumPatches.version or "2000-00-00" spectrumPatches.version;
oldPatches = oldAttrs.spectrumPatches.patches or [ ]; oldPatches = oldPatchesStruct.patches or [ ];
removeAll = removeElts: lst: builtins.filter (x: !(builtins.elem x removeElts)) lst; removeAll = removeElts: lst: builtins.filter (x: !(builtins.elem x removeElts)) lst;
in in
optionalAttrs isNewer { optionalAttrs isNewer {
@ -47,7 +47,7 @@ cloud-hypervisor.overrideAttrs (
# Verbatim from spectrum # Verbatim from spectrum
postUnpack = postUnpack =
oldAttrs.postUnpack or "" oldAttrs.postUnpack or ""
+ optionalString patchPhases '' + optionalString missingPatchPhases ''
unpackFile $vhost unpackFile $vhost
chmod -R +w vhost chmod -R +w vhost
''; '';
@ -58,7 +58,7 @@ cloud-hypervisor.overrideAttrs (
# Verbatim copy from spectrum # Verbatim copy from spectrum
postPatch = postPatch =
oldAttrs.postPatch or "" oldAttrs.postPatch or ""
+ optionalString patchPhases '' + optionalString missingPatchPhases ''
pushd ../vhost pushd ../vhost
for patch in $vhostPatches; do for patch in $vhostPatches; do
echo applying patch $patch echo applying patch $patch

View file

@ -13,6 +13,7 @@ import json
import re import re
from argparse import ArgumentParser from argparse import ArgumentParser
from contextlib import contextmanager, closing, ExitStack from contextlib import contextmanager, closing, ExitStack
from urllib.parse import urlparse, parse_qs
parser = ArgumentParser("supervise-vm") parser = ArgumentParser("supervise-vm")
@ -157,7 +158,7 @@ class Processes:
print(f"Releasing {args}") print(f"Releasing {args}")
finally: finally:
if subprocess.PIPE in (kwargs["stderr"], kwargs["stdout"]): if subprocess.PIPE in (kwargs["stderr"], kwargs["stdout"]):
print(proc.communicate()) print(proc.communicate(timeout=0.125))
while alive_after(proc, 0.125): while alive_after(proc, 0.125):
try: try:
proc.terminate() proc.terminate()
@ -354,7 +355,7 @@ class Processes:
"--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" }',
] ]
with self.popen( with self.popen(
*args, *args,
@ -463,7 +464,7 @@ def connect_ch_vsock(
s.setblocking(blocking) s.setblocking(blocking)
s.connect(vsock_sock_path) s.connect(vsock_sock_path)
with removing(vsock_sock_path): with closing(s):
s.send(b"CONNECT %d\n" % port) s.send(b"CONNECT %d\n" % port)
yield s yield s
@ -517,12 +518,32 @@ def main(args, args_next, cleanup, ps):
app_paths = [] app_paths = []
for a in args.app: for a in args.app:
a = urlparse(a)
nix_file = "./."
attr = None
if a.scheme == "":
nix_file = "<nixpkgs>"
attr = a.path
else:
assert a.fragment, a
attr = a.fragment
nix_file = a.path or "./."
arglist = []
for k, v in parse_qs(a.query).items():
arglist.append("--arg")
arglist.append(k)
arglist.append(v)
assert nix_file is not None, a
assert attr is not None, a
out_path = ps.exec( out_path = ps.exec(
"nix-build", "nix-build",
"<nixpkgs>", nix_file,
"-A", "-A",
a, attr,
*arglist,
"--no-out-link", "--no-out-link",
cwd=os.getcwd(),
capture_output=True, capture_output=True,
text=True, text=True,
).stdout.strip() ).stdout.strip()
@ -641,6 +662,7 @@ def main(args, args_next, cleanup, ps):
assert ready assert ready
cleanup.enter_context(removing(ps.prefix + "/vsock.sock"))
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 = {} res = {}
@ -656,6 +678,9 @@ def main(args, args_next, cleanup, ps):
"EXTRA_PATH": [ "EXTRA_PATH": [
f"{a}/bin" for a in app_paths f"{a}/bin" for a in app_paths
], # noqa: E501 ], # noqa: E501
"EXTRA_XDG_DATA_DIRS": [
f"{a}/share" for a in app_paths
], # noqa: E501
} }
} }
).encode("utf8") ).encode("utf8")

View file

@ -55,6 +55,16 @@ class Processes:
"/run/current-system/sw/bin", "/run/current-system/sw/bin",
], ],
), ),
"XDG_DATA_DIRS": ":".join(
[
*os.environ.get("XDG_DATA_DIRS", "").split(":"),
*run.get(
"EXTRA_XDG_DATA_DIRS",
[],
),
"/run/current-system/sw/share",
],
),
} }
proc = None proc = None
try: try:
@ -63,8 +73,8 @@ class Processes:
text=text, text=text,
env=env, env=env,
cwd="/home/user", cwd="/home/user",
stdin=subprocess.PIPE, stdin=None,
stdout=subprocess.PIPE, stdout=None,
) )
res["status"] = "exec succeeded" res["status"] = "exec succeeded"
except Exception as e: except Exception as e:
@ -116,6 +126,7 @@ def guest_main():
# IDK why but I keep getting empty messages # IDK why but I keep getting empty messages
if req == b"": if req == b"":
print(f"Lost [{con.fileno()}]") print(f"Lost [{con.fileno()}]")
ps.sources = [s for s in ps.sources if s.fileno() != con.fileno()]
continue continue
try: try:
req = json.loads(req) req = json.loads(req)

View file

@ -16,6 +16,7 @@ let
kernelTarget = pkgs.stdenv.hostPlatform.linux-kernel.target; kernelTarget = pkgs.stdenv.hostPlatform.linux-kernel.target;
waylandSock = "/run/user/1000/wayland-1"; waylandSock = "/run/user/1000/wayland-1";
env = { env = {
DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/1000/bus";
XDG_RUNTIME_DIR = "/run/user/1000"; XDG_RUNTIME_DIR = "/run/user/1000";
WAYLAND_DISPLAY = "wayland-1"; WAYLAND_DISPLAY = "wayland-1";
@ -44,6 +45,11 @@ in
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.kernel.sysctl = {
"vm.overcommit_memory" = 1; # "always"
# "vm.overcommit_memory" = 2; # "never"
"vm.panic_on_oom" = 1;
};
boot.initrd.kernelModules = [ boot.initrd.kernelModules = [
"drm" "drm"
"virtio_blk" "virtio_blk"
@ -104,6 +110,7 @@ in
}; };
}; };
programs.dconf.enable = true;
systemd.mounts = [ systemd.mounts = [
{ {
type = "virtiofs"; type = "virtiofs";
@ -210,6 +217,8 @@ in
}; };
environment.profileRelativeSessionVariables.PATH = lib.mkForce [ "/bin\${PATH:+:}$PATH" ]; environment.profileRelativeSessionVariables.PATH = lib.mkForce [ "/bin\${PATH:+:}$PATH" ];
environment.profileRelativeSessionVariables.XDG_DATA_DIRS = lib.mkForce [ "/run/current-system/sw/share/\${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS" ];
environment.sessionVariables = env;
environment.variables = env; environment.variables = env;
systemd.globalEnvironment = env; systemd.globalEnvironment = env;
@ -302,9 +311,9 @@ in
uvms.ch.settings = mkOption { uvms.ch.settings = mkOption {
default = { }; default = { };
type = types.submodule ( type = types.submodule (
let let
osConfig = config; osConfig = config;
in in
{ config, ... }: { config, ... }:
{ {
freeformType = jsonType; freeformType = jsonType;