diff options
Diffstat (limited to 'nixos/modules/virtualisation')
-rw-r--r-- | nixos/modules/virtualisation/incus.nix | 187 | ||||
-rw-r--r-- | nixos/modules/virtualisation/lxd.nix | 4 | ||||
-rw-r--r-- | nixos/modules/virtualisation/nixos-containers.nix | 5 | ||||
-rw-r--r-- | nixos/modules/virtualisation/qemu-vm.nix | 9 | ||||
-rw-r--r-- | nixos/modules/virtualisation/virtualbox-guest.nix | 120 |
5 files changed, 227 insertions, 98 deletions
diff --git a/nixos/modules/virtualisation/incus.nix b/nixos/modules/virtualisation/incus.nix index da7873c7bec86..08e8288fb2038 100644 --- a/nixos/modules/virtualisation/incus.nix +++ b/nixos/modules/virtualisation/incus.nix @@ -1,8 +1,98 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let cfg = config.virtualisation.incus; preseedFormat = pkgs.formats.yaml { }; + + serverBinPath = ''${pkgs.qemu_kvm}/libexec:${ + lib.makeBinPath ( + with pkgs; + [ + cfg.package + + acl + attr + bash + btrfs-progs + cdrkit + coreutils + criu + dnsmasq + e2fsprogs + findutils + getent + gnugrep + gnused + gnutar + gptfdisk + gzip + iproute2 + iptables + kmod + lvm2 + minio + nftables + qemu_kvm + qemu-utils + rsync + squashfsTools + systemd + thin-provisioning-tools + util-linux + virtiofsd + xz + + (writeShellScriptBin "apparmor_parser" '' + exec '${apparmor-parser}/bin/apparmor_parser' -I '${apparmor-profiles}/etc/apparmor.d' "$@" + '') + ] + ++ lib.optionals config.boot.zfs.enabled [ + config.boot.zfs.package + "${config.boot.zfs.package}/lib/udev" + ] + ++ lib.optionals config.virtualisation.vswitch.enable [ config.virtualisation.vswitch.package ] + ) + }''; + + # https://github.com/lxc/incus/blob/cff35a29ee3d7a2af1f937cbb6cf23776941854b/internal/server/instance/drivers/driver_qemu.go#L123 + OVMF2MB = pkgs.OVMF.override { + secureBoot = true; + fdSize2MB = true; + }; + ovmf-prefix = if pkgs.stdenv.hostPlatform.isAarch64 then "AAVMF" else "OVMF"; + ovmf = pkgs.linkFarm "incus-ovmf" [ + # 2MB must remain the default or existing VMs will fail to boot. New VMs will prefer 4MB + { + name = "OVMF_CODE.fd"; + path = "${OVMF2MB.fd}/FV/${ovmf-prefix}_CODE.fd"; + } + { + name = "OVMF_VARS.fd"; + path = "${OVMF2MB.fd}/FV/${ovmf-prefix}_VARS.fd"; + } + { + name = "OVMF_VARS.ms.fd"; + path = "${OVMF2MB.fd}/FV/${ovmf-prefix}_VARS.fd"; + } + + { + name = "OVMF_CODE.4MB.fd"; + path = "${pkgs.OVMFFull.fd}/FV/${ovmf-prefix}_CODE.fd"; + } + { + name = "OVMF_VARS.4MB.fd"; + path = "${pkgs.OVMFFull.fd}/FV/${ovmf-prefix}_VARS.fd"; + } + { + name = "OVMF_VARS.4MB.ms.fd"; + path = "${pkgs.OVMFFull.fd}/FV/${ovmf-prefix}_VARS.fd"; + } + ]; in { meta = { @@ -11,26 +101,31 @@ in options = { virtualisation.incus = { - enable = lib.mkEnableOption (lib.mdDoc '' + enable = lib.mkEnableOption '' incusd, a daemon that manages containers and virtual machines. Users in the "incus-admin" group can interact with the daemon (e.g. to start or stop containers) using the {command}`incus` command line tool, among others. - ''); + ''; - package = lib.mkPackageOption pkgs "incus" { }; + package = lib.mkPackageOption pkgs "incus-lts" { }; lxcPackage = lib.mkPackageOption pkgs "lxc" { }; + clientPackage = lib.mkOption { + type = lib.types.package; + default = cfg.package.client; + defaultText = lib.literalExpression "config.virtualisation.incus.package.client"; + description = "The incus client package to use. This package is added to PATH."; + }; + preseed = lib.mkOption { - type = lib.types.nullOr ( - lib.types.submodule { freeformType = preseedFormat.type; } - ); + type = lib.types.nullOr (lib.types.submodule { freeformType = preseedFormat.type; }); default = null; - description = lib.mdDoc '' + description = '' Configuration for Incus preseed, see <https://linuxcontainers.org/incus/docs/main/howto/initialize/#non-interactive-configuration> for supported values. @@ -80,18 +175,16 @@ in }; }; - socketActivation = lib.mkEnableOption ( - lib.mdDoc '' - socket-activation for starting incus.service. Enabling this option - will stop incus.service from starting automatically on boot. - '' - ); + socketActivation = lib.mkEnableOption ('' + socket-activation for starting incus.service. Enabling this option + will stop incus.service from starting automatically on boot. + ''); startTimeout = lib.mkOption { type = lib.types.ints.unsigned; default = 600; apply = toString; - description = lib.mdDoc '' + description = '' Time to wait (in seconds) for incusd to become ready to process requests. If incusd does not reply within the configured time, `incus.service` will be considered failed and systemd will attempt to restart it. @@ -99,9 +192,12 @@ in }; ui = { - enable = lib.mkEnableOption (lib.mdDoc "(experimental) Incus UI"); + enable = lib.mkEnableOption "(experimental) Incus UI"; - package = lib.mkPackageOption pkgs [ "incus" "ui" ] { }; + package = lib.mkPackageOption pkgs [ + "incus" + "ui" + ] { }; }; }; }; @@ -109,7 +205,12 @@ in config = lib.mkIf cfg.enable { assertions = [ { - assertion = !(config.networking.firewall.enable && !config.networking.nftables.enable && config.virtualisation.incus.enable); + assertion = + !( + config.networking.firewall.enable + && !config.networking.nftables.enable + && config.virtualisation.incus.enable + ); message = "Incus on NixOS is unsupported using iptables. Set `networking.nftables.enable = true;`"; } ]; @@ -137,7 +238,12 @@ in "vhost_vsock" ] ++ lib.optionals (!config.networking.nftables.enable) [ "iptable_mangle" ]; - environment.systemPackages = [ cfg.package ]; + environment.systemPackages = [ + cfg.clientPackage + + # gui console support + pkgs.spice-gtk + ]; # Note: the following options are also declared in virtualisation.lxc, but # the latter can't be simply enabled to reuse the formers, because it @@ -164,31 +270,24 @@ in "network-online.target" "lxcfs.service" "incus.socket" - ] - ++ lib.optional config.virtualisation.vswitch.enable "ovs-vswitchd.service"; + ] ++ lib.optionals config.virtualisation.vswitch.enable [ "ovs-vswitchd.service" ]; requires = [ "lxcfs.service" "incus.socket" - ] - ++ lib.optional config.virtualisation.vswitch.enable "ovs-vswitchd.service"; + ] ++ lib.optionals config.virtualisation.vswitch.enable [ "ovs-vswitchd.service" ]; - wants = [ - "network-online.target" - ]; + wants = [ "network-online.target" ]; - path = lib.optionals config.boot.zfs.enabled [ - config.boot.zfs.package - "${config.boot.zfs.package}/lib/udev" - ] - ++ lib.optional config.virtualisation.vswitch.enable config.virtualisation.vswitch.package; - - environment = lib.mkMerge [ { - # Override Path to the LXC template configuration directory - INCUS_LXC_TEMPLATE_CONFIG = "${pkgs.lxcfs}/share/lxc/config"; - } (lib.mkIf (cfg.ui.enable) { - "INCUS_UI" = cfg.ui.package; - }) ]; + environment = lib.mkMerge [ + { + INCUS_LXC_TEMPLATE_CONFIG = "${pkgs.lxcfs}/share/lxc/config"; + INCUS_OVMF_PATH = ovmf; + INCUS_USBIDS_PATH = "${pkgs.hwdata}/share/hwdata/usb.ids"; + PATH = lib.mkForce serverBinPath; + } + (lib.mkIf (cfg.ui.enable) { "INCUS_UI" = cfg.ui.package; }) + ]; serviceConfig = { ExecStart = "${cfg.package}/bin/incusd --group incus-admin"; @@ -222,15 +321,13 @@ in systemd.services.incus-preseed = lib.mkIf (cfg.preseed != null) { description = "Incus initialization with preseed file"; - wantedBy = ["incus.service"]; - after = ["incus.service"]; - bindsTo = ["incus.service"]; - partOf = ["incus.service"]; + wantedBy = [ "incus.service" ]; + after = [ "incus.service" ]; + bindsTo = [ "incus.service" ]; + partOf = [ "incus.service" ]; script = '' - ${cfg.package}/bin/incus admin init --preseed <${ - preseedFormat.generate "incus-preseed.yaml" cfg.preseed - } + ${cfg.package}/bin/incus admin init --preseed <${preseedFormat.generate "incus-preseed.yaml" cfg.preseed} ''; serviceConfig = { diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix index e0d61b1754949..aa692cfff9044 100644 --- a/nixos/modules/virtualisation/lxd.nix +++ b/nixos/modules/virtualisation/lxd.nix @@ -33,7 +33,7 @@ in { ''; }; - package = lib.mkPackageOption pkgs "lxd" { }; + package = lib.mkPackageOption pkgs "lxd-lts" { }; lxcPackage = lib.mkPackageOption pkgs "lxc" { extraDescription = '' @@ -139,7 +139,7 @@ in { ui = { enable = lib.mkEnableOption (lib.mdDoc "(experimental) LXD UI"); - package = lib.mkPackageOption pkgs [ "lxd-unwrapped" "ui" ] { }; + package = lib.mkPackageOption pkgs [ "lxd-ui" ] { }; }; }; }; diff --git a/nixos/modules/virtualisation/nixos-containers.nix b/nixos/modules/virtualisation/nixos-containers.nix index 5db3a336f85d5..bde1ff9eeb98d 100644 --- a/nixos/modules/virtualisation/nixos-containers.nix +++ b/nixos/modules/virtualisation/nixos-containers.nix @@ -834,7 +834,10 @@ in script = startScript containerConfig; postStart = postStartScript containerConfig; serviceConfig = serviceDirectives containerConfig; - unitConfig.RequiresMountsFor = lib.optional (!containerConfig.ephemeral) "${stateDirectory}/%i"; + unitConfig.RequiresMountsFor = lib.optional (!containerConfig.ephemeral) "${stateDirectory}/%i" + ++ builtins.map + (d: if d.hostPath != null then d.hostPath else d.mountPoint) + (builtins.attrValues cfg.bindMounts); environment.root = if containerConfig.ephemeral then "/run/nixos-containers/%i" else "${stateDirectory}/%i"; } // ( optionalAttrs containerConfig.autoStart diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index b5a8b08eee70d..a8e5db4f8a5ba 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -186,7 +186,7 @@ let NIX_EFI_VARS=$(readlink -f "''${NIX_EFI_VARS:-${config.system.name}-efi-vars.fd}") # VM needs writable EFI vars if ! test -e "$NIX_EFI_VARS"; then - ${if cfg.useBootLoader then + ${if cfg.efi.keepVariables then # We still need the EFI var from the make-disk-image derivation # because our "switch-to-configuration" process might # write into it and we want to keep this data. @@ -905,6 +905,13 @@ in Defaults to OVMF. ''; }; + + keepVariables = mkOption { + type = types.bool; + default = cfg.useBootLoader; + defaultText = literalExpression "cfg.useBootLoader"; + description = "Whether to keep EFI variable values from the generated system image"; + }; }; virtualisation.tpm = { diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix index 94f70c65436c1..c2606968d3bed 100644 --- a/nixos/modules/virtualisation/virtualbox-guest.nix +++ b/nixos/modules/virtualisation/virtualbox-guest.nix @@ -5,14 +5,32 @@ with lib; let - cfg = config.virtualisation.virtualbox.guest; kernel = config.boot.kernelPackages; -in + mkVirtualBoxUserService = serviceArgs: { + description = "VirtualBox Guest User Services ${serviceArgs}"; -{ + wantedBy = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; + + # The graphical session may not be ready when starting the service + # Hence, check if the DISPLAY env var is set, otherwise fail, wait and retry again + startLimitBurst = 20; + + unitConfig.ConditionVirtualization = "oracle"; + # Check if the display environment is ready, otherwise fail + preStart = "${pkgs.bash}/bin/bash -c \"if [ -z $DISPLAY ]; then exit 1; fi\""; + serviceConfig = { + ExecStart = "@${kernel.virtualboxGuestAdditions}/bin/VBoxClient --foreground ${serviceArgs}"; + # Wait after a failure, hoping that the display environment is ready after waiting + RestartSec = 2; + Restart = "always"; + }; + }; +in +{ ###### interface options.virtualisation.virtualbox.guest = { @@ -22,32 +40,45 @@ in description = lib.mdDoc "Whether to enable the VirtualBox service and other guest additions."; }; - x11 = mkOption { + clipboard = mkOption { default = true; type = types.bool; - description = lib.mdDoc "Whether to enable x11 graphics"; + description = lib.mdDoc "Whether to enable clipboard support."; + }; + + seamless = mkOption { + default = true; + type = types.bool; + description = lib.mdDoc "Whether to enable seamless mode. When activated windows from the guest appear next to the windows of the host."; + }; + + draganddrop = mkOption { + default = true; + type = types.bool; + description = lib.mdDoc "Whether to enable drag and drop support."; }; }; ###### implementation - config = mkIf cfg.enable (mkMerge [{ - assertions = [{ - assertion = pkgs.stdenv.hostPlatform.isx86; - message = "Virtualbox not currently supported on ${pkgs.stdenv.hostPlatform.system}"; - }]; + config = mkIf cfg.enable (mkMerge [ + { + assertions = [{ + assertion = pkgs.stdenv.hostPlatform.isx86; + message = "Virtualbox not currently supported on ${pkgs.stdenv.hostPlatform.system}"; + }]; - environment.systemPackages = [ kernel.virtualboxGuestAdditions ]; + environment.systemPackages = [ kernel.virtualboxGuestAdditions ]; - boot.extraModulePackages = [ kernel.virtualboxGuestAdditions ]; + boot.extraModulePackages = [ kernel.virtualboxGuestAdditions ]; - boot.supportedFilesystems = [ "vboxsf" ]; - boot.initrd.supportedFilesystems = [ "vboxsf" ]; + boot.supportedFilesystems = [ "vboxsf" ]; + boot.initrd.supportedFilesystems = [ "vboxsf" ]; - users.groups.vboxsf.gid = config.ids.gids.vboxsf; + users.groups.vboxsf.gid = config.ids.gids.vboxsf; - systemd.services.virtualbox = - { description = "VirtualBox Guest Services"; + systemd.services.virtualbox = { + description = "VirtualBox Guest Services"; wantedBy = [ "multi-user.target" ]; requires = [ "dev-vboxguest.device" ]; @@ -58,36 +89,27 @@ in serviceConfig.ExecStart = "@${kernel.virtualboxGuestAdditions}/bin/VBoxService VBoxService --foreground"; }; - services.udev.extraRules = - '' - # /dev/vboxuser is necessary for VBoxClient to work. Maybe we - # should restrict this to logged-in users. - KERNEL=="vboxuser", OWNER="root", GROUP="root", MODE="0666" - - # Allow systemd dependencies on vboxguest. - SUBSYSTEM=="misc", KERNEL=="vboxguest", TAG+="systemd" - ''; - } (mkIf cfg.x11 { - services.xserver.videoDrivers = [ "vmware" "virtualbox" "modesetting" ]; - - services.xserver.config = - '' - Section "InputDevice" - Identifier "VBoxMouse" - Driver "vboxmouse" - EndSection - ''; - - services.xserver.serverLayoutSection = - '' - InputDevice "VBoxMouse" - ''; - - services.xserver.displayManager.sessionCommands = - '' - PATH=${makeBinPath [ pkgs.gnugrep pkgs.which pkgs.xorg.xorgserver.out ]}:$PATH \ - ${kernel.virtualboxGuestAdditions}/bin/VBoxClient-all - ''; - })]); - + services.udev.extraRules = + '' + # /dev/vboxuser is necessary for VBoxClient to work. Maybe we + # should restrict this to logged-in users. + KERNEL=="vboxuser", OWNER="root", GROUP="root", MODE="0666" + + # Allow systemd dependencies on vboxguest. + SUBSYSTEM=="misc", KERNEL=="vboxguest", TAG+="systemd" + ''; + + systemd.user.services.virtualboxClientVmsvga = mkVirtualBoxUserService "--vmsvga-session"; + } + ( + mkIf cfg.clipboard { + systemd.user.services.virtualboxClientClipboard = mkVirtualBoxUserService "--clipboard"; + } + ) + ( + mkIf cfg.seamless { + systemd.user.services.virtualboxClientSeamless = mkVirtualBoxUserService "--seamless"; + } + ) + ]); } |