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");
vhostPatches = patchesFromDir (spectrum + "/pkgs/cloud-hypervisor/vhost");
};
previouslyPatched = oldAttrs ? spectrumPatches;
patchPhases = !previouslyPatched;
oldPatchesStruct = oldAttrs.passthru.spectrumPatches or { };
missingPatchPhases = previouslyPatched != { };
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;
in
optionalAttrs isNewer {
@ -47,7 +47,7 @@ cloud-hypervisor.overrideAttrs (
# Verbatim from spectrum
postUnpack =
oldAttrs.postUnpack or ""
+ optionalString patchPhases ''
+ optionalString missingPatchPhases ''
unpackFile $vhost
chmod -R +w vhost
'';
@ -58,7 +58,7 @@ cloud-hypervisor.overrideAttrs (
# Verbatim copy from spectrum
postPatch =
oldAttrs.postPatch or ""
+ optionalString patchPhases ''
+ optionalString missingPatchPhases ''
pushd ../vhost
for patch in $vhostPatches; do
echo applying patch $patch

View file

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

View file

@ -55,6 +55,16 @@ class Processes:
"/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
try:
@ -63,8 +73,8 @@ class Processes:
text=text,
env=env,
cwd="/home/user",
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=None,
stdout=None,
)
res["status"] = "exec succeeded"
except Exception as e:
@ -116,6 +126,7 @@ def guest_main():
# IDK why but I keep getting empty messages
if req == b"":
print(f"Lost [{con.fileno()}]")
ps.sources = [s for s in ps.sources if s.fileno() != con.fileno()]
continue
try:
req = json.loads(req)

View file

@ -16,6 +16,7 @@ let
kernelTarget = pkgs.stdenv.hostPlatform.linux-kernel.target;
waylandSock = "/run/user/1000/wayland-1";
env = {
DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/1000/bus";
XDG_RUNTIME_DIR = "/run/user/1000";
WAYLAND_DISPLAY = "wayland-1";
@ -44,6 +45,11 @@ in
hardware.graphics.enable = true;
# boot.kernelPackages = pkgs.linuxPackagesFor uvmsPkgs.linux-uvm;
# boot.isContainer = true;
boot.kernel.sysctl = {
"vm.overcommit_memory" = 1; # "always"
# "vm.overcommit_memory" = 2; # "never"
"vm.panic_on_oom" = 1;
};
boot.initrd.kernelModules = [
"drm"
"virtio_blk"
@ -104,6 +110,7 @@ in
};
};
programs.dconf.enable = true;
systemd.mounts = [
{
type = "virtiofs";
@ -210,6 +217,8 @@ in
};
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;
systemd.globalEnvironment = env;
@ -302,9 +311,9 @@ in
uvms.ch.settings = mkOption {
default = { };
type = types.submodule (
let
osConfig = config;
in
let
osConfig = config;
in
{ config, ... }:
{
freeformType = jsonType;