From e4e732b31d229c7f9ac4d688a3fc9b94f41bb2d1 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Fri, 5 Oct 2018 15:25:39 +0000 Subject: [PATCH 01/19] WIP: Add efi and secureboot support - secure boot support is currently limited to redhat derived distros as the ubuntu packages don't provide UefiShell.iso. - Although the upgrading of qemu packages is more suited to the ansible-role-libvirt-host role, we need to know the location of the UEFI firmware images to setup the virtual machines. As we somtimes require custom packages this makes it hard to know upfront what the path will be. --- README.md | 8 +++++ defaults/main.yml | 16 ++++++++++ tasks/main.yml | 6 ++++ tasks/prepare_secure_boot.yml | 59 +++++++++++++++++++++++++++++++++++ tasks/setup.yml | 31 ++++++++++++++++++ tasks/vm.yml | 6 ++++ templates/vm.xml.j2 | 11 +++++++ vars/Debian.yml | 15 +++++++++ vars/RedHat.yml | 36 +++++++++++++++++++++ 9 files changed, 188 insertions(+) create mode 100644 tasks/prepare_secure_boot.yml create mode 100644 tasks/setup.yml diff --git a/README.md b/README.md index 9ed2c3c..0e4e392 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,12 @@ Role Variables - `libvirt_vm_arch`: CPU architecture, default is `x86_64`. +- `libvirt_vm_enable_efi_support`: Whether to enable EFI support. By default this + will enabled if any of the declared VMs specify the boot_firmware as efi. The + certificates and keys needed to enable secure boot are currently only installed + on RedHat derived distributions. See: [qemu-ovmf-secureboot](https://github.com/puiterwijk/qemu-ovmf-secureboot) + for details of the certificates and keys that are installed. + - `libvirt_vms`: list of VMs to be created/destroyed. Each one may have the following attributes: @@ -91,6 +97,8 @@ Role Variables - `autostart`: Whether to start the VM when the host starts up. Default is `true`. + + - `boot_firmware`: Can be one of: `bios`, or `efi`. Defaults to `bios`. N.B. the following variables are deprecated: `libvirt_vm_state`, diff --git a/defaults/main.yml b/defaults/main.yml index 027618d..e216da1 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -24,6 +24,19 @@ libvirt_vm_engine: # correct emulator to use. libvirt_vm_emulator: +# This is where https://github.com/puiterwijk/qemu-ovmf-secureboot will be +# checked out to. +libvirt_ovmf_vars_generator_checkout_path: "/opt/qemu-ovmf-secureboot" + +# Where to output the generated variable store +libvirt_ovmf_vars_generator_output_path: "{{ libvirt_ovmf_vars_generator_checkout_path }}" + +# Prefix of generated variable file name. The checksum of the input will be appended. +libvirt_ovmf_vars_generator_output_prefix: ovmf_vars_enrolled_ + +# Whether to enable EFI support. +libvirt_vm_enable_efi_support: "{{ 'efi' in (libvirt_vms | map(attribute='boot_firmware') | map('lower')) }}" + # A list of specifications of VMs to be created. # For backwards compatibility, libvirt_vms defaults to a singleton list using # the values of the deprecated variables below. @@ -56,6 +69,9 @@ libvirt_vms: # Path to console log file. console_log_path: "{{ libvirt_vm_console_log_path }}" + # May be one of: bios, or efi. + boot_firmware: bios + ### DEPRECATED ### # Use the above settings for each item within `libvirt_vms`, instead of the diff --git a/tasks/main.yml b/tasks/main.yml index 08e2cdf..29a6c5b 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,4 +1,7 @@ --- + +- include_tasks: setup.yml + - include_tasks: autodetect.yml # We don't need to know the engine and emulator if we're not creating any new # VMs. @@ -26,6 +29,9 @@ interfaces: "{{ vm.interfaces | default([], true) }}" start: "{{ vm.start | default(true) }}" autostart: "{{ vm.autostart | default(true) }}" + boot_firmware: "{{ vm.boot_firmware | default('bios', true) | lower }}" + enable_feature_acpi_default: "{{ true if boot_firmware == 'efi' else false }}" + enable_feature_acpi: "{{ vm.enable_feature_acpi | default(enable_feature_acpi_default, true) }}" with_items: "{{ libvirt_vms }}" loop_control: loop_var: vm diff --git a/tasks/prepare_secure_boot.yml b/tasks/prepare_secure_boot.yml new file mode 100644 index 0000000..b02381b --- /dev/null +++ b/tasks/prepare_secure_boot.yml @@ -0,0 +1,59 @@ +--- + +- name: Gather os specific variables + include_vars: "{{ item }}" + with_first_found: + - files: + - "{{ ansible_distribution }}-{{ ansible_distribution_major_version}}.yml" + - "{{ ansible_distribution }}.yml" + - "{{ ansible_os_family }}.yml" + skip: true + tags: vars + +- name: Ensure ovmf generator checkout directory is owned by ansible_user + file: + path: "{{ libvirt_ovmf_vars_generator_checkout_path }}" + owner: "{{ ansible_user }}" + state: directory + become: true + +- name: Clone ovfm-vars generator + git: + repo: 'https://github.com/puiterwijk/qemu-ovmf-secureboot' + dest: "{{ libvirt_ovmf_vars_generator_checkout_path }}" + update: yes + +- name: Get checksum of template OVMF vars + # We need to keep the generated vars in sync with templated version. + # if the OVMF package is updated - we should update a new version with + # the signing keys enrolled. + stat: + path: "{{ libvirt_vm_ovmf_efi_variable_store_path }}" + get_checksum: true + checksum_algorithm: sha256 + register: ovmf_template + +- name: Register path of generated variables + set_fact: + ovmf_enrolled_variables_path: "\ + {{ libvirt_ovmf_vars_generator_output_path }}/\ + {{ libvirt_ovmf_vars_generator_output_prefix }}\ + {{ ovmf_template.stat.checksum }}" + +- name: Check to see if we have generated these vars before + stat: + path: "{{ ovmf_enrolled_variables_path }}" + register: generated_ovmf + +- name: Run OVMF vars generator + command: > + python {{ libvirt_ovmf_vars_generator_checkout_path}}/ovmf-vars-generator + --ovmf-binary {{ libvirt_vm_ovmf_efi_firmware_path }} + --uefi-shell-iso {{ libvirt_vm_ovmf_uefi_shell_iso_path }} + --ovmf-template-vars {{ libvirt_vm_ovmf_efi_variable_store_path }} + --qemu-binary {{ libvirt_vm_emulator }} + {% if libvirt_vm_engine == 'kvm' %}--enable-kvm{% endif %} + --skip-testing + --no-download + {{ ovmf_enrolled_variables_path }} + when: not generated_ovmf.stat.exists diff --git a/tasks/setup.yml b/tasks/setup.yml new file mode 100644 index 0000000..3fd6b2e --- /dev/null +++ b/tasks/setup.yml @@ -0,0 +1,31 @@ +--- + +- name: Gather os specific variables + include_vars: "{{ item }}" + with_first_found: + - files: + - "{{ ansible_distribution }}-{{ ansible_distribution_major_version}}.yml" + - "{{ ansible_distribution }}.yml" + - "{{ ansible_os_family }}.yml" + skip: true + tags: vars + +- name: Install custom yum repositories + # Although argument splatting is marked as deprecated: + # + # [DEPRECATION WARNING]: Using variables for task params is unsafe, + # especially if the variables come from an external source like facts. This + # feature will be removed in a future release. + # + # The core team had a a change of heart and it is actually being preserved: + # https://github.com/ansible/ansible/pull/43798 + yum_repository: "{{ item }}" + loop: "{{ libvirt_vm_custom_yum_repos | default({}) }}" + become: true + +- name: Install custom packages + package: + name: "{{ item }}" + state: present + loop: "{{ libvirt_vm_extra_packages }}" + diff --git a/tasks/vm.yml b/tasks/vm.yml index eff1152..00438b8 100644 --- a/tasks/vm.yml +++ b/tasks/vm.yml @@ -26,6 +26,12 @@ interface: "{{ item }}" with_items: "{{ interfaces }}" +- name: Create secure boot template variables + include_tasks: prepare_secure_boot.yml + when: + - boot_firmware == "efi" + - libvirt_vm_ovmf_uefi_shell_iso_path is defined + - name: Ensure the VM is defined virt: name: "{{ vm.name }}" diff --git a/templates/vm.xml.j2 b/templates/vm.xml.j2 index 987c147..c349d9f 100644 --- a/templates/vm.xml.j2 +++ b/templates/vm.xml.j2 @@ -12,7 +12,18 @@ + {% if boot_firmware == "efi" %} + {# NOTE: pflash requires qemu 1.6 or newer. There are alternatives for older versions, but + they do not work with secure boot. See OVMF readme for an overview #} + {{ libvirt_vm_ovmf_efi_firmware_path }} + {{ ovmf_enrolled_variables_path | default(libvirt_vm_ovmf_efi_variable_store_path) }} + {% endif %} + + {% if enable_feature_acpi %} + + {% endif %} + diff --git a/vars/Debian.yml b/vars/Debian.yml index 3dda5d3..b53ee1a 100644 --- a/vars/Debian.yml +++ b/vars/Debian.yml @@ -5,3 +5,18 @@ libvirt_vm_log_owner: libvirt-qemu # The environment passed to virt_volume.sh libvirt_vm_volume_creation_env: {} + +# Packages that are only necessary if you require EFI support +libvirt_vm_extra_packages_efi: + - ovmf + +# List of extra packages to install +libvirt_vm_extra_packages: "{{ [] + (libvirt_vm_extra_packages_efi if libvirt_vm_enable_efi_support else []) | unique }}" + +# Path to template OVMF efi variable store. A copy will be created +# for each VM created. +libvirt_vm_ovmf_efi_variable_store_path: /usr/share/OVMF/OVMF_VARS.fd + +# Path to OVMF efi firmware +libvirt_vm_ovmf_efi_firmware_path: /usr/share/OVMF/OVMF_CODE.fd + diff --git a/vars/RedHat.yml b/vars/RedHat.yml index aa0640e..7d25294 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -7,3 +7,39 @@ libvirt_vm_log_owner: qemu libvirt_vm_volume_creation_env: VOLUME_GROUP: qemu VOLUME_OWNER: qemu + +# Packages that are only necessary if you require EFI support +libvirt_vm_extra_packages_efi: + - edk2.git-ovmf-x64 # Official OVMF package doesn't boot (CentOS 7.5) + - qemu-kvm-ev # Need smm support for secure boot + +# List of extra packages to install +libvirt_vm_extra_packages: "{{ [] + (libvirt_vm_extra_packages_efi if libvirt_vm_enable_efi_support else []) | unique }}" + +# Path to template OVMF efi variable store. A copy will be created +# for each VM created. +# note(wszumski): official package path is /usr/share/OVMF/OVMF_VARS.fd +libvirt_vm_ovmf_efi_variable_store_path: /usr/share/edk2.git/ovmf-x64/OVMF_VARS-need-smm.fd + +# Path to OVMF efi firmware +# note(wszumski): official package path is /usr/share/OVMF/OVMF_CODE.secboot.fd +libvirt_vm_ovmf_efi_firmware_path: /usr/share/edk2.git/ovmf-x64/OVMF_CODE-need-smm.fd + +# Path to iso containing signing keys +# note(wszumski): official package path is /usr/share/OVMF/UefiShell.iso +libvirt_vm_ovmf_uefi_shell_iso_path: /usr/share/edk2.git/ovmf-x64/UefiShell.iso + +# Add custom repository as OVMF package seems to be broken +libvirt_vm_custom_yum_repos_efi: + - name: qemu-firmware-jenkins + description: upstream OVMF firmware images + baseurl: https://www.kraxel.org/repos/jenkins/ + gpgcheck: no + # Need an updated version of qemu with smm support + - name: centos-qemu-ev + description: CentOS-$releasever - QEMU EV + baseurl: http://mirror.centos.org/$contentdir/$releasever/virt/$basearch/kvm-common/ + gpgcheck: yes + +libvirt_vm_custom_yum_repos: "{{ [] + (libvirt_vm_custom_yum_repos_efi if libvirt_vm_enable_efi_support else []) | unique }}" + From 0ed64e70f2229ca331676f78d80fc33c0e1aa529 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Fri, 5 Oct 2018 16:30:15 +0000 Subject: [PATCH 02/19] Fix teardown for VMs with efi enabled Before this change you would get: K [stackhpc.libvirt-vm : Ensure the VM is undefined] *********************** * An exception occurred during task execution. To see the full traceback, use -vv v. The error was: libvirtError: Requested operation is not valid: cannot delete inactive domain with nvram fatal: [localhost]: FAILED! => {"changed": false, "msg": "Requested operation i s not valid: cannot delete inactive domain with nvram"} --- tasks/destroy-vm.yml | 9 ++++++--- tasks/main.yml | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tasks/destroy-vm.yml b/tasks/destroy-vm.yml index 4cc3313..a024645 100644 --- a/tasks/destroy-vm.yml +++ b/tasks/destroy-vm.yml @@ -16,8 +16,11 @@ become: yes - name: Ensure the VM is undefined - virt: - name: "{{ vm.name }}" - command: undefine + # note(wszumski): the virt module does not seem to support + # removing vms with nvram defined - as a workaround, use the + # virsh cli directly. It may be better to detect if dumpxml + # actually contains an nvram element rather than relying on + # boot_firmware having the correct value. + command: virsh -c qemu:///system undefine{% if boot_firmware == 'efi' %} --nvram{% endif %} {{ vm.name }} become: yes when: vm.name in result.list_vms diff --git a/tasks/main.yml b/tasks/main.yml index 29a6c5b..540842a 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -46,6 +46,8 @@ when: (vm.state | default('present', true)) == 'absent' - include_tasks: destroy-vm.yml + vars: + boot_firmware: "{{ vm.boot_firmware | default('bios', true) | lower }}" with_items: "{{ libvirt_vms }}" loop_control: loop_var: vm From a90cf1b964e38f4bf0ebefdc5689191ca037ff30 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 11:18:11 +0000 Subject: [PATCH 03/19] SMM requires q35 machine type From the OVMF readme, https://github.com/tianocore/edk2/tree/073891a3e74059e996258e32b56b3f0770c6fe55/OvmfPkg: * The minimum required QEMU machine type is "pc-q35-2.5". --- tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/main.yml b/tasks/main.yml index 540842a..5524618 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -21,7 +21,7 @@ vars: console_log_enabled: "{{ vm.console_log_enabled | default(false) }}" console_log_path: "{{ vm.console_log_path | default(libvirt_vm_default_console_log_dir + '/' + vm.name + '-console.log', true) }}" - machine_default: "{{ none if libvirt_vm_engine == 'kvm' else 'pc-1.0' }}" + machine_default: "{{ ('q35' if boot_firmware == 'efi' else none) if libvirt_vm_engine == 'kvm' else 'pc' }}" machine: "{{ vm.machine | default(machine_default, true) }}" cpu_mode_default: "{{ 'host-passthrough' if libvirt_vm_engine == 'kvm' else 'host-model' }}" cpu_mode: "{{ vm.cpu_mode | default(cpu_mode_default, true) }}" From 97cddf4c0101883c3656304c408913ad0c609d15 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 11:25:14 +0000 Subject: [PATCH 04/19] Rework generation of NVRAM * It seems you cannot specify multiple elements, instead you must use an nvram element * Ensure the qemu user can read the generated file. This is done by generating the file in a temporary location before transferring ownership to the libvirt_vm_log_owner owner. --- defaults/main.yml | 4 ++-- tasks/prepare_secure_boot.yml | 22 ++++++++++++++++++++-- templates/vm.xml.j2 | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index e216da1..72888a2 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -26,10 +26,10 @@ libvirt_vm_emulator: # This is where https://github.com/puiterwijk/qemu-ovmf-secureboot will be # checked out to. -libvirt_ovmf_vars_generator_checkout_path: "/opt/qemu-ovmf-secureboot" +libvirt_ovmf_vars_generator_checkout_path: /opt/qemu-ovmf-secureboot # Where to output the generated variable store -libvirt_ovmf_vars_generator_output_path: "{{ libvirt_ovmf_vars_generator_checkout_path }}" +libvirt_ovmf_vars_generator_output_path: /var/lib/libvirt/qemu/ # Prefix of generated variable file name. The checksum of the input will be appended. libvirt_ovmf_vars_generator_output_prefix: ovmf_vars_enrolled_ diff --git a/tasks/prepare_secure_boot.yml b/tasks/prepare_secure_boot.yml index b02381b..e13a270 100644 --- a/tasks/prepare_secure_boot.yml +++ b/tasks/prepare_secure_boot.yml @@ -33,13 +33,22 @@ checksum_algorithm: sha256 register: ovmf_template -- name: Register path of generated variables +- name: Register destination of generated variables set_fact: ovmf_enrolled_variables_path: "\ {{ libvirt_ovmf_vars_generator_output_path }}/\ {{ libvirt_ovmf_vars_generator_output_prefix }}\ {{ ovmf_template.stat.checksum }}" +- name: Register temporary path to output generated variables + # We don't want to run the generator with elevated privileges + # so use a temporary output before copying into place + set_fact: + ovmf_enrolled_variables_temp_output_path: "\ + {{ libvirt_ovmf_vars_generator_checkout_path}}/\ + {{ libvirt_ovmf_vars_generator_output_prefix }}\ + {{ ovmf_template.stat.checksum }}" + - name: Check to see if we have generated these vars before stat: path: "{{ ovmf_enrolled_variables_path }}" @@ -55,5 +64,14 @@ {% if libvirt_vm_engine == 'kvm' %}--enable-kvm{% endif %} --skip-testing --no-download - {{ ovmf_enrolled_variables_path }} + {{ ovmf_enrolled_variables_temp_output_path }} + when: not generated_ovmf.stat.exists + +- name: Ensure libvirt qemu can access the variable template + copy: + src: "{{ ovmf_enrolled_variables_temp_output_path }}" + dest: "{{ ovmf_enrolled_variables_path }}" + owner: "{{ libvirt_vm_log_owner }}" + group: "{{ libvirt_vm_log_owner }}" + become: true when: not generated_ovmf.stat.exists diff --git a/templates/vm.xml.j2 b/templates/vm.xml.j2 index c349d9f..70e543b 100644 --- a/templates/vm.xml.j2 +++ b/templates/vm.xml.j2 @@ -16,7 +16,7 @@ {# NOTE: pflash requires qemu 1.6 or newer. There are alternatives for older versions, but they do not work with secure boot. See OVMF readme for an overview #} {{ libvirt_vm_ovmf_efi_firmware_path }} - {{ ovmf_enrolled_variables_path | default(libvirt_vm_ovmf_efi_variable_store_path) }} + {% endif %} From 3a2f2a8b0e4b665392e37e392874d6ba0e51f12c Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 11:38:18 +0000 Subject: [PATCH 05/19] Rename libvirt_vm_log_owner to libvirt_vm_qemu_user This has more general applicability than just setting the owner of the log files. --- tasks/prepare_secure_boot.yml | 4 ++-- tasks/vm.yml | 4 ++-- vars/Debian.yml | 5 +++-- vars/RedHat.yml | 5 +++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tasks/prepare_secure_boot.yml b/tasks/prepare_secure_boot.yml index e13a270..f487e31 100644 --- a/tasks/prepare_secure_boot.yml +++ b/tasks/prepare_secure_boot.yml @@ -71,7 +71,7 @@ copy: src: "{{ ovmf_enrolled_variables_temp_output_path }}" dest: "{{ ovmf_enrolled_variables_path }}" - owner: "{{ libvirt_vm_log_owner }}" - group: "{{ libvirt_vm_log_owner }}" + owner: "{{ libvirt_vm_qemu_user }}" + group: "{{ libvirt_vm_qemu_user }}" become: true when: not generated_ovmf.stat.exists diff --git a/tasks/vm.yml b/tasks/vm.yml index 00438b8..5fc07ca 100644 --- a/tasks/vm.yml +++ b/tasks/vm.yml @@ -13,8 +13,8 @@ file: path: "{{ console_log_path | dirname }}" state: directory - owner: "{{ libvirt_vm_log_owner }}" - group: "{{ libvirt_vm_log_owner }}" + owner: "{{ libvirt_vm_qemu_user }}" + group: "{{ libvirt_vm_qemu_user }}" recurse: true mode: 0770 when: console_log_enabled | bool diff --git a/vars/Debian.yml b/vars/Debian.yml index b53ee1a..ba88fac 100644 --- a/vars/Debian.yml +++ b/vars/Debian.yml @@ -1,7 +1,8 @@ --- -# Who owns the serial console logs in console_log_path -libvirt_vm_log_owner: libvirt-qemu +# This controls ownership of files used by the libvirt qemu process, +# e.g the serial console logs in console_log_path. +libvirt_vm_qemu_user: libvirt-qemu # The environment passed to virt_volume.sh libvirt_vm_volume_creation_env: {} diff --git a/vars/RedHat.yml b/vars/RedHat.yml index 7d25294..60158e6 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -1,7 +1,8 @@ --- -# Who owns the serial console logs in console_log_path -libvirt_vm_log_owner: qemu +# This controls ownership of files used by the libvirt qemu process, +# e.g the serial console logs in console_log_path. +libvirt_vm_qemu_user: qemu # The environment passed to virt_volume.sh libvirt_vm_volume_creation_env: From 808573e3e4344b52f7ceefebc27aa4526a6d49e3 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 11:42:31 +0000 Subject: [PATCH 06/19] Use dashes instead of underscores for word separator This matches the existing files. --- tasks/{prepare_secure_boot.yml => prepare-secure-boot.yml} | 0 tasks/vm.yml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tasks/{prepare_secure_boot.yml => prepare-secure-boot.yml} (100%) diff --git a/tasks/prepare_secure_boot.yml b/tasks/prepare-secure-boot.yml similarity index 100% rename from tasks/prepare_secure_boot.yml rename to tasks/prepare-secure-boot.yml diff --git a/tasks/vm.yml b/tasks/vm.yml index 5fc07ca..16bf5db 100644 --- a/tasks/vm.yml +++ b/tasks/vm.yml @@ -27,7 +27,7 @@ with_items: "{{ interfaces }}" - name: Create secure boot template variables - include_tasks: prepare_secure_boot.yml + include_tasks: prepare-secure-boot.yml when: - boot_firmware == "efi" - libvirt_vm_ovmf_uefi_shell_iso_path is defined From 0e9b51f466c3454f3567376124327c6de207d3b4 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 12:00:40 +0000 Subject: [PATCH 07/19] Default value should be an empty list --- tasks/setup.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/setup.yml b/tasks/setup.yml index 3fd6b2e..a895fd9 100644 --- a/tasks/setup.yml +++ b/tasks/setup.yml @@ -11,7 +11,7 @@ tags: vars - name: Install custom yum repositories - # Although argument splatting is marked as deprecated: + # Although argument splatting is marked as deprecated: # # [DEPRECATION WARNING]: Using variables for task params is unsafe, # especially if the variables come from an external source like facts. This @@ -20,7 +20,7 @@ # The core team had a a change of heart and it is actually being preserved: # https://github.com/ansible/ansible/pull/43798 yum_repository: "{{ item }}" - loop: "{{ libvirt_vm_custom_yum_repos | default({}) }}" + loop: "{{ libvirt_vm_custom_yum_repos | default([]) }}" become: true - name: Install custom packages From bade36f2aad3ad91f7e02adf024a5e63c85dce36 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 12:45:43 +0000 Subject: [PATCH 08/19] Add flag to explicitly enable SMM --- tasks/main.yml | 2 ++ templates/vm.xml.j2 | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tasks/main.yml b/tasks/main.yml index 5524618..31e48fe 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -32,6 +32,8 @@ boot_firmware: "{{ vm.boot_firmware | default('bios', true) | lower }}" enable_feature_acpi_default: "{{ true if boot_firmware == 'efi' else false }}" enable_feature_acpi: "{{ vm.enable_feature_acpi | default(enable_feature_acpi_default, true) }}" + enable_feature_smm_default: "{{ true if boot_firmware == 'efi' else false }}" + enable_feature_smm: "{{ vm.enable_feature_smm | default(enable_feature_smm_default, true) }}" with_items: "{{ libvirt_vms }}" loop_control: loop_var: vm diff --git a/templates/vm.xml.j2 b/templates/vm.xml.j2 index 70e543b..4ca7a18 100644 --- a/templates/vm.xml.j2 +++ b/templates/vm.xml.j2 @@ -23,6 +23,9 @@ {% if enable_feature_acpi %} {% endif %} + {% if enable_feature_smm %} + + {% endif %} From 1957070453ee351bfd76c5f74f76cf90a736dc89 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 15:02:05 +0000 Subject: [PATCH 09/19] Add comment explaining usage of OVMF generator --- tasks/prepare-secure-boot.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tasks/prepare-secure-boot.yml b/tasks/prepare-secure-boot.yml index f487e31..acd5d6c 100644 --- a/tasks/prepare-secure-boot.yml +++ b/tasks/prepare-secure-boot.yml @@ -1,4 +1,34 @@ --- +# This playbook enrolls Platform, Key Exchange, and Signature Database keys +# in the emulated NVRAM. NVRAM is the storage location for persistent +# EFI state. The keys that are installed are as follows: +# +# * Platform Key: Red Hat Secure Boot (PK/KEK key 1)/emailAddress=secalert@redhat.com. +# This is a Red Hat controlled key which controls modification to the +# Key Exchange Keys (KEK). +# +# * Key Exchange Keys: +# 1) Microsoft Corporation KEK CA 2011 +# 2) Red Hat Secure Boot (PK/KEK key 1)/emailAddress=secalert@redhat.com +# +# The first KEK is used to sign the revocation database obtained from: +# http://www.uefi.org/revocationlistfile. This allows you to use: dbxtool +# to periodically update your local copy of this blacklist. The second gives +# RedHat control over the dbx (Forbidden Signature) and db (Signature) databases. +# This essentially makes your computer trust RedHat and Microsoft signed binaries. +# +# * Signature database (db) keys: +# - Microsoft Windows Production PCA 2011 (for accepting Windows 8, Windows Server 2012 R2, etc boot loaders) +# - Microsoft Corporation UEFI CA 2011 (for verifying the shim binary, and PCI expansion ROMs). +# +# Further signing keys can be enrolled in the shim binary to allow execution of custom binaries. +# +# When a platform key is enrolled, the secure boot mode changes from "setup mode" to "user mode" +# and secure boot is automatically enabled. Secure boot can only be disabled via the EFI setup +# menu - this is accessed by pressing delete when the VM is started. It does not seem possible to +# to control this setting via libvirt or by using a qemu command line option. +# +# TODO: Allow installation of custom keys - name: Gather os specific variables include_vars: "{{ item }}" From e96b7aa8b10810b3345e4a87afb246e8b0ad3546 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 15:06:20 +0000 Subject: [PATCH 10/19] Appending to an empty list is unnecessary --- vars/Debian.yml | 2 +- vars/RedHat.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vars/Debian.yml b/vars/Debian.yml index ba88fac..3f87215 100644 --- a/vars/Debian.yml +++ b/vars/Debian.yml @@ -12,7 +12,7 @@ libvirt_vm_extra_packages_efi: - ovmf # List of extra packages to install -libvirt_vm_extra_packages: "{{ [] + (libvirt_vm_extra_packages_efi if libvirt_vm_enable_efi_support else []) | unique }}" +libvirt_vm_extra_packages: "{{ libvirt_vm_extra_packages_efi if libvirt_vm_enable_efi_support else [] | unique }}" # Path to template OVMF efi variable store. A copy will be created # for each VM created. diff --git a/vars/RedHat.yml b/vars/RedHat.yml index 60158e6..1981c65 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -15,7 +15,7 @@ libvirt_vm_extra_packages_efi: - qemu-kvm-ev # Need smm support for secure boot # List of extra packages to install -libvirt_vm_extra_packages: "{{ [] + (libvirt_vm_extra_packages_efi if libvirt_vm_enable_efi_support else []) | unique }}" +libvirt_vm_extra_packages: "{{ libvirt_vm_extra_packages_efi if libvirt_vm_enable_efi_support else [] | unique }}" # Path to template OVMF efi variable store. A copy will be created # for each VM created. @@ -42,5 +42,5 @@ libvirt_vm_custom_yum_repos_efi: baseurl: http://mirror.centos.org/$contentdir/$releasever/virt/$basearch/kvm-common/ gpgcheck: yes -libvirt_vm_custom_yum_repos: "{{ [] + (libvirt_vm_custom_yum_repos_efi if libvirt_vm_enable_efi_support else []) | unique }}" +libvirt_vm_custom_yum_repos: "{{ libvirt_vm_custom_yum_repos_efi if libvirt_vm_enable_efi_support else [] | unique }}" From d960ec0de9a0d72773ac6787ea9768e22be52887 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Mon, 22 Oct 2018 16:22:43 +0000 Subject: [PATCH 11/19] Move package installation to stackhpc.libvirt-host role See: stackhpc/ansible-role-libvirt-host#7 --- README.md | 6 ------ defaults/main.yml | 3 --- tasks/main.yml | 2 -- tasks/setup.yml | 31 ------------------------------- vars/Debian.yml | 7 ------- vars/RedHat.yml | 22 ---------------------- 6 files changed, 71 deletions(-) delete mode 100644 tasks/setup.yml diff --git a/README.md b/README.md index 0e4e392..22822c0 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,6 @@ Role Variables - `libvirt_vm_arch`: CPU architecture, default is `x86_64`. -- `libvirt_vm_enable_efi_support`: Whether to enable EFI support. By default this - will enabled if any of the declared VMs specify the boot_firmware as efi. The - certificates and keys needed to enable secure boot are currently only installed - on RedHat derived distributions. See: [qemu-ovmf-secureboot](https://github.com/puiterwijk/qemu-ovmf-secureboot) - for details of the certificates and keys that are installed. - - `libvirt_vms`: list of VMs to be created/destroyed. Each one may have the following attributes: diff --git a/defaults/main.yml b/defaults/main.yml index 72888a2..4e8fe7f 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -34,9 +34,6 @@ libvirt_ovmf_vars_generator_output_path: /var/lib/libvirt/qemu/ # Prefix of generated variable file name. The checksum of the input will be appended. libvirt_ovmf_vars_generator_output_prefix: ovmf_vars_enrolled_ -# Whether to enable EFI support. -libvirt_vm_enable_efi_support: "{{ 'efi' in (libvirt_vms | map(attribute='boot_firmware') | map('lower')) }}" - # A list of specifications of VMs to be created. # For backwards compatibility, libvirt_vms defaults to a singleton list using # the values of the deprecated variables below. diff --git a/tasks/main.yml b/tasks/main.yml index 31e48fe..cbdc4f3 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,7 +1,5 @@ --- -- include_tasks: setup.yml - - include_tasks: autodetect.yml # We don't need to know the engine and emulator if we're not creating any new # VMs. diff --git a/tasks/setup.yml b/tasks/setup.yml deleted file mode 100644 index a895fd9..0000000 --- a/tasks/setup.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- - -- name: Gather os specific variables - include_vars: "{{ item }}" - with_first_found: - - files: - - "{{ ansible_distribution }}-{{ ansible_distribution_major_version}}.yml" - - "{{ ansible_distribution }}.yml" - - "{{ ansible_os_family }}.yml" - skip: true - tags: vars - -- name: Install custom yum repositories - # Although argument splatting is marked as deprecated: - # - # [DEPRECATION WARNING]: Using variables for task params is unsafe, - # especially if the variables come from an external source like facts. This - # feature will be removed in a future release. - # - # The core team had a a change of heart and it is actually being preserved: - # https://github.com/ansible/ansible/pull/43798 - yum_repository: "{{ item }}" - loop: "{{ libvirt_vm_custom_yum_repos | default([]) }}" - become: true - -- name: Install custom packages - package: - name: "{{ item }}" - state: present - loop: "{{ libvirt_vm_extra_packages }}" - diff --git a/vars/Debian.yml b/vars/Debian.yml index 3f87215..394d226 100644 --- a/vars/Debian.yml +++ b/vars/Debian.yml @@ -7,13 +7,6 @@ libvirt_vm_qemu_user: libvirt-qemu # The environment passed to virt_volume.sh libvirt_vm_volume_creation_env: {} -# Packages that are only necessary if you require EFI support -libvirt_vm_extra_packages_efi: - - ovmf - -# List of extra packages to install -libvirt_vm_extra_packages: "{{ libvirt_vm_extra_packages_efi if libvirt_vm_enable_efi_support else [] | unique }}" - # Path to template OVMF efi variable store. A copy will be created # for each VM created. libvirt_vm_ovmf_efi_variable_store_path: /usr/share/OVMF/OVMF_VARS.fd diff --git a/vars/RedHat.yml b/vars/RedHat.yml index 1981c65..0d6f2c3 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -9,14 +9,6 @@ libvirt_vm_volume_creation_env: VOLUME_GROUP: qemu VOLUME_OWNER: qemu -# Packages that are only necessary if you require EFI support -libvirt_vm_extra_packages_efi: - - edk2.git-ovmf-x64 # Official OVMF package doesn't boot (CentOS 7.5) - - qemu-kvm-ev # Need smm support for secure boot - -# List of extra packages to install -libvirt_vm_extra_packages: "{{ libvirt_vm_extra_packages_efi if libvirt_vm_enable_efi_support else [] | unique }}" - # Path to template OVMF efi variable store. A copy will be created # for each VM created. # note(wszumski): official package path is /usr/share/OVMF/OVMF_VARS.fd @@ -30,17 +22,3 @@ libvirt_vm_ovmf_efi_firmware_path: /usr/share/edk2.git/ovmf-x64/OVMF_CODE-need-s # note(wszumski): official package path is /usr/share/OVMF/UefiShell.iso libvirt_vm_ovmf_uefi_shell_iso_path: /usr/share/edk2.git/ovmf-x64/UefiShell.iso -# Add custom repository as OVMF package seems to be broken -libvirt_vm_custom_yum_repos_efi: - - name: qemu-firmware-jenkins - description: upstream OVMF firmware images - baseurl: https://www.kraxel.org/repos/jenkins/ - gpgcheck: no - # Need an updated version of qemu with smm support - - name: centos-qemu-ev - description: CentOS-$releasever - QEMU EV - baseurl: http://mirror.centos.org/$contentdir/$releasever/virt/$basearch/kvm-common/ - gpgcheck: yes - -libvirt_vm_custom_yum_repos: "{{ libvirt_vm_custom_yum_repos_efi if libvirt_vm_enable_efi_support else [] | unique }}" - From fdbdbe2e5e50104d4e8c6b8def9eb2104cb02604 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Tue, 23 Oct 2018 09:12:46 +0000 Subject: [PATCH 12/19] Remove trailing whitespace --- tasks/prepare-secure-boot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/prepare-secure-boot.yml b/tasks/prepare-secure-boot.yml index acd5d6c..d03d9af 100644 --- a/tasks/prepare-secure-boot.yml +++ b/tasks/prepare-secure-boot.yml @@ -98,7 +98,7 @@ when: not generated_ovmf.stat.exists - name: Ensure libvirt qemu can access the variable template - copy: + copy: src: "{{ ovmf_enrolled_variables_temp_output_path }}" dest: "{{ ovmf_enrolled_variables_path }}" owner: "{{ libvirt_vm_qemu_user }}" From 8da41b5e8cfac98165a742779c2f3ce3b74d3a8a Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Tue, 23 Oct 2018 16:21:18 +0000 Subject: [PATCH 13/19] Add option to disable secure boot --- tasks/main.yml | 1 + tasks/vm.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/tasks/main.yml b/tasks/main.yml index cbdc4f3..1bc9b46 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -32,6 +32,7 @@ enable_feature_acpi: "{{ vm.enable_feature_acpi | default(enable_feature_acpi_default, true) }}" enable_feature_smm_default: "{{ true if boot_firmware == 'efi' else false }}" enable_feature_smm: "{{ vm.enable_feature_smm | default(enable_feature_smm_default, true) }}" + enable_secure_boot: "{{ vm.enable_secure_boot | default(false) | bool }}" with_items: "{{ libvirt_vms }}" loop_control: loop_var: vm diff --git a/tasks/vm.yml b/tasks/vm.yml index 16bf5db..03a82dc 100644 --- a/tasks/vm.yml +++ b/tasks/vm.yml @@ -30,6 +30,7 @@ include_tasks: prepare-secure-boot.yml when: - boot_firmware == "efi" + - enable_secure_boot - libvirt_vm_ovmf_uefi_shell_iso_path is defined - name: Ensure the VM is defined From 06d33323e905852b31cc69f7f1c3871201b30086 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Wed, 24 Oct 2018 14:43:53 +0000 Subject: [PATCH 14/19] Default to software emulation if target architecture != host_architecture The qemu-kvm binary only supports the host architecture. We must therefore use the qemu-system- binaries when the target architecture is not the same as the host architecture. Although it may be possible that the host CPU may support acceleration for a foreign architecture, I do not currently know of any chips that support this functionality. For this reason, we default to software emulation. --- tasks/autodetect.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tasks/autodetect.yml b/tasks/autodetect.yml index a29647c..89b1ddf 100644 --- a/tasks/autodetect.yml +++ b/tasks/autodetect.yml @@ -14,7 +14,18 @@ - name: Set a fact containing the virtualisation engine set_fact: - libvirt_vm_engine: "{% if stat_kvm.stat.exists %}kvm{% else %}qemu{% endif %}" + libvirt_vm_engine: >- + {%- if ansible_architecture != libvirt_vm_arch -%} + {# Virtualisation instructions are generally available only for the host + architecture. Ideally we would test for virtualisation instructions, eg. vt-d + as it is possible that another architecture could support these even + if the emulated cpu architecture is not the same. #} + qemu + {%- elif stat_kvm.stat.exists -%} + kvm + {%- else -%} + qemu + {%- endif -%} when: libvirt_vm_engine is none - name: Detect the virtualisation emulator From ea6989f328d92483c96f366b7548abda1419da6b Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Wed, 24 Oct 2018 14:58:12 +0000 Subject: [PATCH 15/19] Always undefine a VM before defining it It seems that the virt module does not take into account changes to the templated vm.xml.j2 file. As such, changes to variables used within this template are not propagated to libvirt i.e the output of virsh dumpxml remains the same before and after the application of define. --- tasks/vm.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tasks/vm.yml b/tasks/vm.yml index 03a82dc..55a61e5 100644 --- a/tasks/vm.yml +++ b/tasks/vm.yml @@ -33,6 +33,19 @@ - enable_secure_boot - libvirt_vm_ovmf_uefi_shell_iso_path is defined +- name: Undefine libvirt machine if already defined + # Otherwise vm.xml.j2 will not be updated when variables are changed + # + # note(wszumski): the virt module does not seem to support + # removing vms with nvram defined - as a workaround, use the + # virsh cli directly. It may be better to detect if dumpxml + # actually contains an nvram element rather than relying on + # boot_firmware having the correct value. + command: virsh -c qemu:///system undefine{% if boot_firmware == 'efi' %} --nvram{% endif %} {{ vm.name }} + become: true + register: result + failed_when: result.rc != 0 and "no domain with matching name" not in result.stderr + - name: Ensure the VM is defined virt: name: "{{ vm.name }}" From 547a03dc23b83e3448c99f79923984398e67d1b5 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Wed, 24 Oct 2018 15:05:49 +0000 Subject: [PATCH 16/19] Use q35 machine type for EFI based booting This is a requirement for smm and secureboot, see: https://github.com/tianocore/edk2/tree/master/OvmfPkg and can be used with and without kvm. --- tasks/main.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tasks/main.yml b/tasks/main.yml index 1bc9b46..c585d15 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -19,7 +19,14 @@ vars: console_log_enabled: "{{ vm.console_log_enabled | default(false) }}" console_log_path: "{{ vm.console_log_path | default(libvirt_vm_default_console_log_dir + '/' + vm.name + '-console.log', true) }}" - machine_default: "{{ ('q35' if boot_firmware == 'efi' else none) if libvirt_vm_engine == 'kvm' else 'pc' }}" + machine_default: >- + {%- if boot_firmware == 'efi' -%} + q35 + {%- elif libvirt_vm_engine == 'kvm' -%} + none + {%- else -%} + pc + {%- endif -%} machine: "{{ vm.machine | default(machine_default, true) }}" cpu_mode_default: "{{ 'host-passthrough' if libvirt_vm_engine == 'kvm' else 'host-model' }}" cpu_mode: "{{ vm.cpu_mode | default(cpu_mode_default, true) }}" From 5bb890d1ab7f2da5d2802baf6952127ed8c756e1 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Wed, 24 Oct 2018 15:09:42 +0000 Subject: [PATCH 17/19] SMM defaults to enabled when secure boot is enabled SMM is requirement for secure boot, see: https://github.com/tianocore/edk2/blob/a8b5750901faa63ff5570634851e648b8e335e5a/OvmfPkg/README --- tasks/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/main.yml b/tasks/main.yml index c585d15..9402300 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -37,9 +37,9 @@ boot_firmware: "{{ vm.boot_firmware | default('bios', true) | lower }}" enable_feature_acpi_default: "{{ true if boot_firmware == 'efi' else false }}" enable_feature_acpi: "{{ vm.enable_feature_acpi | default(enable_feature_acpi_default, true) }}" - enable_feature_smm_default: "{{ true if boot_firmware == 'efi' else false }}" + enable_feature_smm_default: "{{ enable_secure_boot }}" enable_feature_smm: "{{ vm.enable_feature_smm | default(enable_feature_smm_default, true) }}" - enable_secure_boot: "{{ vm.enable_secure_boot | default(false) | bool }}" + enable_secure_boot: "{{ vm.enable_secure_boot | default(false, true) | bool }}" with_items: "{{ libvirt_vms }}" loop_control: loop_var: vm From 923bf751cc4072b1a915c368bed6cb791978dcca Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Wed, 24 Oct 2018 15:15:28 +0000 Subject: [PATCH 18/19] Auto detection now relies on virtualisation features This is so we can use a newer version of qemu if secure boot is enabled. The version shipped in CentOS 7.5 does not support SMM which is a requirement of secure boot. --- tasks/autodetect.yml | 33 +++++++++++++++++---------------- tasks/detect-kvm.yml | 16 ++++++++++++++++ tasks/main.yml | 7 ------- tasks/vm.yml | 14 ++++++++++++++ templates/vm.xml.j2 | 2 +- 5 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 tasks/detect-kvm.yml diff --git a/tasks/autodetect.yml b/tasks/autodetect.yml index 89b1ddf..3ac188e 100644 --- a/tasks/autodetect.yml +++ b/tasks/autodetect.yml @@ -30,21 +30,11 @@ - name: Detect the virtualisation emulator block: - - block: - - name: Detect the KVM emulator binary path - stat: - path: "{{ item }}" - register: kvm_emulator_result - with_items: - - /usr/bin/kvm - - /usr/bin/qemu-kvm - - /usr/libexec/qemu-kvm + - name: Ensure old value stored in detected_libvirt_vm_emulator is cleared + set_fact: + detected_libvirt_vm_emulator: none - - name: Set a fact containing the KVM emulator binary path - set_fact: - libvirt_vm_emulator: "{{ item.item }}" - with_items: "{{ kvm_emulator_result.results }}" - when: item.stat.exists + - include_tasks: detect-kvm.yml when: libvirt_vm_engine == 'kvm' - block: @@ -55,11 +45,22 @@ - name: Set a fact containing the QEMU emulator binary path set_fact: - libvirt_vm_emulator: "{{ qemu_emulator_result.stdout }}" + detected_libvirt_vm_emulator: "{{ qemu_emulator_result.stdout }}" + + - name: Override the QEMU emulator binary path on RedHat based distros + # CentOS 7.5 ships qemu-system-x86-2.0.0-1.el7.6.x86_64, this + # does not have smm support. We can use the qemu-kvm binary + # from SIG virtualization repository. + include_tasks: detect-kvm.yml + when: + - enable_feature_smm + - ansible_os_family == "RedHat" + - ansible_architecture == libvirt_vm_arch + when: libvirt_vm_engine == 'qemu' - name: Fail if unable to detect the emulator fail: msg: Unable to detect emulator for engine {{ libvirt_vm_engine }}. - when: libvirt_vm_emulator is none + when: detected_libvirt_vm_emulator is none when: libvirt_vm_emulator is none diff --git a/tasks/detect-kvm.yml b/tasks/detect-kvm.yml new file mode 100644 index 0000000..e7a5120 --- /dev/null +++ b/tasks/detect-kvm.yml @@ -0,0 +1,16 @@ +--- + +- name: Detect the KVM emulator binary path + stat: + path: "{{ item }}" + register: kvm_emulator_result + with_items: + - /usr/bin/kvm + - /usr/bin/qemu-kvm + - /usr/libexec/qemu-kvm + +- name: Set a fact containing the KVM emulator binary path + set_fact: + detected_libvirt_vm_emulator: "{{ item.item }}" + with_items: "{{ kvm_emulator_result.results }}" + when: item.stat.exists diff --git a/tasks/main.yml b/tasks/main.yml index 9402300..416a88b 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,12 +1,5 @@ --- -- include_tasks: autodetect.yml - # We don't need to know the engine and emulator if we're not creating any new - # VMs. - when: >- - (libvirt_vms | selectattr('state', 'defined') - | selectattr('state', 'equalto', 'absent') | list) != libvirt_vms - - include_tasks: volumes.yml vars: volumes: "{{ vm.volumes | default([], true) }}" diff --git a/tasks/vm.yml b/tasks/vm.yml index 55a61e5..6bf940d 100644 --- a/tasks/vm.yml +++ b/tasks/vm.yml @@ -9,6 +9,20 @@ skip: true tags: vars +- include_tasks: autodetect.yml + # We include this here as detection depends on the emulation features that + # are requested. We don't need to know the engine and emulator if we're + # not creating any newv VMs. + when: >- + (libvirt_vms | selectattr('state', 'defined') + | selectattr('state', 'equalto', 'absent') | list) != libvirt_vms + +- name: Set fact containing libvirt emulator + set_fact: + # The detected emulator may change between VM, but always prefer an explictly + # requested emulator + emulator: "{{ libvirt_vm_emulator | default(detected_libvirt_vm_emulator, true) }}" + - name: Ensure the VM console log directory exists file: path: "{{ console_log_path | dirname }}" diff --git a/templates/vm.xml.j2 b/templates/vm.xml.j2 index 4ca7a18..97cbfa6 100644 --- a/templates/vm.xml.j2 +++ b/templates/vm.xml.j2 @@ -31,7 +31,7 @@ - {{ libvirt_vm_emulator }} + {{ emulator }} {% for volume in volumes %} From 93a9ed704b89d12b6598c6e96c6c6f04fbad7ea3 Mon Sep 17 00:00:00 2001 From: Will Szumski Date: Wed, 24 Oct 2018 15:18:33 +0000 Subject: [PATCH 19/19] Use pure efi version of OVMF if SMM is disabled. SMM is a requirement to use the needs-SMM variant and qemu will hang on boot if SMM is disabled. --- vars/RedHat.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/vars/RedHat.yml b/vars/RedHat.yml index 0d6f2c3..1489c04 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -12,11 +12,21 @@ libvirt_vm_volume_creation_env: # Path to template OVMF efi variable store. A copy will be created # for each VM created. # note(wszumski): official package path is /usr/share/OVMF/OVMF_VARS.fd -libvirt_vm_ovmf_efi_variable_store_path: /usr/share/edk2.git/ovmf-x64/OVMF_VARS-need-smm.fd +libvirt_vm_ovmf_efi_variable_store_path: >- + {%- if enable_feature_smm -%} + /usr/share/edk2.git/ovmf-x64/OVMF_VARS-need-smm.fd + {%- else -%} + /usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd + {%- endif -%} # Path to OVMF efi firmware # note(wszumski): official package path is /usr/share/OVMF/OVMF_CODE.secboot.fd -libvirt_vm_ovmf_efi_firmware_path: /usr/share/edk2.git/ovmf-x64/OVMF_CODE-need-smm.fd +libvirt_vm_ovmf_efi_firmware_path: >- + {%- if enable_feature_smm -%} + /usr/share/edk2.git/ovmf-x64/OVMF_CODE-need-smm.fd + {%- else -%} + /usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd + {%- endif -%} # Path to iso containing signing keys # note(wszumski): official package path is /usr/share/OVMF/UefiShell.iso