hashicorp / packer-plugin-qemu

Packer plugin for QEMU Builder
https://www.packer.io/docs/builders/qemu
Mozilla Public License 2.0
64 stars 44 forks source link

Unable to boot Windows Server 2022 in UEFI mode on RHEL 8.10 - always boots in Legacy BIOS - no errors #177

Open jamesfreeman959 opened 3 months ago

jamesfreeman959 commented 3 months ago

Overview of the Issue

I am trying to produce a proof of concept based around Windows Server 2022 (eval) but booted in UEFI mode with a vTPM. My source system is RHEL 8.10 but I can test on newer systems if that helps. All permutations of the build file are booting into SeaBIOS, and there are no errors I can see in the output of packer with PACKER_LOG=1 set. It's almost like the efi_boot parameter is being ignored.

Reproduction Steps

  1. Define build file as below
  2. Run packer build
  3. VM boots - if you open the VNC console, you can see it has booted into SeaBIOS. Also the qemu arguments do not show any EFI or OVMF related flags.

Plugin and Packer version

Packer v1.11.2

Simplified Packer Buildfile

source "qemu" "ws2022" {
  accelerator      = "kvm"
  boot_wait        = "0s"
  communicator     = "winrm"
  cpus             = "${var.cpu}"
  disk_size        = "${var.disk_size}"
  efi_boot         = true
  efi_firmware_code = "/usr/share/OVMF/OVMF_CODE.secboot.fd"
  efi_firmware_vars = "/usr/share/OVMF/OVMF_VARS.fd"
  headless         = true
  iso_checksum     = "${var.iso_checksum}"
  iso_url          = "${var.iso_url}"
  machine_type     = "q35"
  memory           = "${var.ram}"
  output_directory = "windows_2022-qemu"
  qemu_binary      = "/usr/libexec/qemu-kvm"
  qemuargs         = [["-drive", "file=windows_2022-qemu/{{ .Name }},if=virtio,cache=writeback,discard=ignore,format=qcow2,index=1"], 
                      ["-drive", "file=${var.virtio_win_iso},media=cdrom,index=3"]]
  vm_name          = "WindowsServer2022"
  vtpm             = true
  winrm_password   = "${var.ssh_password}"
  winrm_timeout    = "${var.winrm_timeout}"
  winrm_username   = "${var.ssh_username}"
}

Operating system and Environment details

RHEL 8.10 host machine on AMD64 architecture. OVMF files installed and verified as present.

Log Fragments and crash.log files

==> qemu.ws2022: Overriding default Qemu arguments with qemuargs template option...
2024/08/02 17:03:53 packer-plugin-qemu_v1.1.0_x5.0_linux_amd64 plugin: 2024/08/02 17:03:53 Executing /usr/libexec/qemu-kvm: []string{"-drive", "file=windows_2022-qemu/WindowsServer2022,if=virtio,cache=writeback,discard=ignore,format=qcow2,index=1", "-drive", "file=/home/jamesf_local/packer-netboot-webserver/webroot/iso/virtio-win.iso,media=cdrom,index=3", "-smp", "2", "-netdev", "user,id=user.0,hostfwd=tcp::3032-:5985", "-machine", "type=q35,accel=kvm", "-m", "2048M", "-chardev", "socket,id=vtpm,path=/tmp/2886944654/vtpm.sock", "-device", "virtio-net,netdev=user.0", "-device", "tpm-tis,tpmdev=tpm0", "-name", "WindowsServer2022", "-vnc", "127.0.0.1:39", "-tpmdev", "emulator,id=tpm0,chardev=vtpm"}
2024/08/02 17:03:53 packer-plugin-qemu_v1.1.0_x5.0_linux_amd64 plugin: 2024/08/02 17:03:53 Started Qemu. Pid: 235889
jamesfreeman959 commented 3 months ago

Quick update - if you remove qemuargs, then the VM boots into UEFI mode, so it appears that these are overriding the efi_boot parameter. Is this a bug, or did I miss something in the documentation about how this argument interacts with others? I'd argue it's a bug as the TPM related flags are not affects, but if I've misunderstood something please let me know!

QEMU paramters without qemuargs:

2024/08/02 17:16:14 packer-plugin-qemu_v1.1.0_x5.0_linux_amd64 plugin: 2024/08/02 17:16:14 Executing /usr/libexec/qemu-kvm: []string{"-drive", "file=windows_2022-qemu/WindowsServer2022,if=virtio,cache=writeback,discard=ignore,format=qcow2", "-drive", "file=/home/jamesf_local/.cache/packer/f1379c61c4705c2d66f46d271609fc75e967a5fe.iso,media=cdrom", "-drive", "file=/usr/share/OVMF/OVMF_CODE.secboot.fd,if=pflash,unit=0,format=raw,readonly=on", "-drive", "file=windows_2022-qemu/efivars.fd,if=pflash,unit=1,format=raw", "-name", "WindowsServer2022", "-netdev", "user,id=user.0,hostfwd=tcp::4357-:5985", "-device", "virtio-net,netdev=user.0", "-device", "tpm-tis,tpmdev=tpm0", "-machine", "type=q35,accel=kvm", "-m", "2048M", "-smp", "2", "-vnc", "127.0.0.1:10", "-chardev", "socket,id=vtpm,path=/tmp/410159575/vtpm.sock", "-tpmdev", "emulator,id=tpm0,chardev=vtpm"}
lbajolet-hashicorp commented 3 months ago

Hi @jamesfreeman959,

As you noted this is a conflict between the arguments provided in qemuargs and how the EFI blob is mounted, as you define a -drive in your config, it takes precedence over everything that the plugin computes, including the EFI blob here, so qemu defaults to SEABios in this case. The documentation does specify that For instance adding a "--drive" or "--device" override will mean that none of the default configuration Packer sets will be used., but there maybe a misunderstanding regarding what default configuration means here. The device and drive args are computed as part of a getDeviceAndDriveArgs function, and the EFIvars/OVMFCode are mounted as -drive (maybe they could be mounted some other way though?) so they are overridden by yours, as you can inspect in applyUserOverrides.

Right now I think the easiest way we can fix this problem is by improving the docs so they declare how the arguments are passed to qemu, so you can bisect more easily why/which argument overrides them, but I'm all ears if you have other suggestions!

Thanks for the report!

jamesfreeman959 commented 3 months ago

Hey there!

Thanks so much for your response - I did see that in the documentation although much later on after reporting the issue. Overall the challenge is:

This necessitates two CDROM drives in Qemu, as you can't add a floppy drive to a Qemu machine in UEFI mode (it throws an error).

What works really well (but isn't documented as clearly) is using cd_files to build up a supplemental ISO containing the Autounattend.xml, Virtio drivers, and any other scripts. When you use this in conjunction with iso_url, you actually get two CDROM drives attached to the VM. The iso_url drive is first (so D:) and cd_files is second (E:).

This actually solves my problem perfectly and last night I produced my first working VM through Packer per the above requirements. So all the right functionality is there already - but I found out through trial and error about how to create two CDROM drives on the VM. I don't know if you can drop in an application note, or add a note to the two parameters I've mentioned here about how they work together? Just a few thoughts - happy to help contribute if I can!

lbajolet-hashicorp commented 3 months ago

Hey @jamesfreeman959,

Good to know you managed to make your case work!

Regarding cd_files/floopy_files that's interesting, I didn't know that floppy was unsupported with UEFI, that might be a good idea to add a note to the attribute pointing to cd_files in this case, though I think they're inherited from the SDK so it could be slightly touchy to add the note in the right place, but it may be possible to hint at it at least.

If you're willing to submit a PR to add something like this please feel free to do so, we'll review it ASAP, and provide suggestions if we have an idea on how to improve the docs; otherwise I'll add this to my TODO list and revisit it when possible.

Thanks for the update!

Stromweld commented 3 months ago

It'd be nice if cd_files property were a default property from packer that all providers then would inherit or at least it should be a standard for all providers that it makes sense for. I've only seen it in the qemu and hyper-v iso builders. much like floppy_files is pretty standard for all builders. UEFI drops support for floppy disk drives and newer OS's are scanning cdrom drives for automation files for cloud init or windows autounattend.xml. I opened an issue in parllels plugin repo along the same lines https://github.com/Parallels/packer-plugin-parallels/issues/102