diff options
author | Alyssa Ross <hi@alyssa.is> | 2021-01-10 07:13:44 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2021-01-12 14:07:16 +0000 |
commit | e2698550456abba83c6dcd5d5e5a9990a0b96f8a (patch) | |
tree | 79a56f0df3fa55e470d84b4dff6059fbf487ec18 /nixpkgs/nixos/modules/virtualisation | |
parent | 1cdc42df888dc98c347e03bd942ed9825a55bcb3 (diff) | |
parent | 84d74ae9c9cbed73274b8e4e00be14688ffc93fe (diff) | |
download | nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.gz nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.bz2 nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.lz nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.xz nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.zst nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.zip |
Merge commit '84d74ae9c9cbed73274b8e4e00be14688ffc93fe'
Diffstat (limited to 'nixpkgs/nixos/modules/virtualisation')
14 files changed, 286 insertions, 267 deletions
diff --git a/nixpkgs/nixos/modules/virtualisation/azure-image.nix b/nixpkgs/nixos/modules/virtualisation/azure-image.nix index 21fd58e5c902..60fed3222ef3 100644 --- a/nixpkgs/nixos/modules/virtualisation/azure-image.nix +++ b/nixpkgs/nixos/modules/virtualisation/azure-image.nix @@ -6,7 +6,7 @@ let in { imports = [ ./azure-common.nix ]; - + options = { virtualisation.azureImage.diskSize = mkOption { type = with types; int; diff --git a/nixpkgs/nixos/modules/virtualisation/containers.nix b/nixpkgs/nixos/modules/virtualisation/containers.nix index 7d184575640b..997edf77ba99 100644 --- a/nixpkgs/nixos/modules/virtualisation/containers.nix +++ b/nixpkgs/nixos/modules/virtualisation/containers.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, pkgs, utils, ... }: let cfg = config.virtualisation.containers; @@ -13,16 +13,21 @@ let json2toml "$valuePath" "$out" ''; - # Copy configuration files to avoid having the entire sources in the system closure - copyFile = filePath: pkgs.runCommandNoCC (builtins.unsafeDiscardStringContext (builtins.baseNameOf filePath)) {} '' - cp ${filePath} $out - ''; in { meta = { maintainers = [] ++ lib.teams.podman.members; }; + + imports = [ + ( + lib.mkRemovedOptionModule + [ "virtualisation" "containers" "users" ] + "All users with `isNormalUser = true` set now get appropriate subuid/subgid mappings." + ) + ]; + options.virtualisation.containers = { enable = @@ -34,6 +39,31 @@ in ''; }; + ociSeccompBpfHook.enable = mkOption { + type = types.bool; + default = false; + description = "Enable the OCI seccomp BPF hook"; + }; + + containersConf = mkOption { + default = {}; + description = "containers.conf configuration"; + type = types.submodule { + options = { + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration that should be put in the containers.conf + configuration file + ''; + + }; + }; + }; + }; + registries = { search = mkOption { type = types.listOf types.str; @@ -80,46 +110,29 @@ in ''; }; - users = mkOption { - default = []; - type = types.listOf types.str; - description = '' - List of users to set up subuid/subgid mappings for. - This is a requirement for running rootless containers. - ''; - }; - }; config = lib.mkIf cfg.enable { + environment.etc."containers/containers.conf".text = '' + [network] + cni_plugin_dirs = ["${pkgs.cni-plugins}/bin/"] + + ${lib.optionalString (cfg.ociSeccompBpfHook.enable == true) '' + [engine] + hooks_dir = [ + "${config.boot.kernelPackages.oci-seccomp-bpf-hook}", + ] + ''} + '' + cfg.containersConf.extraConfig; + environment.etc."containers/registries.conf".source = toTOML "registries.conf" { registries = lib.mapAttrs (n: v: { registries = v; }) cfg.registries; }; - users.extraUsers = builtins.listToAttrs ( - ( - builtins.foldl' ( - acc: user: { - values = acc.values ++ [ - { - name = user; - value = { - subUidRanges = [ { startUid = acc.offset; count = 65536; } ]; - subGidRanges = [ { startGid = acc.offset; count = 65536; } ]; - }; - } - ]; - offset = acc.offset + 65536; - } - ) - { values = []; offset = 100000; } (lib.unique cfg.users) - ).values - ); - environment.etc."containers/policy.json".source = if cfg.policy != {} then pkgs.writeText "policy.json" (builtins.toJSON cfg.policy) - else copyFile "${pkgs.skopeo.src}/default-policy.json"; + else utils.copyFile "${pkgs.skopeo.src}/default-policy.json"; }; } diff --git a/nixpkgs/nixos/modules/virtualisation/cri-o.nix b/nixpkgs/nixos/modules/virtualisation/cri-o.nix index f267c97b1788..aa416e7990a8 100644 --- a/nixpkgs/nixos/modules/virtualisation/cri-o.nix +++ b/nixpkgs/nixos/modules/virtualisation/cri-o.nix @@ -1,16 +1,11 @@ -{ config, lib, pkgs, ... }: +{ config, lib, pkgs, utils, ... }: with lib; - let cfg = config.virtualisation.cri-o; crioPackage = (pkgs.cri-o.override { inherit (cfg) extraPackages; }); - # Copy configuration files to avoid having the entire sources in the system closure - copyFile = filePath: pkgs.runCommandNoCC (builtins.unsafeDiscardStringContext (builtins.baseNameOf filePath)) {} '' - cp ${filePath} $out - ''; in { imports = [ @@ -78,14 +73,21 @@ in The final CRI-O package (including extra packages). ''; }; + + networkDir = mkOption { + type = types.nullOr types.path; + default = null; + description = "Override the network_dir option."; + internal = true; + }; }; config = mkIf cfg.enable { environment.systemPackages = [ cfg.package pkgs.cri-tools ]; - environment.etc."crictl.yaml".source = copyFile "${pkgs.cri-o-unwrapped.src}/crictl.yaml"; + environment.etc."crictl.yaml".source = utils.copyFile "${pkgs.cri-o-unwrapped.src}/crictl.yaml"; - environment.etc."crio/crio.conf".text = '' + environment.etc."crio/crio.conf.d/00-default.conf".text = '' [crio] storage_driver = "${cfg.storageDriver}" @@ -95,11 +97,13 @@ in [crio.network] plugin_dirs = ["${pkgs.cni-plugins}/bin/"] + ${optionalString (cfg.networkDir != null) ''network_dir = "${cfg.networkDir}"''} [crio.runtime] cgroup_manager = "systemd" log_level = "${cfg.logLevel}" - manage_ns_lifecycle = true + pinns_path = "${cfg.package}/bin/pinns" + hooks_dir = [] ${optionalString (cfg.runtime != null) '' default_runtime = "${cfg.runtime}" @@ -108,7 +112,8 @@ in ''} ''; - environment.etc."cni/net.d/10-crio-bridge.conf".source = copyFile "${pkgs.cri-o-unwrapped.src}/contrib/cni/10-crio-bridge.conf"; + environment.etc."cni/net.d/10-crio-bridge.conf".source = utils.copyFile "${pkgs.cri-o-unwrapped.src}/contrib/cni/10-crio-bridge.conf"; + environment.etc."cni/net.d/99-loopback.conf".source = utils.copyFile "${pkgs.cri-o-unwrapped.src}/contrib/cni/99-loopback.conf"; # Enable common /etc/containers configuration virtualisation.containers.enable = true; diff --git a/nixpkgs/nixos/modules/virtualisation/docker-preloader.nix b/nixpkgs/nixos/modules/virtualisation/docker-preloader.nix deleted file mode 100644 index 6ab83058dee1..000000000000 --- a/nixpkgs/nixos/modules/virtualisation/docker-preloader.nix +++ /dev/null @@ -1,134 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; -with builtins; - -let - cfg = config.virtualisation; - - sanitizeImageName = image: replaceStrings ["/"] ["-"] image.imageName; - hash = drv: head (split "-" (baseNameOf drv.outPath)); - # The label of an ext4 FS is limited to 16 bytes - labelFromImage = image: substring 0 16 (hash image); - - # The Docker image is loaded and some files from /var/lib/docker/ - # are written into a qcow image. - preload = image: pkgs.vmTools.runInLinuxVM ( - pkgs.runCommand "docker-preload-image-${sanitizeImageName image}" { - buildInputs = with pkgs; [ docker e2fsprogs utillinux curl kmod ]; - preVM = pkgs.vmTools.createEmptyImage { - size = cfg.dockerPreloader.qcowSize; - fullName = "docker-deamon-image.qcow2"; - }; - } - '' - mkfs.ext4 /dev/vda - e2label /dev/vda ${labelFromImage image} - mkdir -p /var/lib/docker - mount -t ext4 /dev/vda /var/lib/docker - - modprobe overlay - - # from https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount - mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup - cd /sys/fs/cgroup - for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do - mkdir -p $sys - if ! mountpoint -q $sys; then - if ! mount -n -t cgroup -o $sys cgroup $sys; then - rmdir $sys || true - fi - fi - done - - dockerd -H tcp://127.0.0.1:5555 -H unix:///var/run/docker.sock & - - until $(curl --output /dev/null --silent --connect-timeout 2 http://127.0.0.1:5555); do - printf '.' - sleep 1 - done - - docker load -i ${image} - - kill %1 - find /var/lib/docker/ -maxdepth 1 -mindepth 1 -not -name "image" -not -name "overlay2" | xargs rm -rf - ''); - - preloadedImages = map preload cfg.dockerPreloader.images; - -in - -{ - options.virtualisation.dockerPreloader = { - images = mkOption { - default = [ ]; - type = types.listOf types.package; - description = - '' - A list of Docker images to preload (in the /var/lib/docker directory). - ''; - }; - qcowSize = mkOption { - default = 1024; - type = types.int; - description = - '' - The size (MB) of qcow files. - ''; - }; - }; - - config = mkIf (cfg.dockerPreloader.images != []) { - assertions = [{ - # If docker.storageDriver is null, Docker choose the storage - # driver. So, in this case, we cannot be sure overlay2 is used. - assertion = cfg.docker.storageDriver == "overlay2" - || cfg.docker.storageDriver == "overlay" - || cfg.docker.storageDriver == null; - message = "The Docker image Preloader only works with overlay2 storage driver!"; - }]; - - virtualisation.qemu.options = - map (path: "-drive if=virtio,file=${path}/disk-image.qcow2,readonly,media=cdrom,format=qcow2") - preloadedImages; - - - # All attached QCOW files are mounted and their contents are linked - # to /var/lib/docker/ in order to make image available. - systemd.services.docker-preloader = { - description = "Preloaded Docker images"; - wantedBy = ["docker.service"]; - after = ["network.target"]; - path = with pkgs; [ mount rsync jq ]; - script = '' - mkdir -p /var/lib/docker/overlay2/l /var/lib/docker/image/overlay2 - echo '{}' > /tmp/repositories.json - - for i in ${concatStringsSep " " (map labelFromImage cfg.dockerPreloader.images)}; do - mkdir -p /mnt/docker-images/$i - - # The ext4 label is limited to 16 bytes - mount /dev/disk/by-label/$(echo $i | cut -c1-16) -o ro,noload /mnt/docker-images/$i - - find /mnt/docker-images/$i/overlay2/ -maxdepth 1 -mindepth 1 -not -name l\ - -exec ln -s '{}' /var/lib/docker/overlay2/ \; - cp -P /mnt/docker-images/$i/overlay2/l/* /var/lib/docker/overlay2/l/ - - rsync -a /mnt/docker-images/$i/image/ /var/lib/docker/image/ - - # Accumulate image definitions - cp /tmp/repositories.json /tmp/repositories.json.tmp - jq -s '.[0] * .[1]' \ - /tmp/repositories.json.tmp \ - /mnt/docker-images/$i/image/overlay2/repositories.json \ - > /tmp/repositories.json - done - - mv /tmp/repositories.json /var/lib/docker/image/overlay2/repositories.json - ''; - serviceConfig = { - Type = "oneshot"; - }; - }; - }; -} diff --git a/nixpkgs/nixos/modules/virtualisation/docker.nix b/nixpkgs/nixos/modules/virtualisation/docker.nix index 7d196a46276a..d87ada35a0ae 100644 --- a/nixpkgs/nixos/modules/virtualisation/docker.nix +++ b/nixpkgs/nixos/modules/virtualisation/docker.nix @@ -149,6 +149,7 @@ in ###### implementation config = mkIf cfg.enable (mkMerge [{ + boot.kernelModules = [ "bridge" "veth" ]; environment.systemPackages = [ cfg.package ] ++ optional cfg.enableNvidia pkgs.nvidia-docker; users.groups.docker.gid = config.ids.gids.docker; diff --git a/nixpkgs/nixos/modules/virtualisation/libvirtd.nix b/nixpkgs/nixos/modules/virtualisation/libvirtd.nix index 43b5fcfa8fae..1d6a9457dde4 100644 --- a/nixpkgs/nixos/modules/virtualisation/libvirtd.nix +++ b/nixpkgs/nixos/modules/virtualisation/libvirtd.nix @@ -265,8 +265,8 @@ in { restartIfChanged = false; }; - systemd.sockets.libvirtd .wantedBy = [ "sockets.target" ]; - systemd.sockets.libvirtd-tcp.wantedBy = [ "sockets.target" ]; + # https://libvirt.org/daemons.html#monolithic-systemd-integration + systemd.sockets.libvirtd.wantedBy = [ "sockets.target" ]; security.polkit.extraConfig = '' polkit.addRule(function(action, subject) { diff --git a/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix b/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix index b0fa03917c82..8fbb4efd2019 100644 --- a/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix +++ b/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix @@ -627,7 +627,7 @@ in }; bindMounts = mkOption { - type = with types; loaOf (submodule bindMountOpts); + type = with types; attrsOf (submodule bindMountOpts); default = {}; example = literalExample '' { "/home" = { hostPath = "/home/alice"; diff --git a/nixpkgs/nixos/modules/virtualisation/parallels-guest.nix b/nixpkgs/nixos/modules/virtualisation/parallels-guest.nix index 828419fb4b9d..55605b388b7c 100644 --- a/nixpkgs/nixos/modules/virtualisation/parallels-guest.nix +++ b/nixpkgs/nixos/modules/virtualisation/parallels-guest.nix @@ -32,7 +32,7 @@ in }; package = mkOption { - type = types.package; + type = types.nullOr types.package; default = config.boot.kernelPackages.prl-tools; defaultText = "config.boot.kernelPackages.prl-tools"; example = literalExample "config.boot.kernelPackages.prl-tools"; diff --git a/nixpkgs/nixos/modules/virtualisation/podman.nix b/nixpkgs/nixos/modules/virtualisation/podman.nix index 652850bf5006..f554aeffb451 100644 --- a/nixpkgs/nixos/modules/virtualisation/podman.nix +++ b/nixpkgs/nixos/modules/virtualisation/podman.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, lib, pkgs, utils, ... }: let cfg = config.virtualisation.podman; @@ -21,13 +21,12 @@ let done ''; - # Copy configuration files to avoid having the entire sources in the system closure - copyFile = filePath: pkgs.runCommandNoCC (builtins.unsafeDiscardStringContext (builtins.baseNameOf filePath)) {} '' - cp ${filePath} $out - ''; - in { + imports = [ + (lib.mkRenamedOptionModule [ "virtualisation" "podman" "libpod" ] [ "virtualisation" "containers" "containersConf" ]) + ]; + meta = { maintainers = lib.teams.podman.members; }; @@ -67,25 +66,6 @@ in ''; }; - libpod = mkOption { - default = {}; - description = "Libpod configuration"; - type = types.submodule { - options = { - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Extra configuration that should be put in the libpod.conf - configuration file - ''; - - }; - }; - }; - }; - package = lib.mkOption { type = types.package; default = podmanPackage; @@ -103,12 +83,7 @@ in environment.systemPackages = [ cfg.package ] ++ lib.optional cfg.dockerCompat dockerCompat; - environment.etc."containers/libpod.conf".text = '' - cni_plugin_dir = ["${pkgs.cni-plugins}/bin/"] - - '' + cfg.libpod.extraConfig; - - environment.etc."cni/net.d/87-podman-bridge.conflist".source = copyFile "${pkgs.podman-unwrapped.src}/cni/87-podman-bridge.conflist"; + environment.etc."cni/net.d/87-podman-bridge.conflist".source = utils.copyFile "${pkgs.podman-unwrapped.src}/cni/87-podman-bridge.conflist"; # Enable common /etc/containers configuration virtualisation.containers.enable = true; diff --git a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix index be06d6feb11f..42e43f5ee023 100644 --- a/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixpkgs/nixos/modules/virtualisation/qemu-vm.nix @@ -16,11 +16,6 @@ let qemu = config.system.build.qemu or pkgs.qemu_test; - vmName = - if config.networking.hostName == "" - then "noname" - else config.networking.hostName; - cfg = config.virtualisation; consoles = lib.concatMapStringsSep " " (c: "console=${c}") cfg.qemu.consoles; @@ -46,6 +41,13 @@ let description = "Extra options passed to device flag."; }; + name = mkOption { + type = types.nullOr types.str; + default = null; + description = + "A name for the drive. Must be unique in the drives list. Not passed to qemu."; + }; + }; }; @@ -74,6 +76,32 @@ let drivesCmdLine = drives: concatStringsSep " " (imap1 driveCmdline drives); + + # Creates a device name from a 1-based a numerical index, e.g. + # * `driveDeviceName 1` -> `/dev/vda` + # * `driveDeviceName 2` -> `/dev/vdb` + driveDeviceName = idx: + let letter = elemAt lowerChars (idx - 1); + in if cfg.qemu.diskInterface == "scsi" then + "/dev/sd${letter}" + else + "/dev/vd${letter}"; + + lookupDriveDeviceName = driveName: driveList: + (findSingle (drive: drive.name == driveName) + (throw "Drive ${driveName} not found") + (throw "Multiple drives named ${driveName}") driveList).device; + + addDeviceNames = + imap1 (idx: drive: drive // { device = driveDeviceName idx; }); + + efiPrefix = + if (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then "${pkgs.OVMF.fd}/FV/OVMF" + else if pkgs.stdenv.isAarch64 then "${pkgs.OVMF.fd}/FV/AAVMF" + else throw "No EFI firmware available for platform"; + efiFirmware = "${efiPrefix}_CODE.fd"; + efiVarsDefault = "${efiPrefix}_VARS.fd"; + # Shell script to start the VM. startVM = '' @@ -99,10 +127,14 @@ let # A writable boot disk can be booted from automatically. ${qemu}/bin/qemu-img create -f qcow2 -b ${bootDisk}/disk.img $TMPDIR/disk.img || exit 1 + NIX_EFI_VARS=$(readlink -f ''${NIX_EFI_VARS:-${cfg.efiVars}}) + ${if cfg.useEFIBoot then '' - # VM needs a writable flash BIOS. - cp ${bootDisk}/bios.bin $TMPDIR || exit 1 - chmod 0644 $TMPDIR/bios.bin || exit 1 + # VM needs writable EFI vars + if ! test -e "$NIX_EFI_VARS"; then + cp ${bootDisk}/efi-vars.fd "$NIX_EFI_VARS" || exit 1 + chmod 0644 "$NIX_EFI_VARS" || exit 1 + fi '' else '' ''} '' else '' @@ -119,7 +151,7 @@ let # Start QEMU. exec ${qemuBinary qemu} \ - -name ${vmName} \ + -name ${config.system.name} \ -m ${toString config.virtualisation.memorySize} \ -smp ${toString config.virtualisation.cores} \ -device virtio-rng-pci \ @@ -139,6 +171,8 @@ let # Generate a hard disk image containing a /boot partition and GRUB # in the MBR. Used when the `useBootLoader' option is set. + # Uses `runInLinuxVM` to create the image in a throwaway VM. + # See note [Disk layout with `useBootLoader`]. # FIXME: use nixos/lib/make-disk-image.nix. bootDisk = pkgs.vmTools.runInLinuxVM ( @@ -147,21 +181,22 @@ let '' mkdir $out diskImage=$out/disk.img - bootFlash=$out/bios.bin - ${qemu}/bin/qemu-img create -f qcow2 $diskImage "40M" + ${qemu}/bin/qemu-img create -f qcow2 $diskImage "60M" ${if cfg.useEFIBoot then '' - cp ${pkgs.OVMF-CSM.fd}/FV/OVMF.fd $bootFlash - chmod 0644 $bootFlash + efiVars=$out/efi-vars.fd + cp ${efiVarsDefault} $efiVars + chmod 0644 $efiVars '' else '' ''} ''; buildInputs = [ pkgs.utillinux ]; - QEMU_OPTS = if cfg.useEFIBoot - then "-pflash $out/bios.bin -nographic -serial pty" - else "-nographic -serial pty"; + QEMU_OPTS = "-nographic -serial stdio -monitor none" + + lib.optionalString cfg.useEFIBoot ( + " -drive if=pflash,format=raw,unit=0,readonly=on,file=${efiFirmware}" + + " -drive if=pflash,format=raw,unit=1,file=$efiVars"); } '' - # Create a /boot EFI partition with 40M and arbitrary but fixed GUIDs for reproducibility + # Create a /boot EFI partition with 60M and arbitrary but fixed GUIDs for reproducibility ${pkgs.gptfdisk}/bin/sgdisk \ --set-alignment=1 --new=1:34:2047 --change-name=1:BIOSBootPartition --typecode=1:ef02 \ --set-alignment=512 --largest-new=2 --change-name=2:EFISystem --typecode=2:ef00 \ @@ -172,6 +207,19 @@ let --partition-guid=2:970C694F-AFD0-4B99-B750-CDB7A329AB6F \ --hybrid 2 \ --recompute-chs /dev/vda + + ${optionalString (config.boot.loader.grub.device != "/dev/vda") + # In this throwaway VM, we only have the /dev/vda disk, but the + # actual VM described by `config` (used by `switch-to-configuration` + # below) may set `boot.loader.grub.device` to a different device + # that's nonexistent in the throwaway VM. + # Create a symlink for that device, so that the `grub-install` + # by `switch-to-configuration` will hit /dev/vda anyway. + '' + ln -s /dev/vda ${config.boot.loader.grub.device} + '' + } + ${pkgs.dosfstools}/bin/mkfs.fat -F16 /dev/vda2 export MTOOLS_SKIP_CHECK=1 ${pkgs.mtools}/bin/mlabel -i /dev/vda2 ::boot @@ -185,6 +233,10 @@ let mkdir /boot mount /dev/vda2 /boot + ${optionalString config.boot.loader.efi.canTouchEfiVariables '' + mount -t efivarfs efivarfs /sys/firmware/efi/efivars + ''} + # This is needed for GRUB 0.97, which doesn't know about virtio devices. mkdir /boot/grub echo '(hd0) /dev/vda' > /boot/grub/device.map @@ -212,7 +264,6 @@ in { imports = [ ../profiles/qemu-guest.nix - ./docker-preloader.nix ]; options = { @@ -237,7 +288,7 @@ in virtualisation.diskImage = mkOption { - default = "./${vmName}.qcow2"; + default = "./${config.system.name}.qcow2"; description = '' Path to the disk image containing the root filesystem. @@ -396,6 +447,7 @@ in mkOption { type = types.listOf (types.submodule driveOpts); description = "Drives passed to qemu."; + apply = addDeviceNames; }; diskInterface = @@ -441,6 +493,16 @@ in ''; }; + virtualisation.efiVars = + mkOption { + default = "./${config.system.name}-efi-vars.fd"; + description = + '' + Path to nvram image containing UEFI variables. The will be created + on startup if it does not exist. + ''; + }; + virtualisation.bios = mkOption { default = null; @@ -457,7 +519,27 @@ in config = { - boot.loader.grub.device = mkVMOverride cfg.bootDevice; + # Note [Disk layout with `useBootLoader`] + # + # If `useBootLoader = true`, we configure 2 drives: + # `/dev/?da` for the root disk, and `/dev/?db` for the boot disk + # which has the `/boot` partition and the boot loader. + # Concretely: + # + # * The second drive's image `disk.img` is created in `bootDisk = ...` + # using a throwaway VM. Note that there the disk is always `/dev/vda`, + # even though in the final VM it will be at `/dev/*b`. + # * The disks are attached in `virtualisation.qemu.drives`. + # Their order makes them appear as devices `a`, `b`, etc. + # * `fileSystems."/boot"` is adjusted to be on device `b`. + + # If `useBootLoader`, GRUB goes to the second disk, see + # note [Disk layout with `useBootLoader`]. + boot.loader.grub.device = mkVMOverride ( + if cfg.useBootLoader + then driveDeviceName 2 # second disk + else cfg.bootDevice + ); boot.initrd.extraUtilsCommands = '' @@ -512,8 +594,7 @@ in optional cfg.writableStore "overlay" ++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"; - virtualisation.bootDevice = - mkDefault (if cfg.qemu.diskInterface == "scsi" then "/dev/sda" else "/dev/vda"); + virtualisation.bootDevice = mkDefault (driveDeviceName 1); virtualisation.pathsInNixDB = [ config.system.build.toplevel ]; @@ -531,7 +612,8 @@ in ''-append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.toplevel}/init regInfo=${regInfo}/registration ${consoles} $QEMU_KERNEL_PARAMS"'' ]) (mkIf cfg.useEFIBoot [ - "-pflash $TMPDIR/bios.bin" + "-drive if=pflash,format=raw,unit=0,readonly,file=${efiFirmware}" + "-drive if=pflash,format=raw,unit=1,file=$NIX_EFI_VARS" ]) (mkIf (cfg.bios != null) [ "-bios ${cfg.bios}/bios.bin" @@ -542,25 +624,22 @@ in ]; virtualisation.qemu.drives = mkMerge [ + [{ + name = "root"; + file = "$NIX_DISK_IMAGE"; + driveExtraOpts.cache = "writeback"; + driveExtraOpts.werror = "report"; + }] (mkIf cfg.useBootLoader [ + # The order of this list determines the device names, see + # note [Disk layout with `useBootLoader`]. { - file = "$NIX_DISK_IMAGE"; - driveExtraOpts.cache = "writeback"; - driveExtraOpts.werror = "report"; - } - { + name = "boot"; file = "$TMPDIR/disk.img"; driveExtraOpts.media = "disk"; deviceExtraOpts.bootindex = "1"; } ]) - (mkIf (!cfg.useBootLoader) [ - { - file = "$NIX_DISK_IMAGE"; - driveExtraOpts.cache = "writeback"; - driveExtraOpts.werror = "report"; - } - ]) (imap0 (idx: _: { file = "$(pwd)/empty${toString idx}.qcow2"; driveExtraOpts.werror = "report"; @@ -608,9 +687,9 @@ in }; } // optionalAttrs cfg.useBootLoader { "/boot" = - { device = "/dev/vdb2"; + # see note [Disk layout with `useBootLoader`] + { device = "${lookupDriveDeviceName "boot" cfg.qemu.drives}2"; # 2 for e.g. `vdb2`, as created in `bootDisk` fsType = "vfat"; - options = [ "ro" ]; noCheck = true; # fsck fails on a r/o filesystem }; }); @@ -627,7 +706,7 @@ in '' mkdir -p $out/bin ln -s ${config.system.build.toplevel} $out/system - ln -s ${pkgs.writeScript "run-nixos-vm" startVM} $out/bin/run-${vmName}-vm + ln -s ${pkgs.writeScript "run-nixos-vm" startVM} $out/bin/run-${config.system.name}-vm ''; # When building a regular system configuration, override whatever diff --git a/nixpkgs/nixos/modules/virtualisation/railcar.nix b/nixpkgs/nixos/modules/virtualisation/railcar.nix index 12da1c75fc38..10464f628984 100644 --- a/nixpkgs/nixos/modules/virtualisation/railcar.nix +++ b/nixpkgs/nixos/modules/virtualisation/railcar.nix @@ -29,9 +29,9 @@ let default = "none"; description = '' The type of the filesystem to be mounted. - Linux: filesystem types supported by the kernel as listed in - `/proc/filesystems` (e.g., "minix", "ext2", "ext3", "jfs", "xfs", - "reiserfs", "msdos", "proc", "nfs", "iso9660"). For bind mounts + Linux: filesystem types supported by the kernel as listed in + `/proc/filesystems` (e.g., "minix", "ext2", "ext3", "jfs", "xfs", + "reiserfs", "msdos", "proc", "nfs", "iso9660"). For bind mounts (when options include either bind or rbind), the type is a dummy, often "none" (not listed in /proc/filesystems). ''; @@ -41,13 +41,13 @@ let description = "Source for the in-container mount"; }; options = mkOption { - type = loaOf (str); + type = attrsOf (str); default = [ "bind" ]; description = '' Mount options of the filesystem to be used. - - Support optoions are listed in the mount(8) man page. Note that - both filesystem-independent and filesystem-specific options + + Support options are listed in the mount(8) man page. Note that + both filesystem-independent and filesystem-specific options are listed. ''; }; @@ -61,7 +61,7 @@ in containers = mkOption { default = {}; description = "Declarative container configuration"; - type = with types; loaOf (submodule ({ name, config, ... }: { + type = with types; attrsOf (submodule ({ name, config, ... }: { options = { cmd = mkOption { type = types.lines; diff --git a/nixpkgs/nixos/modules/virtualisation/spice-usb-redirection.nix b/nixpkgs/nixos/modules/virtualisation/spice-usb-redirection.nix new file mode 100644 index 000000000000..4168cebe79b1 --- /dev/null +++ b/nixpkgs/nixos/modules/virtualisation/spice-usb-redirection.nix @@ -0,0 +1,24 @@ +{ config, pkgs, lib, ... }: +{ + options.virtualisation.spiceUSBRedirection.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Install the SPICE USB redirection helper with setuid + privileges. This allows unprivileged users to pass USB devices + connected to this machine to libvirt VMs, both local and + remote. Note that this allows users arbitrary access to USB + devices. + ''; + }; + + config = lib.mkIf config.virtualisation.spiceUSBRedirection.enable { + environment.systemPackages = [ pkgs.spice-gtk ]; # For polkit actions + security.wrappers.spice-client-glib-usb-acl-helper ={ + source = "${pkgs.spice-gtk}/bin/spice-client-glib-usb-acl-helper"; + capabilities = "cap_fowner+ep"; + }; + }; + + meta.maintainers = [ lib.maintainers.lheckemann ]; +} diff --git a/nixpkgs/nixos/modules/virtualisation/virtualbox-guest.nix b/nixpkgs/nixos/modules/virtualisation/virtualbox-guest.nix index 834b994e92d2..486951983d30 100644 --- a/nixpkgs/nixos/modules/virtualisation/virtualbox-guest.nix +++ b/nixpkgs/nixos/modules/virtualisation/virtualbox-guest.nix @@ -68,7 +68,7 @@ in SUBSYSTEM=="misc", KERNEL=="vboxguest", TAG+="systemd" ''; } (mkIf cfg.x11 { - services.xserver.videoDrivers = mkOverride 50 [ "virtualbox" "modesetting" ]; + services.xserver.videoDrivers = mkOverride 50 [ "vmware" "virtualbox" "modesetting" ]; services.xserver.config = '' diff --git a/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix b/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix index 788b4d9d9761..fa580e8b42d6 100644 --- a/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix @@ -58,6 +58,35 @@ in { Run <literal>VBoxManage modifyvm --help</literal> to see more options. ''; }; + extraDisk = mkOption { + description = '' + Optional extra disk/hdd configuration. + The disk will be an 'ext4' partition on a separate VMDK file. + ''; + default = null; + example = { + label = "storage"; + mountPoint = "/home/demo/storage"; + size = 100 * 1024; + }; + type = types.nullOr (types.submodule { + options = { + size = mkOption { + type = types.int; + description = "Size in MiB"; + }; + label = mkOption { + type = types.str; + default = "vm-extra-storage"; + description = "Label for the disk partition"; + }; + mountPoint = mkOption { + type = types.str; + description = "Path where to mount this disk."; + }; + }; + }); + }; }; }; @@ -72,6 +101,7 @@ in { audiocontroller = "ac97"; audio = "alsa"; audioout = "on"; + graphicscontroller = "vmsvga"; rtcuseutc = "on"; usb = "on"; usbehci = "on"; @@ -95,6 +125,20 @@ in { echo "creating VirtualBox pass-through disk wrapper (no copying involved)..." VBoxManage internalcommands createrawvmdk -filename disk.vmdk -rawdisk $diskImage + ${optionalString (cfg.extraDisk != null) '' + echo "creating extra disk: data-disk.raw" + dataDiskImage=data-disk.raw + truncate -s ${toString cfg.extraDisk.size}M $dataDiskImage + + parted --script $dataDiskImage -- \ + mklabel msdos \ + mkpart primary ext4 1MiB -1 + eval $(partx $dataDiskImage -o START,SECTORS --nr 1 --pairs) + mkfs.ext4 -F -L ${cfg.extraDisk.label} $dataDiskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K + echo "creating extra disk: data-disk.vmdk" + VBoxManage internalcommands createrawvmdk -filename data-disk.vmdk -rawdisk $dataDiskImage + ''} + echo "creating VirtualBox VM..." vmName="${cfg.vmName}"; VBoxManage createvm --name "$vmName" --register \ @@ -105,6 +149,10 @@ in { VBoxManage storagectl "$vmName" --name SATA --add sata --portcount 4 --bootable on --hostiocache on VBoxManage storageattach "$vmName" --storagectl SATA --port 0 --device 0 --type hdd \ --medium disk.vmdk + ${optionalString (cfg.extraDisk != null) '' + VBoxManage storageattach "$vmName" --storagectl SATA --port 1 --device 0 --type hdd \ + --medium data-disk.vmdk + ''} echo "exporting VirtualBox VM..." mkdir -p $out @@ -118,11 +166,19 @@ in { ''; }; - fileSystems."/" = { - device = "/dev/disk/by-label/nixos"; - autoResize = true; - fsType = "ext4"; - }; + fileSystems = { + "/" = { + device = "/dev/disk/by-label/nixos"; + autoResize = true; + fsType = "ext4"; + }; + } // (lib.optionalAttrs (cfg.extraDisk != null) { + ${cfg.extraDisk.mountPoint} = { + device = "/dev/disk/by-label/" + cfg.extraDisk.label; + autoResize = true; + fsType = "ext4"; + }; + }); boot.growPartition = true; boot.loader.grub.device = "/dev/sda"; |