Merge "libvirt: Parse the 'os' element from domainCapabilities"
This commit is contained in:
commit
3386c71fbd
|
@ -659,6 +659,10 @@ DOMCAPABILITIES_SPARC = """
|
|||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
<cpu>
|
||||
|
@ -732,6 +736,10 @@ DOMCAPABILITIES_ARMV7L = """
|
|||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
<cpu>
|
||||
|
@ -845,6 +853,10 @@ DOMCAPABILITIES_PPC = """
|
|||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
<cpu>
|
||||
|
@ -924,6 +936,10 @@ DOMCAPABILITIES_MIPS = """
|
|||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
<cpu>
|
||||
|
@ -1005,6 +1021,10 @@ DOMCAPABILITIES_MIPSEL = """
|
|||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
<cpu>
|
||||
|
@ -1089,6 +1109,10 @@ DOMCAPABILITIES_I686 = """
|
|||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
<cpu>
|
||||
|
@ -1231,9 +1255,12 @@ DOMCAPABILITIES_X86_64_TEMPLATE = """
|
|||
<arch>x86_64</arch>
|
||||
<vcpu max='255'/>
|
||||
<os supported='yes'>
|
||||
<enum name='firmware'>
|
||||
<value>efi</value>
|
||||
</enum>
|
||||
<loader supported='yes'>
|
||||
<value>/usr/share/qemu/ovmf-x86_64-ms-4m-code.bin</value>
|
||||
<value>/usr/share/qemu/ovmf-x86_64-ms-code.bin</value>
|
||||
<value>/usr/share/edk2/ovmf/OVMF_CODE.fd</value>
|
||||
<value>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</value>
|
||||
<enum name='type'>
|
||||
<value>rom</value>
|
||||
<value>pflash</value>
|
||||
|
@ -1242,6 +1269,10 @@ DOMCAPABILITIES_X86_64_TEMPLATE = """
|
|||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
<cpu>
|
||||
|
|
|
@ -3798,7 +3798,7 @@ class LibvirtConfigGuestVPMEMTest(LibvirtConfigBaseTest):
|
|||
</memory>""")
|
||||
|
||||
|
||||
class LibvirtConfigVideoModelsTests(LibvirtConfigBaseTest):
|
||||
class LibvirtConfigDomainCapsVideoModelsTests(LibvirtConfigBaseTest):
|
||||
|
||||
def test_parse_video_model(self):
|
||||
|
||||
|
@ -3822,7 +3822,7 @@ class LibvirtConfigVideoModelsTests(LibvirtConfigBaseTest):
|
|||
self.assertNotIn('gop', obj.models)
|
||||
|
||||
|
||||
class LibvirtConfigDiskBusesTests(LibvirtConfigBaseTest):
|
||||
class LibvirtConfigDomainCapsDiskBusesTests(LibvirtConfigBaseTest):
|
||||
|
||||
def test_parse_disk_buses(self):
|
||||
|
||||
|
@ -3927,6 +3927,50 @@ class LibvirtConfigDomainCapsDevicesTests(LibvirtConfigBaseTest):
|
|||
obj.video, config.LibvirtConfigDomainCapsVideoModels)
|
||||
|
||||
|
||||
class LibvirtConfigDomainCapsOSTests(LibvirtConfigBaseTest):
|
||||
|
||||
def test_parse_domain_caps_os(self):
|
||||
xml = """
|
||||
<os supported="yes">
|
||||
<enum name="firmware">
|
||||
<value>efi</value>
|
||||
</enum>
|
||||
<loader supported="yes">
|
||||
<value>/usr/share/edk2/ovmf/OVMF_CODE.fd</value>
|
||||
<value>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</value>
|
||||
<enum name="type">
|
||||
<value>rom</value>
|
||||
<value>pflash</value>
|
||||
</enum>
|
||||
<enum name="readonly">
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name="secure">
|
||||
<value>no</value>
|
||||
<value>yes</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
"""
|
||||
|
||||
obj = config.LibvirtConfigDomainCapsOS()
|
||||
obj.parse_str(xml)
|
||||
|
||||
self.assertTrue(obj.supported)
|
||||
self.assertTrue(obj.loader_supported)
|
||||
self.assertTrue(obj.uefi_autoconfig_supported)
|
||||
self.assertEqual(
|
||||
[
|
||||
'/usr/share/edk2/ovmf/OVMF_CODE.fd',
|
||||
'/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd',
|
||||
],
|
||||
obj.loader_paths,
|
||||
)
|
||||
self.assertTrue(obj.uefi_supported)
|
||||
self.assertTrue(obj.secure_boot_supported)
|
||||
|
||||
|
||||
class LibvirtConfigTPMTest(LibvirtConfigBaseTest):
|
||||
|
||||
def test_config_tpm_tis_1_2(self):
|
||||
|
|
|
@ -1259,6 +1259,189 @@ cg /cgroup/memory cg opt1,opt2 0 0
|
|||
"""
|
||||
self.assertFalse(self.host.has_hyperthreading)
|
||||
|
||||
@mock.patch(
|
||||
'nova.virt.libvirt.host.libvirt.Connection.getDomainCapabilities')
|
||||
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.getCapabilities')
|
||||
def test_supports_uefi__false(self, mock_caps, mock_domcaps):
|
||||
mock_caps.return_value = """
|
||||
<capabilities>
|
||||
<host>
|
||||
<uuid>cef19ce0-0ca2-11df-855d-b19fbce37686</uuid>
|
||||
<cpu>
|
||||
<arch>x86_64</arch>
|
||||
<vendor>Intel</vendor>
|
||||
</cpu>
|
||||
</host>
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='x86_64'/>
|
||||
</guest>
|
||||
</capabilities>
|
||||
"""
|
||||
mock_domcaps.return_value = """
|
||||
<domainCapabilities>
|
||||
<machine>pc-q35-5.1</machine>
|
||||
<arch>x86_64</arch>
|
||||
<os supported='yes'>
|
||||
<enum name='firmware'>
|
||||
<value>bios</value>
|
||||
</enum>
|
||||
<loader supported='yes'>
|
||||
<enum name='type'>
|
||||
<value>rom</value>
|
||||
</enum>
|
||||
<enum name='readonly'>
|
||||
<value>yes</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
</domainCapabilities>
|
||||
"""
|
||||
self.assertFalse(self.host.supports_uefi)
|
||||
|
||||
@mock.patch(
|
||||
'nova.virt.libvirt.host.libvirt.Connection.getDomainCapabilities')
|
||||
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.getCapabilities')
|
||||
def test_supports_uefi__true(self, mock_caps, mock_domcaps):
|
||||
mock_caps.return_value = """
|
||||
<capabilities>
|
||||
<host>
|
||||
<uuid>cef19ce0-0ca2-11df-855d-b19fbce37686</uuid>
|
||||
<cpu>
|
||||
<arch>x86_64</arch>
|
||||
<vendor>Intel</vendor>
|
||||
</cpu>
|
||||
</host>
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='x86_64'/>
|
||||
</guest>
|
||||
</capabilities>
|
||||
"""
|
||||
mock_domcaps.return_value = """
|
||||
<domainCapabilities>
|
||||
<machine>pc-q35-5.1</machine>
|
||||
<arch>x86_64</arch>
|
||||
<os supported='yes'>
|
||||
<enum name='firmware'>
|
||||
<value>efi</value>
|
||||
</enum>
|
||||
<loader supported='yes'>
|
||||
<value>/usr/share/edk2/ovmf/OVMF_CODE.fd</value>
|
||||
<enum name='type'>
|
||||
<value>rom</value>
|
||||
<value>pflash</value>
|
||||
</enum>
|
||||
<enum name='readonly'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
</domainCapabilities>
|
||||
"""
|
||||
self.assertTrue(self.host.supports_uefi)
|
||||
|
||||
@mock.patch(
|
||||
'nova.virt.libvirt.host.libvirt.Connection.getDomainCapabilities')
|
||||
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.getCapabilities')
|
||||
def test_supports_secure_boot__false(self, mock_caps, mock_domcaps):
|
||||
mock_caps.return_value = """
|
||||
<capabilities>
|
||||
<host>
|
||||
<uuid>cef19ce0-0ca2-11df-855d-b19fbce37686</uuid>
|
||||
<cpu>
|
||||
<arch>x86_64</arch>
|
||||
<vendor>Intel</vendor>
|
||||
</cpu>
|
||||
</host>
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='x86_64'/>
|
||||
</guest>
|
||||
</capabilities>
|
||||
"""
|
||||
mock_domcaps.return_value = """
|
||||
<domainCapabilities>
|
||||
<machine>pc-q35-5.1</machine>
|
||||
<arch>x86_64</arch>
|
||||
<os supported='yes'>
|
||||
<enum name='firmware'>
|
||||
<value>efi</value>
|
||||
</enum>
|
||||
<loader supported='yes'>
|
||||
<value>/usr/share/edk2/ovmf/OVMF_CODE.fd</value>
|
||||
<enum name='type'>
|
||||
<value>rom</value>
|
||||
<value>pflash</value>
|
||||
</enum>
|
||||
<enum name='readonly'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
</domainCapabilities>
|
||||
"""
|
||||
self.assertFalse(self.host.supports_secure_boot)
|
||||
|
||||
@mock.patch(
|
||||
'nova.virt.libvirt.host.libvirt.Connection.getDomainCapabilities')
|
||||
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.getCapabilities')
|
||||
def test_supports_secure_boot__true(self, mock_caps, mock_domcaps):
|
||||
mock_caps.return_value = """
|
||||
<capabilities>
|
||||
<host>
|
||||
<uuid>cef19ce0-0ca2-11df-855d-b19fbce37686</uuid>
|
||||
<cpu>
|
||||
<arch>x86_64</arch>
|
||||
<vendor>Intel</vendor>
|
||||
</cpu>
|
||||
</host>
|
||||
<guest>
|
||||
<os_type>hvm</os_type>
|
||||
<arch name='x86_64'/>
|
||||
</guest>
|
||||
</capabilities>
|
||||
"""
|
||||
mock_domcaps.return_value = """
|
||||
<domainCapabilities>
|
||||
<machine>pc-q35-5.1</machine>
|
||||
<arch>x86_64</arch>
|
||||
<os supported='yes'>
|
||||
<enum name='firmware'>
|
||||
<value>efi</value>
|
||||
</enum>
|
||||
<loader supported='yes'>
|
||||
<value>/usr/share/edk2/ovmf/OVMF_CODE.fd</value>
|
||||
<value>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</value>
|
||||
<enum name='type'>
|
||||
<value>rom</value>
|
||||
<value>pflash</value>
|
||||
</enum>
|
||||
<enum name='readonly'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
<enum name='secure'>
|
||||
<value>yes</value>
|
||||
<value>no</value>
|
||||
</enum>
|
||||
</loader>
|
||||
</os>
|
||||
</domainCapabilities>
|
||||
"""
|
||||
self.assertTrue(self.host.supports_secure_boot)
|
||||
|
||||
|
||||
vc = fakelibvirt.virConnect
|
||||
|
||||
|
@ -1318,7 +1501,6 @@ class TestLibvirtSEVUnsupported(TestLibvirtSEV):
|
|||
</capabilities>'''
|
||||
with mock.patch.object(fakelibvirt.virConnect, 'getCapabilities',
|
||||
return_value=fake_caps_xml):
|
||||
self.host._set_amd_sev_support()
|
||||
self.assertFalse(self.host.supports_amd_sev)
|
||||
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ class LibvirtConfigDomainCaps(LibvirtConfigObject):
|
|||
self._machine = None
|
||||
self._alias = None
|
||||
self._devices = None
|
||||
self._os = None
|
||||
|
||||
def parse_dom(self, xmldoc):
|
||||
super(LibvirtConfigDomainCaps, self).parse_dom(xmldoc)
|
||||
|
@ -137,6 +138,10 @@ class LibvirtConfigDomainCaps(LibvirtConfigObject):
|
|||
devices = LibvirtConfigDomainCapsDevices()
|
||||
devices.parse_dom(c)
|
||||
self._devices = devices
|
||||
elif c.tag == "os":
|
||||
os = LibvirtConfigDomainCapsOS()
|
||||
os.parse_dom(c)
|
||||
self._os = os
|
||||
|
||||
@property
|
||||
def features(self):
|
||||
|
@ -166,6 +171,10 @@ class LibvirtConfigDomainCaps(LibvirtConfigObject):
|
|||
return []
|
||||
return self._devices
|
||||
|
||||
@property
|
||||
def os(self):
|
||||
return self._os
|
||||
|
||||
|
||||
class LibvirtConfigDomainCapsVideoModels(LibvirtConfigObject):
|
||||
|
||||
|
@ -287,6 +296,50 @@ class LibvirtConfigDomainCapsFeatureSev(LibvirtConfigObject):
|
|||
self.cbitpos = int(c.text)
|
||||
|
||||
|
||||
class LibvirtConfigDomainCapsOS(LibvirtConfigObject):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(root_name='os', **kwargs)
|
||||
|
||||
self.supported = False
|
||||
self.loader_supported = None
|
||||
self.uefi_autoconfig_supported = None
|
||||
self.loader_paths = []
|
||||
self.uefi_supported = None
|
||||
self.secure_boot_supported = None
|
||||
|
||||
def parse_dom(self, xmldoc):
|
||||
super().parse_dom(xmldoc)
|
||||
|
||||
self.supported = xmldoc.get('supported')
|
||||
|
||||
for c in xmldoc:
|
||||
self.loader_supported = c.get('supported')
|
||||
|
||||
if c.tag == 'enum':
|
||||
if c.get('name') == 'firmware':
|
||||
# theoretically we can also do autoconfiguration of BIOS
|
||||
# but it's unlikely that anything supports this yet
|
||||
self.uefi_autoconfig_supported = 'efi' in [
|
||||
child.text for child in c if child.tag == 'value'
|
||||
]
|
||||
elif c.tag == 'loader':
|
||||
for c2 in c:
|
||||
if c2.tag == 'value':
|
||||
self.loader_paths.append(c2.text)
|
||||
elif c2.tag == 'enum':
|
||||
if c2.get('name') == 'type':
|
||||
self.uefi_supported = 'pflash' in [
|
||||
val.text for val in c2 if val.tag == 'value'
|
||||
]
|
||||
elif c2.get('name') == 'secure':
|
||||
# we might want to ensure 'no' is also supported,
|
||||
# but a platform that only supports SB sounds odd
|
||||
self.secure_boot_supported = 'yes' in [
|
||||
val.text for val in c2 if val.tag == 'value'
|
||||
]
|
||||
|
||||
|
||||
class LibvirtConfigCapsNUMATopology(LibvirtConfigObject):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
|
|
@ -118,10 +118,12 @@ class Host(object):
|
|||
self._libvirt_proxy_classes = self._get_libvirt_proxy_classes(libvirt)
|
||||
self._libvirt_proxy = self._wrap_libvirt_proxy(libvirt)
|
||||
|
||||
# AMD SEV is conditional on support in the hardware, kernel,
|
||||
# qemu, and libvirt. This is determined on demand and
|
||||
# memoized by the supports_amd_sev property below.
|
||||
# A number of features are conditional on support in the hardware,
|
||||
# kernel, QEMU, and/or libvirt. These are determined on demand and
|
||||
# memoized by various properties below
|
||||
self._supports_amd_sev = None
|
||||
self._supports_uefi: ty.Optional[bool] = None
|
||||
self._supports_secure_boot: ty.Optional[bool] = None
|
||||
|
||||
self._has_hyperthreading = None
|
||||
|
||||
|
@ -838,13 +840,9 @@ class Host(object):
|
|||
_domain_caps.
|
||||
|
||||
:returns: a nested dict of dicts which maps architectures to
|
||||
machine types to instances of config.LibvirtConfigDomainCaps
|
||||
representing the domain capabilities of the host for that arch
|
||||
and machine type:
|
||||
|
||||
{ arch:
|
||||
{ machine_type: LibvirtConfigDomainCaps }
|
||||
}
|
||||
machine types to instances of config.LibvirtConfigDomainCaps
|
||||
representing the domain capabilities of the host for that arch and
|
||||
machine type: ``{arch: machine_type: LibvirtConfigDomainCaps}{``
|
||||
"""
|
||||
if self._domain_caps:
|
||||
return self._domain_caps
|
||||
|
@ -1263,6 +1261,55 @@ class Host(object):
|
|||
|
||||
return self._has_hyperthreading
|
||||
|
||||
@property
|
||||
def supports_uefi(self) -> bool:
|
||||
"""Returns whether the host supports UEFI guests."""
|
||||
|
||||
if self._supports_uefi is not None:
|
||||
return self._supports_uefi
|
||||
|
||||
# we only check the host architecture since nova doesn't support
|
||||
# non-host architectures currently
|
||||
arch = self.get_capabilities().host.cpu.arch
|
||||
domain_caps = self.get_domain_capabilities()
|
||||
for machine_type in domain_caps[arch]:
|
||||
LOG.debug("Checking UEFI support for host arch (%s)", arch)
|
||||
_domain_caps = domain_caps[arch][machine_type]
|
||||
if _domain_caps.os.uefi_supported:
|
||||
LOG.info('UEFI support detected')
|
||||
self._supports_uefi = True
|
||||
return True
|
||||
|
||||
LOG.debug('No UEFI support detected')
|
||||
self._supports_uefi = False
|
||||
return False
|
||||
|
||||
@property
|
||||
def supports_secure_boot(self) -> bool:
|
||||
"""Determine if the host supports Secure Boot for guests."""
|
||||
|
||||
if self._supports_secure_boot is not None:
|
||||
return self._supports_secure_boot
|
||||
|
||||
# we only check the host architecture since nova doesn't support
|
||||
# non-host architectures currently
|
||||
arch = self.get_capabilities().host.cpu.arch
|
||||
domain_caps = self.get_domain_capabilities()
|
||||
for machine_type in domain_caps[arch]:
|
||||
LOG.debug(
|
||||
"Checking secure boot support for host arch (%s)",
|
||||
arch,
|
||||
)
|
||||
_domain_caps = domain_caps[arch][machine_type]
|
||||
if _domain_caps.os.secure_boot_supported:
|
||||
LOG.info('Secure Boot support detected')
|
||||
self._supports_secure_boot = True
|
||||
return True
|
||||
|
||||
LOG.debug('No Secure Boot support detected')
|
||||
self._supports_secure_boot = False
|
||||
return False
|
||||
|
||||
def _kernel_supports_amd_sev(self):
|
||||
if not os.path.exists(SEV_KERNEL_PARAM_FILE):
|
||||
LOG.debug("%s does not exist", SEV_KERNEL_PARAM_FILE)
|
||||
|
|
Loading…
Reference in New Issue