From fc1b42c60d19e148a746bc171a71ec13dd39ecfd Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Wed, 2 Feb 2022 11:17:57 +0000 Subject: [PATCH] Support UEFI boot mode Adds support for using UEFI boot mode for nodes. This is done via node capabilities, as it is in Ironic. The default boot mode is now configurable via the default_boot_mode variable. The default boot mode remains legacy BIOS for now, although this may change. Updates the existing CI jobs, with the OVS jobs using BIOS boot mode, and the linuxbridge jobs using UEFI boot mode. Depends-On: https://github.com/stackhpc/ansible-role-libvirt-vm/pull/83 Depends-On: https://github.com/stackhpc/ansible-role-libvirt-host/pull/50 Depends-On: https://review.opendev.org/c/openstack/kayobe/+/827486 Change-Id: Ifaf95ecfd4f6e925d3c69d4b324fdf2cd6b0ca52 --- ansible/filter_plugins/tenks.py | 49 +++++++++++++++++++ ansible/host_setup.yml | 7 +++ ansible/host_vars/localhost | 4 ++ ansible/node_instantiation.yml | 1 + ansible/roles/ironic-enrolment/tasks/node.yml | 10 ++-- doc/source/configuration.rst | 5 ++ doc/source/development.rst | 6 --- .../templates/tenks-overrides.yml.j2 | 2 + releasenotes/notes/uefi-7a19ff8a549a3e9e.yaml | 6 +++ zuul.d/base.yaml | 6 ++- zuul.d/jobs.yaml | 16 +++--- zuul.d/project.yaml | 16 +++--- 12 files changed, 99 insertions(+), 29 deletions(-) create mode 100644 releasenotes/notes/uefi-7a19ff8a549a3e9e.yaml diff --git a/ansible/filter_plugins/tenks.py b/ansible/filter_plugins/tenks.py index eb048b5..4857da5 100644 --- a/ansible/filter_plugins/tenks.py +++ b/ansible/filter_plugins/tenks.py @@ -45,6 +45,7 @@ class FilterModule(object): 'set_libvirt_interfaces': set_libvirt_interfaces, 'set_libvirt_start_params': set_libvirt_start_params, 'set_libvirt_volume_pool': set_libvirt_volume_pool, + 'set_libvirt_boot_firmware': set_libvirt_boot_firmware, # Miscellaneous filters. 'size_string_to_gb': size_string_to_gb, @@ -89,6 +90,54 @@ def set_libvirt_volume_pool(context, node): return node +# The following function has been adapted from Ironic: +# https://opendev.org/openstack/ironic/src/commit/5f6d753b2c334e4f404818d5e94a145b60244736/ironic/drivers/utils.py#L229 + +def _capabilities_to_dict(capabilities): + """Parse the capabilities string into a dictionary + + :param capabilities: the capabilities of the node as a formatted string. + :raises: InvalidParameterValue if capabilities is not an string or has a + malformed value + """ + capabilities_dict = {} + if capabilities: + if not isinstance(capabilities, str): + raise AnsibleFilterError( + "Value of 'capabilities' must be string. Got %s" + % type(capabilities)) + try: + for capability in capabilities.split(','): + key, value = capability.split(':') + capabilities_dict[key] = value + except ValueError: + raise AnsibleFilterError( + "Malformed capabilities value: %s" % capability + ) + + return capabilities_dict + + +@contextfilter +def set_libvirt_boot_firmware(context, node): + """Set the boot firmware for a node.""" + default_boot_mode = _get_hostvar(context, 'default_boot_mode', + inventory_hostname='localhost') + properties = node.get('ironic_config', {}).get('properties', {}) + caps = properties.get('capabilities', '') + caps_dict = _capabilities_to_dict(caps) + boot_mode = caps_dict.get('boot_mode', default_boot_mode) + if boot_mode not in ['bios', 'uefi']: + raise AnsibleFilterError( + "Unexpected boot firmware. Must be one of 'bios' or 'uefi'. Got " + "'%s'" % boot_mode + ) + boot_mode_to_firmware = {'uefi': 'efi', 'bios': 'bios'} + node['boot_firmware'] = boot_mode_to_firmware[boot_mode] + + return node + + def set_libvirt_start_params(node): """Set the Libvirt start and autostart parameters. diff --git a/ansible/host_setup.yml b/ansible/host_setup.yml index a2e2735..82b16f9 100644 --- a/ansible/host_setup.yml +++ b/ansible/host_setup.yml @@ -38,6 +38,13 @@ libvirt_host_uri: "{{ libvirt_local_uri }}" libvirt_host_socket_dir: "{{ libvirt_custom_socket_path }}" libvirt_host_pid_path: "{{ libvirt_custom_pid_path }}" + libvirt_host_enable_efi_support: >- + {{ hostvars.localhost.tenks_state[inventory_hostname].nodes | + default([]) | + map('set_libvirt_boot_firmware') | + selectattr('boot_firmware', 'equalto', 'efi') | + list | + length > 0 }} - name: Set up Virtual BMC daemon include_role: diff --git a/ansible/host_vars/localhost b/ansible/host_vars/localhost index 10b487c..314b271 100644 --- a/ansible/host_vars/localhost +++ b/ansible/host_vars/localhost @@ -111,6 +111,10 @@ state_file_path: >- # The default Ironic driver of a node. Can be overridden per-node. default_ironic_driver: ipmi +# The default boot mode of a node. One of 'bios' or 'uefi'. Can be +# overridden per-node via properties.capabilities.boot_mode. +default_boot_mode: bios + # Maps Ironic drivers to the BMC emulation tool they support. bmc_emulators: agent_ipmitool: virtualbmc diff --git a/ansible/node_instantiation.yml b/ansible/node_instantiation.yml index 08c68f9..513b95a 100644 --- a/ansible/node_instantiation.yml +++ b/ansible/node_instantiation.yml @@ -30,4 +30,5 @@ {{ nodes | map('set_libvirt_interfaces') | map('set_libvirt_volume_pool') | map('set_libvirt_start_params') + | map('set_libvirt_boot_firmware') | list }} diff --git a/ansible/roles/ironic-enrolment/tasks/node.yml b/ansible/roles/ironic-enrolment/tasks/node.yml index 3290b15..52d431c 100644 --- a/ansible/roles/ironic-enrolment/tasks/node.yml +++ b/ansible/roles/ironic-enrolment/tasks/node.yml @@ -102,11 +102,11 @@ cpus: "{{ node.vcpus }}" memory_mb: "{{ node.memory_mb }}" local_gb: "{{ node.volumes[0].capacity | size_string_to_gb if node.volumes | length > 0 else 0 }}" - # Since we currently only support legacy BIOS boot mode, set it - # explicitly here. This is especially important since Ironic changed - # the default boot mode to UEFI in Yoga. If the capabilities field is - # provided, the boot_mode should be set explicitly. - capabilities: "boot_mode:bios" + # Set the boot mode explicitly here, since we cannot rely on a stable + # default in Ironic (it changed from legacy BIOS to UEFI in Yoga). + # If the capabilities field is provided, the boot_mode should be set + # explicitly. + capabilities: "boot_mode:{{ default_boot_mode }}" - name: Add Ironic node traits command: >- diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst index 4bfe1e7..7008e02 100644 --- a/doc/source/configuration.rst +++ b/doc/source/configuration.rst @@ -54,6 +54,11 @@ Another variable that may be useful is ``bridge_type``. This may be either created by Tenks. This may be different from the type of interfaces or bridges in ``physnet_mappings``. +The default boot mode is legacy BIOS. This may be changed to UEFI by setting +``default_boot_mode`` to ``uefi`` in a variable file. The boot mode for nodes +may be set individually via ``ironic_config.properties.capabilities.boot_mode`` +in the ``specs`` list. + Standalone Ironic ----------------- diff --git a/doc/source/development.rst b/doc/source/development.rst index bf651f0..fcaf836 100644 --- a/doc/source/development.rst +++ b/doc/source/development.rst @@ -47,12 +47,6 @@ to be implemented in future. ``ansible-playbook`` invocation with multiple parameters. It would be less clunky to introduce a simple CLI wrapper encapsulating some default commands. -* **Configurable boot modes**. Support for boot modes other than legacy BIOS - (for example, UEFI) would be useful. OpenStack Ironic supports configuration - of boot modes with the `boot_mode` parameter for certain drivers. The - Libvirt/QEMU/KVM stack supports UEFI boot with the `OVMF project - `__ - Contribution ------------ diff --git a/playbooks/tenks-deploy-teardown/templates/tenks-overrides.yml.j2 b/playbooks/tenks-deploy-teardown/templates/tenks-overrides.yml.j2 index d62f5f9..7e9dd4c 100644 --- a/playbooks/tenks-deploy-teardown/templates/tenks-overrides.yml.j2 +++ b/playbooks/tenks-deploy-teardown/templates/tenks-overrides.yml.j2 @@ -21,6 +21,8 @@ specs: - type: type0 count: 2 +default_boot_mode: {{ boot_mode }} + nova_flavors: [] physnet_mappings: diff --git a/releasenotes/notes/uefi-7a19ff8a549a3e9e.yaml b/releasenotes/notes/uefi-7a19ff8a549a3e9e.yaml new file mode 100644 index 0000000..bc3dc79 --- /dev/null +++ b/releasenotes/notes/uefi-7a19ff8a549a3e9e.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Adds support for UEFI boot mode. The default boot mode may be set via + ``default_boot_mode``. The default boot mode remains legacy BIOS, although + this may change. diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml index e4f8031..fc74c2e 100644 --- a/zuul.d/base.yaml +++ b/zuul.d/base.yaml @@ -23,13 +23,15 @@ - ^tox.ini$ - job: - name: tenks-deploy-teardown-ovs-base + name: tenks-deploy-teardown-ovs-bios-base parent: tenks-deploy-teardown-base vars: bridge_type: openvswitch + boot_mode: bios - job: - name: tenks-deploy-teardown-linuxbridge-base + name: tenks-deploy-teardown-linuxbridge-uefi-base parent: tenks-deploy-teardown-base vars: bridge_type: linuxbridge + boot_mode: uefi diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index ea78770..6772860 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -8,21 +8,21 @@ tox_envlist: alint - job: - name: tenks-deploy-teardown-ovs-centos8s - parent: tenks-deploy-teardown-ovs-base + name: tenks-deploy-teardown-ovs-bios-centos8s + parent: tenks-deploy-teardown-ovs-bios-base nodeset: centos-8-stream - job: - name: tenks-deploy-teardown-ovs-ubuntu - parent: tenks-deploy-teardown-ovs-base + name: tenks-deploy-teardown-ovs-bios-ubuntu + parent: tenks-deploy-teardown-ovs-bios-base nodeset: ubuntu-bionic - job: - name: tenks-deploy-teardown-linuxbridge-centos8s - parent: tenks-deploy-teardown-linuxbridge-base + name: tenks-deploy-teardown-linuxbridge-uefi-centos8s + parent: tenks-deploy-teardown-linuxbridge-uefi-base nodeset: centos-8-stream - job: - name: tenks-deploy-teardown-linuxbridge-ubuntu - parent: tenks-deploy-teardown-linuxbridge-base + name: tenks-deploy-teardown-linuxbridge-uefi-ubuntu + parent: tenks-deploy-teardown-linuxbridge-uefi-base nodeset: ubuntu-bionic diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index b202e24..e3ce23e 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -13,10 +13,10 @@ - openstack-tox-py38 - openstack-tox-py39 - tenks-tox-ansible-lint - - tenks-deploy-teardown-ovs-centos8s - - tenks-deploy-teardown-ovs-ubuntu - - tenks-deploy-teardown-linuxbridge-centos8s - - tenks-deploy-teardown-linuxbridge-ubuntu + - tenks-deploy-teardown-ovs-bios-centos8s + - tenks-deploy-teardown-ovs-bios-ubuntu + - tenks-deploy-teardown-linuxbridge-uefi-centos8s + - tenks-deploy-teardown-linuxbridge-uefi-ubuntu # Until we have ironic jobs using tenks, gate on the kayobe overcloud # deploy job, which uses tenks to test bare metal compute provisioning. - kayobe-overcloud-centos8s @@ -29,10 +29,10 @@ - openstack-tox-py38 - openstack-tox-py39 - tenks-tox-ansible-lint - - tenks-deploy-teardown-ovs-centos8s - - tenks-deploy-teardown-ovs-ubuntu - - tenks-deploy-teardown-linuxbridge-centos8s - - tenks-deploy-teardown-linuxbridge-ubuntu + - tenks-deploy-teardown-ovs-bios-centos8s + - tenks-deploy-teardown-ovs-bios-ubuntu + - tenks-deploy-teardown-linuxbridge-uefi-centos8s + - tenks-deploy-teardown-linuxbridge-uefi-ubuntu # Until we have ironic jobs using tenks, gate on the kayobe overcloud # deploy job, which uses tenks to test bare metal compute provisioning. - kayobe-overcloud-centos8s