Install the guest agent
guest_exec, guest_file_read and guest_file_write talk to
qemu-guest-agent running inside the guest operating system. mcqemu wires the
host side of that channel (a virtio-serial port named
org.qemu.guest_agent.0) into every VM it launches, so the only missing piece
is the package inside the guest.
Check what you have:
guest_ping(name="vm")Success means you are done. Failure means the agent is not installed, not
running, or the guest is paused or frozen. guest_info then reports the guest
OS, the agent version, and which agent commands are enabled.
Option 1: from inside a running guest
Section titled “Option 1: from inside a running guest”Use this when the guest is up and you can reach a console (with
vm_type_text, see Drive an installer) or an
SSH session through a forwarded port.
The guest needs package downloads to work, so if this VM was created with
sandbox_vm, it has outbound networking blocked by default; recreate it with
allow_network=true for the install.
Run the pair of commands for the distribution, as root:
# Debian, Ubuntuapt-get update && apt-get install -y qemu-guest-agentsystemctl enable --now qemu-guest-agent
# Fedora, RHEL, CentOS, Rocky, Almadnf install -y qemu-guest-agentsystemctl enable --now qemu-guest-agent
# Archpacman -S --noconfirm qemu-guest-agentsystemctl enable --now qemu-guest-agent
# Alpineapk add qemu-guest-agentrc-update add qemu-guest-agent default && rc-service qemu-guest-agent start
# openSUSEzypper install -y qemu-guest-agentsystemctl enable --now qemu-guest-agentWindows guests get the agent from the
virtio-win ISO: attach
it with launch_vm(..., iso="/path/to/virtio-win.iso") and run
guest-agent\qemu-ga-x86_64.msi from inside the guest.
Then confirm from the host:
guest_ping(name="vm")guest_exec(name="vm", command="uname", args=["-a"])Enabling the service matters as much as installing the package. An agent that is running now but not enabled at boot will be missing the next time you launch that image, and every sandbox built on it.
Option 2: inject it into a stopped disk image
Section titled “Option 2: inject it into a stopped disk image”Use this when you cannot get a console: a downloaded cloud image with no password set, an image whose network never comes up, or when you are preparing a base image and would rather not boot it at all.
The technique exposes the disk image to the host as a block device with
qemu-nbd, mounts the guest’s root filesystem, and installs the package into
it through chroot.
-
Load the network block device module and connect the image:
Terminal window sudo modprobe nbd max_part=8sudo qemu-nbd --connect=/dev/nbd0 ~/vms/debian.qcow2 -
Find the root partition. Do not guess: images vary, and picking a boot or EFI partition wastes time.
Terminal window lsblk /dev/nbd0sudo blkid /dev/nbd0p*The root filesystem is usually the largest ext4, xfs or btrfs partition. If
lsblkshows LVM physical volumes instead of a plain filesystem, runsudo vgchange -ayand mount the resulting device under/dev/mapper/. -
Mount it, plus the pseudo-filesystems the package manager needs:
Terminal window sudo mkdir -p /mnt/guestsudo mount /dev/nbd0p1 /mnt/guestsudo mount --bind /dev /mnt/guest/devsudo mount --bind /proc /mnt/guest/procsudo mount --bind /sys /mnt/guest/sysIf the image has a separate
/bootor EFI partition, mount those inside/mnt/guesttoo. Installing the agent does not need them, but a package manager that decides to regenerate an initramfs will fail without them. -
Give the chroot working DNS, keeping the original so you can put it back:
Terminal window sudo cp /mnt/guest/etc/resolv.conf /mnt/guest/etc/resolv.conf.origsudo cp /etc/resolv.conf /mnt/guest/etc/resolv.conf -
Install the agent inside the image:
Terminal window sudo chroot /mnt/guest apt-get updatesudo chroot /mnt/guest apt-get install -y qemu-guest-agentsudo chroot /mnt/guest systemctl enable qemu-guest-agentsystemctl enableworks in a chroot because it only creates symlinks; it does not need systemd to be running.systemctl startwould fail, which is fine, because the guest starts the service on its next boot. For dnf-based images substitutednf install -y qemu-guest-agent, and for Alpineapk add qemu-guest-agentwithrc-update add qemu-guest-agent default. -
Restore the guest’s own resolver:
Terminal window sudo mv /mnt/guest/etc/resolv.conf.orig /mnt/guest/etc/resolv.conf -
Tear down in reverse order, and check each step succeeded:
Terminal window sudo umount -R /mnt/guestsudo qemu-nbd --disconnect /dev/nbd0If
umountreports the target is busy, find what is holding it withsudo lsof +D /mnt/guestand stop that before retrying. Disconnecting the nbd device while a filesystem is still mounted loses writes. -
Boot it and check:
launch_vm(name="debian", disks=["~/vms/debian.qcow2"])guest_ping(name="debian")
Making it a base image
Section titled “Making it a base image”Once guest_ping answers, that image is ready to be the base for disposable
clones. Shut the VM down cleanly with stop_vm so the filesystem is
consistent, then never launch the base directly again; build sandboxes on it
instead, as in Disposable sandboxes.
While you are in there, two things are worth doing to the image because every
future sandbox inherits them: install the packages you always want, and make
sure the SSH server is enabled if you plan to use the forwarded port that
sandbox_vm sets up.
Related
Section titled “Related”- Disposable sandboxes for using the finished base image.
- Snapshots for checkpointing an image before you modify it.
- Tool reference for the
guest_*tool parameters.