Skip to content

Commit 31ff7ce

Browse files
committed
driver/secheduler/docs for Adds Pick guest CPU architecture based on
host arch in libvirt driver support This is split 2 of 3 for the architecture emulation feature. This implements emulated multi-architecture support through qemu within OpenStack Nova. Additional config variable check to pull host architecture into hw_architecture field for emulation checks to be made. Adds a custom function that simply performs a check for hw_emulation_architecture field being set, allowing for core code to function as normal while enabling a simple check to enable emulated architectures to follow the same path as all multi-arch support already established for physical nodes but instead levaraging qemu which allows for the overall emulation. Added check for domain xml unit test to strip arch from the os tag, as it is not required uefi checks, and only leveraged for emulation checks. Added additional test cases test_driver validating emulation functionality with checking hw_emulation_architecture against the os_arch/hw_architecture field. Added required os-traits and settings for scheduler request_filter. Added RISCV64 to architecture enum for better support in driver. Implements: blueprint pick-guest-arch-based-on-host-arch-in-libvirt-driver Closes-Bug: 1863728 Change-Id: Ia070a29186c6123cf51e1b17373c2dc69676ae7c Signed-off-by: Jonathan Race <[email protected]>
1 parent 79887a6 commit 31ff7ce

File tree

10 files changed

+319
-18
lines changed

10 files changed

+319
-18
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
..
2+
Licensed under the Apache License, Version 2.0 (the "License"); you may
3+
not use this file except in compliance with the License. You may obtain
4+
a copy of the License at
5+
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10+
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11+
License for the specific language governing permissions and limitations
12+
under the License.
13+
14+
============================================================================
15+
hw_emulation_architecture - Configuring QEMU instance emulation architecture
16+
============================================================================
17+
18+
.. versionadded:: 25.0.0 (Yoga)
19+
20+
The libvirt driver now allows for handling of specific cpu architectures
21+
when defined within the image metadata properties, to be emulated through
22+
QEMU.
23+
24+
Added ``hw_emulation_architecture`` as an available image_meta property.
25+
26+
.. note::
27+
28+
The following only applies to environments using libvirt compute hosts.
29+
and should be considered experimental in its entirety, during its first
30+
release as a feature.
31+
32+
Introduction
33+
------------
34+
35+
This capability is to fill a need with environments that do not have the
36+
capability to support the various cpu architectures that are present today
37+
with physical hardware. A small subset of architectures that are supported
38+
both within libvirt and QEMU have been selected as prime candidates for
39+
emulation support.
40+
41+
While support has been added for the below base architectures, this does
42+
not guarantee that every subset or custom operating system that leverages
43+
one of these architectures will function.
44+
45+
Configure
46+
---------
47+
48+
-------------------
49+
QEMU Binary Support
50+
-------------------
51+
52+
To ensure that libvirt and QEMU can properly handle the level of cpu
53+
emulation desired by the end-user, you are required to install the specific
54+
``qemu-system-XXX``, ``qemu-efi-arm``, ``qemu-efi-aarch64`` binaries on the
55+
compute nodes that will be providing support.
56+
57+
---------------
58+
Console Support
59+
---------------
60+
61+
Consideration need to be made in regards to which architectures you want to
62+
support, as there are limitations on support through spice, novnc, and
63+
serial. All testing and validation has been done to ensure that spice and
64+
serial connections function as expected.
65+
66+
- ``AARCH64`` - Spice & Serial
67+
- ``S390X`` - Serial
68+
- ``PPC64LE`` - Spice & Serial
69+
- ``MIPSEL`` - untested
70+
71+
--------------------------------
72+
Supported Emulated Architectures
73+
--------------------------------
74+
75+
The supported emulated architectures require specific image meta
76+
properties to be set in order to trigger the proper settings to be
77+
configured by libvirtd.
78+
79+
For end users the emulation architecture of an instance is controlled by the
80+
selection of an image with the ``hw_emulation_architecture`` image metadata
81+
property set.
82+
83+
84+
AARCH64
85+
~~~~~~~
86+
87+
``Tested and Validated as functional``
88+
89+
.. code-block:: shell
90+
91+
$ openstack image set --property hw_emulation_architecture=aarch64 $IMAGE
92+
$ openstack image set --property hw_machine_type=virt $IMAGE
93+
$ openstack image set --property hw_firmware_type=uefi $IMAGE
94+
95+
S390x
96+
~~~~~
97+
98+
``Tested and Validated as functional``
99+
100+
.. code-block:: shell
101+
102+
$ openstack image set --property hw_emulation_architecture=s390x $IMAGE
103+
$ openstack image set --property hw_machine_type=s390-ccw-virtio $IMAGE
104+
$ openstack image set --property hw_video_model=virtio $IMAGE
105+
106+
PPC64LE
107+
~~~~~~~
108+
109+
``Tested and Validated as functional``
110+
111+
.. code-block:: shell
112+
113+
$ openstack image set --property hw_emulation_architecture=ppc64le $IMAGE
114+
$ openstack image set --property hw_machine_type=pseries $IMAGE
115+
116+
117+
MIPSEL
118+
~~~~~~
119+
120+
``Testing and validation is ongoing to overcome PCI issues``
121+
122+
.. note::
123+
124+
Support is currently impacted, one current method for support is manually
125+
patching and compiling as defined in libvirt bug
126+
`XML error: No PCI buses available`_.
127+
128+
.. _`XML error: No PCI buses available`: https://bugzilla.redhat.com/show_bug.cgi?id=1432101
129+
130+
.. code-block:: shell
131+
132+
$ openstack image set --property hw_emulation_architecture=mipsel $IMAGE
133+
$ openstack image set --property hw_machine_type=virt $IMAGE

doc/source/admin/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,4 @@ Once you are running nova, the following information is extremely useful.
227227
upgrades
228228
node-down
229229
hw-machine-type
230+
hw-emulation-architecture

nova/scheduler/request_filter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ def transform_image_metadata(ctxt, request_spec):
212212
'hw_disk_bus': 'COMPUTE_STORAGE_BUS',
213213
'hw_video_model': 'COMPUTE_GRAPHICS_MODEL',
214214
'hw_vif_model': 'COMPUTE_NET_VIF_MODEL',
215+
'hw_architecture': 'HW_ARCH',
216+
'hw_emulation_architecture': 'COMPUTE_ARCH',
215217
}
216218

217219
trait_names = []

nova/tests/functional/libvirt/test_uefi.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# under the License.
1515

1616
import datetime
17+
import re
1718

1819
from lxml import etree
1920
from oslo_log import log as logging
@@ -47,6 +48,8 @@ def test_create_server(self):
4748
orig_create = nova.virt.libvirt.guest.Guest.create
4849

4950
def fake_create(cls, xml, host):
51+
xml = re.sub('type arch.*machine',
52+
'type machine', xml)
5053
tree = etree.fromstring(xml)
5154
self.assertXmlEqual(
5255
"""

nova/tests/unit/scheduler/test_request_filter.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,13 +406,15 @@ def test_compute_status_filter(self, mock_log):
406406
self.assertIn('took %.1f seconds', log_lines[1])
407407

408408
@mock.patch.object(request_filter, 'LOG', new=mock.Mock())
409-
def test_transform_image_metadata(self):
409+
def test_transform_image_metadata_x86(self):
410410
self.flags(image_metadata_prefilter=True, group='scheduler')
411411
properties = objects.ImageMetaProps(
412412
hw_disk_bus=objects.fields.DiskBus.SATA,
413413
hw_cdrom_bus=objects.fields.DiskBus.IDE,
414414
hw_video_model=objects.fields.VideoModel.QXL,
415-
hw_vif_model=network_model.VIF_MODEL_VIRTIO
415+
hw_vif_model=network_model.VIF_MODEL_VIRTIO,
416+
hw_architecture=objects.fields.Architecture.X86_64,
417+
hw_emulation_architecture=objects.fields.Architecture.AARCH64
416418
)
417419
reqspec = objects.RequestSpec(
418420
image=objects.ImageMeta(properties=properties),
@@ -426,6 +428,36 @@ def test_transform_image_metadata(self):
426428
'COMPUTE_NET_VIF_MODEL_VIRTIO',
427429
'COMPUTE_STORAGE_BUS_IDE',
428430
'COMPUTE_STORAGE_BUS_SATA',
431+
'HW_ARCH_X86_64',
432+
'COMPUTE_ARCH_AARCH64',
433+
}
434+
self.assertEqual(expected, reqspec.root_required)
435+
436+
@mock.patch.object(request_filter, 'LOG', new=mock.Mock())
437+
def test_transform_image_metadata_aarch64(self):
438+
self.flags(image_metadata_prefilter=True, group='scheduler')
439+
properties = objects.ImageMetaProps(
440+
hw_disk_bus=objects.fields.DiskBus.SATA,
441+
hw_cdrom_bus=objects.fields.DiskBus.IDE,
442+
hw_video_model=objects.fields.VideoModel.QXL,
443+
hw_vif_model=network_model.VIF_MODEL_VIRTIO,
444+
hw_architecture=objects.fields.Architecture.AARCH64,
445+
hw_emulation_architecture=objects.fields.Architecture.X86_64
446+
)
447+
reqspec = objects.RequestSpec(
448+
image=objects.ImageMeta(properties=properties),
449+
flavor=objects.Flavor(extra_specs={}),
450+
)
451+
self.assertTrue(
452+
request_filter.transform_image_metadata(None, reqspec)
453+
)
454+
expected = {
455+
'COMPUTE_GRAPHICS_MODEL_QXL',
456+
'COMPUTE_NET_VIF_MODEL_VIRTIO',
457+
'COMPUTE_STORAGE_BUS_IDE',
458+
'COMPUTE_STORAGE_BUS_SATA',
459+
'HW_ARCH_AARCH64',
460+
'COMPUTE_ARCH_X86_64',
429461
}
430462
self.assertEqual(expected, reqspec.root_required)
431463

nova/tests/unit/virt/libvirt/test_driver.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5218,7 +5218,8 @@ def test_check_uefi_support_aarch64(self):
52185218
self.mock_uname.return_value = fakelibvirt.os_uname(
52195219
'Linux', '', '5.4.0-0-generic', '', fields.Architecture.AARCH64)
52205220
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
5221-
self.assertTrue(drvr._check_uefi_support(None))
5221+
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
5222+
self.assertTrue(drvr._check_uefi_support(image_meta))
52225223

52235224
def test_get_guest_config_with_block_device(self):
52245225
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
@@ -5769,6 +5770,7 @@ def test_create_serial_console_devices_based_on_arch(
57695770
self.flags(enabled=True, group='serial_console')
57705771
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
57715772
instance = objects.Instance(**self.test_instance)
5773+
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
57725774

57735775
expected = {
57745776
fields.Architecture.X86_64: vconfig.LibvirtConfigGuestSerial,
@@ -5781,7 +5783,10 @@ def test_create_serial_console_devices_based_on_arch(
57815783

57825784
guest = vconfig.LibvirtConfigGuest()
57835785
drvr._create_consoles(
5784-
guest_cfg=guest, instance=instance, flavor={}, image_meta={})
5786+
guest_cfg=guest,
5787+
instance=instance,
5788+
flavor={},
5789+
image_meta=image_meta)
57855790
self.assertEqual(1, len(guest.devices))
57865791
console_device = guest.devices[0]
57875792
self.assertIsInstance(console_device, device_type)
@@ -5993,9 +5998,13 @@ def _test_consoles(arch_to_mock, serial_enabled,
59935998
self.flags(enabled=serial_enabled, group='serial_console')
59945999
guest_cfg = vconfig.LibvirtConfigGuest()
59956000
instance = objects.Instance(**self.test_instance)
6001+
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
59966002

59976003
drvr._create_consoles(
5998-
guest_cfg, instance=instance, flavor=None, image_meta=None)
6004+
guest_cfg,
6005+
instance=instance,
6006+
flavor=None,
6007+
image_meta=image_meta)
59996008

60006009
self.assertEqual(1, len(guest_cfg.devices))
60016010
device = guest_cfg.devices[0]
@@ -7975,6 +7984,33 @@ def test_get_guest_cpu_config_qemu_custom_aarch64(self):
79757984
self.assertIsInstance(conf.cpu, vconfig.LibvirtConfigGuestCPU)
79767985
self.assertEqual(conf.cpu.mode, 'custom')
79777986

7987+
def test_get_x86_64_hw_emulated_architecture_aarch64(self):
7988+
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
7989+
image_meta = objects.ImageMeta.from_dict({
7990+
"disk_format": "raw",
7991+
'properties': {
7992+
'hw_architecture': 'x86_64',
7993+
'hw_emulation_architecture': 'aarch64',
7994+
'hw_machine_type': 'virt',
7995+
'hw_firmware_type': 'uefi',
7996+
}})
7997+
7998+
self.assertEqual(drvr._check_emulation_arch(image_meta),
7999+
'aarch64')
8000+
8001+
def test_get_x86_64_hw_emulated_architecture_ppc64(self):
8002+
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
8003+
image_meta = objects.ImageMeta.from_dict({
8004+
"disk_format": "raw",
8005+
'properties': {
8006+
'hw_architecture': 'x86_64',
8007+
'hw_emulation_architecture': 'ppc64le',
8008+
'hw_machine_type': 'pseries',
8009+
}})
8010+
8011+
self.assertEqual(drvr._check_emulation_arch(image_meta),
8012+
'ppc64le')
8013+
79788014
@mock.patch.object(libvirt_driver.LOG, 'warning')
79798015
def test_get_guest_cpu_config_custom_with_extra_flags(self,
79808016
mock_warn):

nova/virt/libvirt/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,6 +2823,7 @@ def __init__(self, **kwargs):
28232823
self.os_init_path = None
28242824
self.os_boot_dev = []
28252825
self.os_smbios = None
2826+
self.os_arch = None
28262827
self.os_mach_type = None
28272828
self.os_bootmenu = False
28282829
self.devices = []
@@ -2865,6 +2866,8 @@ def _format_os(self, root):
28652866
os.set("firmware", self.os_firmware)
28662867

28672868
type_node = self._text_node("type", self.os_type)
2869+
if self.os_arch is not None:
2870+
type_node.set("arch", self.os_arch)
28682871
if self.os_mach_type is not None:
28692872
type_node.set("machine", self.os_mach_type)
28702873
os.append(type_node)

0 commit comments

Comments
 (0)