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