This introduces support for drag&drop and printing portals, and later camera/screencasting should be possible as well. However we break backwards compatibility with already built closures because the nixosModule needs to be changed. In the next commit, the runtime environment related services will be removed from the nixosModule to prevent unnecessary future breakage.
313 lines
10 KiB
Nix
313 lines
10 KiB
Nix
{
|
|
self,
|
|
}:
|
|
{
|
|
pkgs,
|
|
lib,
|
|
utils,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
useTTY = {
|
|
TTYPath = "/dev/hvc0";
|
|
StandardOutput = "tty";
|
|
StandardInput = "tty";
|
|
StandardError = "tty";
|
|
};
|
|
runtimeDir = "/run/vm-user";
|
|
system = pkgs.stdenv.hostPlatform.system;
|
|
in
|
|
{
|
|
options.virtualisation.munix.defaultCommand = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "bash";
|
|
description = "Default command to run when starting the VM without arguments.";
|
|
};
|
|
|
|
config = {
|
|
boot.isContainer = true;
|
|
fileSystems."/".device = lib.mkDefault "/dev/sda"; # dummy
|
|
|
|
# Disable unused things
|
|
environment.defaultPackages = lib.mkDefault [ ];
|
|
documentation = {
|
|
enable = lib.mkDefault false;
|
|
doc.enable = lib.mkDefault false;
|
|
info.enable = lib.mkDefault false;
|
|
man.enable = lib.mkDefault false;
|
|
nixos.enable = lib.mkDefault false;
|
|
};
|
|
services.logrotate.enable = false;
|
|
services.udisks2.enable = false;
|
|
system.tools.nixos-generate-config.enable = false;
|
|
system.activationScripts.specialfs = lib.mkForce "";
|
|
systemd.coredump.enable = false;
|
|
networking.firewall.enable = false;
|
|
powerManagement.enable = false;
|
|
boot.kexec.enable = false;
|
|
console.enable = false;
|
|
|
|
# Configure activation / systemd
|
|
boot.initrd.systemd.enable = true; # for etc.overlay, but we don't have initrd
|
|
system.etc.overlay.enable = true; # erofs
|
|
system.etc.overlay.mutable = false;
|
|
system.systemBuilderCommands = # XXX: removed with the introduction of nixos-init
|
|
''
|
|
ln -s ${config.system.build.etcMetadataImage} $out/etc-metadata-image
|
|
ln -s ${config.system.build.etcBasedir} $out/etc-basedir
|
|
'';
|
|
system.switch.enable = false;
|
|
services.udev.enable = lib.mkDefault true;
|
|
services.udev.packages = lib.mkDefault [ ];
|
|
services.resolved.enable = false;
|
|
environment.etc."resolv.conf".source = "/run/resolv.conf";
|
|
environment.etc."machine-id".source = "/run/machine-id";
|
|
environment.etc."localtime".source = "/run/localtime";
|
|
environment.etc."systemd/system".source = lib.mkForce (
|
|
utils.systemdUtils.lib.generateUnits {
|
|
type = "system";
|
|
units = config.systemd.units;
|
|
upstreamUnits = [
|
|
"sysinit.target"
|
|
"local-fs.target"
|
|
"nss-user-lookup.target"
|
|
"umount.target"
|
|
"sockets.target"
|
|
"shutdown.target"
|
|
"reboot.target"
|
|
"exit.target"
|
|
"final.target"
|
|
"systemd-exit.service"
|
|
"systemd-journald.socket"
|
|
"systemd-journald-audit.socket"
|
|
"systemd-journald-dev-log.socket"
|
|
"systemd-journald.service"
|
|
"systemd-udevd-kernel.socket"
|
|
"systemd-udevd-control.socket"
|
|
"user.slice"
|
|
];
|
|
upstreamWants = [ "multi-user.target.wants" ];
|
|
}
|
|
);
|
|
|
|
# systemd.package = pkgs.systemdMinimal; # no analyze
|
|
systemd.defaultUnit = "microvm.target";
|
|
systemd.targets.microvm = {
|
|
description = "Minimal microVM system";
|
|
wants = [
|
|
"systemd-journald.socket"
|
|
"systemd-udevd.service"
|
|
"dbus.socket"
|
|
];
|
|
unitConfig.AllowIsolate = "yes";
|
|
};
|
|
systemd.services.generate-shutdown-ramfs.enable = lib.mkForce false;
|
|
systemd.services.systemd-remount-fs.enable = lib.mkForce false;
|
|
systemd.services.systemd-pstore.enable = lib.mkForce false;
|
|
systemd.services.lastlog2-import.enable = lib.mkForce false;
|
|
systemd.services.suid-sgid-wrappers.enable = lib.mkForce false;
|
|
systemd.services.systemd-udevd = {
|
|
# Redefine to remove the Before deps and get out of the critical chain
|
|
enable = true;
|
|
description = "Rule-based Manager for Device Events and Files";
|
|
unitConfig.DefaultDependencies = "no";
|
|
serviceConfig = {
|
|
CapabilityBoundingSet = "~CAP_SYS_TIME CAP_WAKE_ALARM";
|
|
Delegate = "";
|
|
DelegateSubgroup = "udev";
|
|
Type = "notify-reload";
|
|
OOMScoreAdjust = "-1000";
|
|
Sockets = "systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd-varlink.socket";
|
|
Restart = "always";
|
|
RestartSec = "0";
|
|
ExecStart = "${pkgs.systemd}/lib/systemd/systemd-udevd";
|
|
FileDescriptorStoreMax = "512";
|
|
FileDescriptorStorePreserve = "yes";
|
|
KillMode = "mixed";
|
|
TasksMax = "infinity";
|
|
PrivateMounts = "yes";
|
|
ProtectHostname = "yes";
|
|
MemoryDenyWriteExecute = "yes";
|
|
RestrictAddressFamilies = "AF_UNIX AF_NETLINK AF_INET AF_INET6";
|
|
RestrictRealtime = "yes";
|
|
RestrictSUIDSGID = "yes";
|
|
SystemCallFilter = [
|
|
"@system-service @module @raw-io bpf"
|
|
"~@clock"
|
|
];
|
|
SystemCallErrorNumber = "EPERM";
|
|
SystemCallArchitectures = "native";
|
|
LockPersonality = "yes";
|
|
IPAddressDeny = "any";
|
|
WatchdogSec = "3min";
|
|
};
|
|
};
|
|
|
|
# Configure user accounts
|
|
systemd.sysusers.enable = false;
|
|
services.userborn.enable = true;
|
|
services.userborn.static = true;
|
|
users.mutableUsers = false;
|
|
users.users.appvm = {
|
|
uid = 1337;
|
|
group = "appvm";
|
|
isNormalUser = false;
|
|
isSystemUser = true;
|
|
home = "/home/appvm";
|
|
description = "microVM User";
|
|
shell = pkgs.bash; # not nologin, despite being a "system" user
|
|
extraGroups = [
|
|
"wheel"
|
|
"video"
|
|
"input"
|
|
"systemd-journal"
|
|
];
|
|
};
|
|
users.groups.appvm.gid = 1337;
|
|
users.allowNoPasswordLogin = true;
|
|
|
|
# Configure services
|
|
|
|
systemd.settings.Manager.DefaultEnvironment = "XDG_RUNTIME_DIR=${runtimeDir}";
|
|
|
|
systemd.services.muvm-remote = {
|
|
enable = true;
|
|
description = "microVM Application runner";
|
|
onFailure = [ "exit.target" ];
|
|
onSuccess = [ "exit.target" ];
|
|
wants = [ "sockets.target" ];
|
|
after = [ "sockets.target" ];
|
|
wantedBy = [ "microvm.target" ];
|
|
serviceConfig = {
|
|
Type = "exec";
|
|
PassEnvironment = [
|
|
"MESA_LOADER_DRIVER_OVERRIDE"
|
|
"MUVM_REMOTE_CONFIG"
|
|
# "KRUN_CONFIG"
|
|
|
|
"TERM"
|
|
"XDG_SESSION_TYPE"
|
|
"SDL_VIDEODRIVER"
|
|
"QT_QPA_PLATFORM"
|
|
"_JAVA_AWT_WM_NONREPARENTING"
|
|
"ELECTRON_OZONE_PLATFORM_HINT"
|
|
"GTK_USE_PORTAL"
|
|
"QT_QPA_PLATFORMTHEME"
|
|
];
|
|
Environment = [
|
|
"WAYLAND_DISPLAY=wayland-1"
|
|
"DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock"
|
|
"PATH=/run/current-system/sw/bin"
|
|
];
|
|
User = "appvm";
|
|
Group = "appvm";
|
|
ExecStartPre = "+/run/current-system/sw/bin/chown appvm:appvm ${runtimeDir}";
|
|
ExecStart = "/opt/bin/muvm-remote";
|
|
ExecStopPost = ''+${pkgs.python3}/bin/python -c "import os,fcntl,struct;print(os.getenv('EXIT_STATUS', '1'));fcntl.ioctl(os.open('/', os.O_RDONLY), 0x7602, int(os.getenv('EXIT_STATUS', '1')))"'';
|
|
}
|
|
// useTTY;
|
|
};
|
|
|
|
systemd.services.muvm-configure-network = {
|
|
enable = true;
|
|
description = "microVM Network configuration";
|
|
wantedBy = [ "microvm.target" ];
|
|
serviceConfig.Type = "oneshot";
|
|
serviceConfig.ExecStart = "/opt/bin/muvm-configure-network";
|
|
};
|
|
|
|
systemd.sockets.muvm-pwbridge = {
|
|
enable = true;
|
|
description = "PipeWire cross-domain proxy socket";
|
|
wantedBy = [ "microvm.target" ];
|
|
partOf = [ "muvm-pwbridge.service" ];
|
|
listenStreams = [ "${runtimeDir}/pipewire-0" ];
|
|
socketConfig = {
|
|
SocketUser = "appvm";
|
|
SocketGroup = "appvm";
|
|
};
|
|
};
|
|
systemd.services.muvm-pwbridge = {
|
|
enable = true;
|
|
description = "PipeWire cross-domain proxy";
|
|
requires = [ "muvm-pwbridge.socket" ];
|
|
serviceConfig.Type = "exec";
|
|
serviceConfig.ExecStart = "/opt/bin/muvm-pwbridge";
|
|
};
|
|
|
|
systemd.sockets.wayland-proxy = {
|
|
enable = true;
|
|
description = "Wayland cross-domain proxy socket";
|
|
wantedBy = [ "microvm.target" ];
|
|
partOf = [ "wayland-proxy.service" ];
|
|
listenStreams = [ "${runtimeDir}/wayland-1" ];
|
|
socketConfig = {
|
|
SocketUser = "appvm";
|
|
SocketGroup = "appvm";
|
|
FileDescriptorName = "wayland";
|
|
};
|
|
};
|
|
systemd.services.wayland-proxy = {
|
|
enable = true;
|
|
description = "Wayland cross-domain proxy";
|
|
requires = [ "wayland-proxy.socket" ];
|
|
serviceConfig = {
|
|
ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128";
|
|
ExecStart = "${self.packages.${system}.wl-cross-domain-proxy}/bin/wl-cross-domain-proxy --listen-fd --filter-global wp_presentation";
|
|
User = "appvm";
|
|
Group = "appvm";
|
|
};
|
|
};
|
|
|
|
systemd.sockets.session-bus = {
|
|
enable = true;
|
|
description = "D-Bus session bus socket";
|
|
wantedBy = [ "microvm.target" ];
|
|
partOf = [ "session-bus.service" ];
|
|
listenStreams = [ "${runtimeDir}/dbus.sock" ];
|
|
socketConfig = {
|
|
SocketUser = "appvm";
|
|
SocketGroup = "appvm";
|
|
};
|
|
};
|
|
systemd.services.session-bus = {
|
|
enable = true;
|
|
description = "D-Bus session bus";
|
|
requires = [ "session-bus.socket" ];
|
|
serviceConfig = {
|
|
ExecStart = "${pkgs.dbus}/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --syslog-only"; # no systemd activation, we don't run a *session* systemd
|
|
User = "appvm";
|
|
Group = "appvm";
|
|
};
|
|
};
|
|
systemd.services.session-bus-bridge = {
|
|
enable = true;
|
|
description = "D-Bus session bus";
|
|
wantedBy = ["microvm.target"];
|
|
requires = ["session-bus.socket" "session-bus.service"];
|
|
after = ["session-bus.service"];
|
|
serviceConfig = {
|
|
Environment = ["DBUS_SESSION_BUS_ADDRESS=unix:path=${runtimeDir}/dbus.sock"];
|
|
ExecStartPre = "+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128";
|
|
ExecStart = "/opt/bin/muvm-dbusbridge";
|
|
User = "appvm";
|
|
Group = "appvm";
|
|
};
|
|
};
|
|
|
|
hardware.graphics.enable = true;
|
|
hardware.graphics.package = self.packages.${system}.mesa;
|
|
|
|
system.build.munix = pkgs.symlinkJoin {
|
|
name = "munix";
|
|
paths = [ self.packages.${system}.munix ];
|
|
buildInputs = [ pkgs.makeWrapper ];
|
|
postBuild = ''
|
|
wrapProgram $out/bin/munix \
|
|
--add-flags ${config.system.build.toplevel} \
|
|
--set MICROVM_DEFAULT_COMMAND ${lib.escapeShellArg config.virtualisation.munix.defaultCommand}
|
|
'';
|
|
};
|
|
};
|
|
}
|