117 lines
3.5 KiB
Nix
117 lines
3.5 KiB
Nix
# This module creates a virtual machine from the NixOS configuration.
|
|
# Building the `config.system.build.vm' attribute gives you a command
|
|
# that starts a KVM/QEMU VM running the NixOS configuration defined in
|
|
# `config'. The Nix store is shared read-only with the host, which
|
|
# makes (re)building VMs very efficient. However, it also means you
|
|
# can't reconfigure the guest inside the guest - you need to rebuild
|
|
# the VM in the host. On the other hand, the root filesystem is a
|
|
# read/writable disk image persistent across VM reboots.
|
|
|
|
{config, pkgs, ...}:
|
|
|
|
let
|
|
|
|
vmName = config.networking.hostName;
|
|
|
|
options = {
|
|
|
|
virtualisation.diskImage =
|
|
pkgs.lib.mkOption {
|
|
default = "./${vmName}.qcow2";
|
|
description =
|
|
''
|
|
Path to the disk image containing the root filesystem.
|
|
The image will be created on startup if it does not
|
|
exist.
|
|
'';
|
|
};
|
|
|
|
};
|
|
|
|
|
|
# Shell script to start the VM.
|
|
startVM =
|
|
''
|
|
#! ${pkgs.stdenv.shell}
|
|
|
|
export PATH=${pkgs.samba}/sbin:$PATH
|
|
|
|
NIX_DISK_IMAGE=''${NIX_DISK_IMAGE:-${config.virtualisation.diskImage}}
|
|
|
|
if ! test -e "$NIX_DISK_IMAGE"; then
|
|
${pkgs.kvm}/bin/qemu-img create -f qcow2 "$NIX_DISK_IMAGE" 512M || exit 1
|
|
fi
|
|
|
|
${pkgs.kvm}/bin/qemu-system-x86_64 \
|
|
-net nic,model=virtio -net user -smb / \
|
|
-drive file=$NIX_DISK_IMAGE,if=virtio,boot=on \
|
|
-kernel ${config.system.build.system}/kernel \
|
|
-initrd ${config.system.build.system}/initrd \
|
|
$QEMU_OPTS \
|
|
-append "$(cat ${config.system.build.system}/kernel-params) init=${config.system.build.bootStage2} systemConfig=${config.system.build.system}"
|
|
'';
|
|
|
|
in
|
|
|
|
{
|
|
require = options;
|
|
|
|
# All the modules the initrd needs to mount the host filesystem via
|
|
# CIFS. Also use paravirtualised network and block devices for
|
|
# performance.
|
|
boot.initrd.extraKernelModules =
|
|
["cifs" "virtio_net" "virtio_pci" "virtio_blk" "virtio_balloon" "nls_utf8"];
|
|
|
|
boot.initrd.extraUtilsCommands =
|
|
''
|
|
# We need mke2fs in the initrd.
|
|
cp ${pkgs.e2fsprogs}/sbin/mke2fs $out/bin
|
|
'';
|
|
|
|
boot.initrd.postDeviceCommands =
|
|
''
|
|
# Set up networking. Needed for CIFS mounting.
|
|
ipconfig 10.0.2.15:::::eth0:none
|
|
|
|
# If the disk image appears to be empty (fstype "unknown";
|
|
# hacky!!!), run mke2fs to initialise.
|
|
eval $(fstype /dev/vda)
|
|
if test "$FSTYPE" = unknown; then
|
|
mke2fs -t ext3 /dev/vda
|
|
fi
|
|
'';
|
|
|
|
# Mount the host filesystem via CIFS, and bind-mount the Nix store
|
|
# of the host into our own filesystem.
|
|
fileSystems =
|
|
[ { mountPoint = "/";
|
|
device = "/dev/vda";
|
|
}
|
|
{ mountPoint = "/hostfs";
|
|
device = "//10.0.2.4/qemu";
|
|
fsType = "cifs";
|
|
options = "guest,username=nobody";
|
|
neededForBoot = true;
|
|
}
|
|
{ mountPoint = "/nix/store";
|
|
device = "/hostfs/nix/store";
|
|
options = "bind";
|
|
neededForBoot = true;
|
|
}
|
|
];
|
|
|
|
# Starting DHCP brings down eth0, which kills the connection to the
|
|
# host filesystem and thus deadlocks the system.
|
|
networking.useDHCP = false;
|
|
|
|
system.build.vm = pkgs.runCommand "nixos-vm" {}
|
|
''
|
|
ensureDir $out/bin
|
|
ln -s ${config.system.build.system} $out/system
|
|
ln -s ${pkgs.writeScript "run-nixos-vm" startVM} $out/bin/run-${vmName}-vm
|
|
'';
|
|
|
|
# sendfile() is currently broken over CIFS, so fix it here for all
|
|
# configurations that use Apache.
|
|
services.httpd.extraConfig = "EnableSendFile Off";
|
|
}
|