Stream: nixos

Topic: ✔ VM - QEMU


view this post on Zulip David Arnold (Mar 06 2024 at 09:34):

How do you fake the net devices to a NixOS VM specialization that is simply built with standard Nixos module system components:

nix build .\#nixosConfigurations.deploy-test-roble\
  .config.system.build.vm

It's stuck until timeout on this startup:

image.png

This is my current qemu flag setting:

QEMU_KERNEL_PARAMS=console=ttyS0 \
QEMU_NET_OPTS="hostfwd=tcp:127.0.0.1:80-:80,hostfwd=tcp:127.0.0.1:443-:433" \
sudo ./result/bin/run-roble-vm -nographic; reset

Added qemu expert question: why don't I see the boot sequence when run with sudo despite QEMU_KERNEL_PARAMS=console=ttyS0?

view this post on Zulip Andreas (Mar 06 2024 at 10:39):

These env variables are NixOS specific, yes? I wasn't able to find anything on the QEMU_KERNEL_PARAMS variable. But I would say that QEMU_KERNEL_PARAMS=console=ttyS0looks odd without quotation marks. Shouldn't it be like QEMU_KERNEL_PARAMS="console=ttyS0"?

view this post on Zulip David Arnold (Mar 06 2024 at 10:47):

Yes, these are a way to inject into the nixos-specific bash wrapper:

#! /nix/store/r9h133c9m8f6jnlsqzwf89zg9w0w78s8-bash-5.2-p15/bin/bash

export PATH=/nix/store/rk067yylvhyb7a360n8k1ps4lb4xsbl3-coreutils-9.3/bin${PATH:+:}$PATH

set -e

# Create an empty ext4 filesystem image. A filesystem image does not
# contain a partition table but just a filesystem.
createEmptyFilesystemImage() {
  local name=$1
  local size=$2
  local temp=$(mktemp)
  /nix/store/vvgmw7dmbpfzli5bbcks63j08ajdrl83-qemu-host-cpu-only-8.1.5/bin/qemu-img create -f raw "$temp" "$size"
  /nix/store/l9sv8g6xlv06wwbsmqxx4hwpa22q7nq0-e2fsprogs-1.47.0-bin/bin/mkfs.ext4 -L nixos "$temp"
  /nix/store/vvgmw7dmbpfzli5bbcks63j08ajdrl83-qemu-host-cpu-only-8.1.5/bin/qemu-img convert -f raw -O qcow2 "$temp" "$name"
  rm "$temp"
}

NIX_DISK_IMAGE=$(readlink -f "${NIX_DISK_IMAGE:-./roble.qcow2}") || test -z "$NIX_DISK_IMAGE"

if test -n "$NIX_DISK_IMAGE" && ! test -e "$NIX_DISK_IMAGE"; then
    echo "Disk image do not exist, creating the virtualisation disk image..."

    createEmptyFilesystemImage "$NIX_DISK_IMAGE" "1024M"

    echo "Virtualisation disk image created."
fi

# Create a directory for storing temporary data of the running VM.
if [ -z "$TMPDIR" ] || [ -z "$USE_TMPDIR" ]; then
    TMPDIR=$(mktemp -d nix-vm.XXXXXXXXXX --tmpdir)
fi



# Create a directory for exchanging data with the VM.
mkdir -p "$TMPDIR/xchg"







cd "$TMPDIR"




# Start QEMU.
exec /nix/store/vvgmw7dmbpfzli5bbcks63j08ajdrl83-qemu-host-cpu-only-8.1.5/bin/qemu-kvm -cpu max \
    -name roble \
    -m 1024 \
    -smp 1 \
    -device virtio-rng-pci \
    -net nic,netdev=user.0,model=virtio -netdev user,id=user.0,"$QEMU_NET_OPTS" \
    -virtfs local,path=/nix/store,security_model=none,mount_tag=nix-store \
    -virtfs local,path="${SHARED_DIR:-$TMPDIR/xchg}",security_model=none,mount_tag=shared \
    -virtfs local,path="$TMPDIR"/xchg,security_model=none,mount_tag=xchg \
    -drive cache=writeback,file="$NIX_DISK_IMAGE",id=drive1,if=none,index=1,werror=report -device virtio-blk-pci,bootindex=1,drive=drive1,serial=root \
    -device virtio-keyboard \
    -usb \
    -device usb-tablet,bus=usb-bus.0 \
    -kernel ${NIXPKGS_QEMU_KERNEL_roble:-/nix/store/w13hckxyqaqjaf9xxx7s889mbfhnv5iq-nixos-system-roble-23.11pre-git/kernel} \
    -initrd /nix/store/ayvzq5hpdx552w092k0mbmr1qfia9inb-initrd-linux-6.6.19/initrd \
    -append "$(cat /nix/store/w13hckxyqaqjaf9xxx7s889mbfhnv5iq-nixos-system-roble-23.11pre-git/kernel-params) init=/nix/store/w13hckxyqaqjaf9xxx7s889mbfhnv5iq-nixos-system-roble-23.11pre-git/init regInfo=/nix/store/xss2c6kv0rjjawcwf7vwjhcnlda8wq5q-closure-info/registration console=ttyS0,115200n8 console=tty0 $QEMU_KERNEL_PARAMS" \
    $QEMU_OPTS \
    "$@"

view this post on Zulip Andreas (Mar 06 2024 at 11:04):

Looking at this wrapper, console=ttyS0,115200n8 console=tty0 appears to be the default, right? So you wouldn't have to set this yourself?

view this post on Zulip David Arnold (Mar 06 2024 at 13:22):

I figured it out -- under virtualisation.vmVariant one can modify the vm variant.

And similarly, I could modify the network interfaces.

    virtualisation.vmVariant.networking.useDHCP = lib.mkForce true;
    virtualisation.vmVariant.networking.interfaces = lib.mkForce {};

view this post on Zulip Notification Bot (Mar 06 2024 at 13:22):

David Arnold has marked this topic as resolved.

view this post on Zulip Andreas (Mar 06 2024 at 14:17):

Alright, would you care posting a snippet of the whole working thing @David Arnold ? I wanna play with it maybe in the coming days. Is it possible to create Non-NixOS VMs this way?

view this post on Zulip David Arnold (Mar 06 2024 at 14:50):

Yep, any NixOS is also a VM under config.system.build.vm...

It's just that virtualisation.vmVariant.* is made so that under that namespace, you can override any other option that would otherwise be set in the "main" NixOS.

I'm currently using this for testing a Frappix deployment, but the deployment itself is private, so I can't share too much. I try to sketch some domain-specific gotchas in the docs, though.


Last updated: Nov 15 2024 at 13:04 UTC