New option to prevent libvirt defining boot order

Add a new config option "SUSHY_EMULATOR_IGNORE_BOOT_DEVICE".
Instructs the libvirt driver to ignore any instructions to
set the boot device. Allowing the UEFI firmware to instead
rely on the EFI Boot Manager

Change-Id: Ica78dab39639d7acb2168866b0035f9c3d865fa1
This commit is contained in:
Derek Higgins 2021-02-19 14:30:34 +00:00
parent 57d05d944b
commit 02b451b500
3 changed files with 54 additions and 9 deletions

View File

@ -19,6 +19,15 @@ SUSHY_EMULATOR_OS_CLOUD = None
# The libvirt URI to use. This option enables libvirt driver. # The libvirt URI to use. This option enables libvirt driver.
SUSHY_EMULATOR_LIBVIRT_URI = u'qemu:///system' SUSHY_EMULATOR_LIBVIRT_URI = u'qemu:///system'
# Instruct the libvirt driver to ignore any instructions to
# set the boot device. Allowing the UEFI firmware to instead
# rely on the EFI Boot Manager
# Note: This sets the legacy boot element to dev="fd"
# and relies on the floppy not existing, it likely wont work
# your VM has a floppy drive.
SUSHY_EMULATOR_IGNORE_BOOT_DEVICE = False
# The map of firmware loaders dependant on the boot mode and # The map of firmware loaders dependant on the boot mode and
# system architecture # system architecture
SUSHY_EMULATOR_BOOT_LOADER_MAP = { SUSHY_EMULATOR_BOOT_LOADER_MAP = {

View File

@ -155,6 +155,8 @@ class LibvirtDriver(AbstractSystemsDriver):
'SUSHY_EMULATOR_BOOT_LOADER_MAP', cls.BOOT_LOADER_MAP) 'SUSHY_EMULATOR_BOOT_LOADER_MAP', cls.BOOT_LOADER_MAP)
cls.KNOWN_BOOT_LOADERS = set(y for x in cls.BOOT_LOADER_MAP.values() cls.KNOWN_BOOT_LOADERS = set(y for x in cls.BOOT_LOADER_MAP.values()
for y in x.values()) for y in x.values())
cls.SUSHY_EMULATOR_IGNORE_BOOT_DEVICE = \
cls._config.get('SUSHY_EMULATOR_IGNORE_BOOT_DEVICE', False)
return cls return cls
@memoize.memoize() @memoize.memoize()
@ -282,6 +284,11 @@ class LibvirtDriver(AbstractSystemsDriver):
:returns: boot device name as `str` or `None` if device name :returns: boot device name as `str` or `None` if device name
can't be determined can't be determined
""" """
# If not setting Boot devices then just report HDD
if self.SUSHY_EMULATOR_IGNORE_BOOT_DEVICE:
return constants.DEVICE_TYPE_HDD
domain = self._get_domain(identity, readonly=True) domain = self._get_domain(identity, readonly=True)
tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)) tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE))
@ -347,6 +354,15 @@ class LibvirtDriver(AbstractSystemsDriver):
return boot_source_target return boot_source_target
def _defineDomain(self, tree):
try:
with libvirt_open(self._uri) as conn:
conn.defineXML(ET.tostring(tree).decode('utf-8'))
except libvirt.libvirtError as e:
msg = ('Error changing boot device at libvirt URI "%(uri)s": '
'%(error)s' % {'uri': self._uri, 'error': e})
raise error.FishyError(msg)
def set_boot_device(self, identity, boot_source): def set_boot_device(self, identity, boot_source):
"""Get/Set computer system boot device name """Get/Set computer system boot device name
@ -372,6 +388,13 @@ class LibvirtDriver(AbstractSystemsDriver):
for boot_element in os_element.findall('boot'): for boot_element in os_element.findall('boot'):
os_element.remove(boot_element) os_element.remove(boot_element)
if self.SUSHY_EMULATOR_IGNORE_BOOT_DEVICE:
self._logger.warning('Ignoring setting of boot device')
boot_element = ET.SubElement(os_element, 'boot')
boot_element.set('dev', 'fd')
self._defineDomain(tree)
return
target = self.DISK_DEVICE_MAP.get(boot_source) target = self.DISK_DEVICE_MAP.get(boot_source)
# Process per-device boot configuration # Process per-device boot configuration
@ -426,15 +449,7 @@ class LibvirtDriver(AbstractSystemsDriver):
boot_element = ET.SubElement(target_device_element, 'boot') boot_element = ET.SubElement(target_device_element, 'boot')
boot_element.set('order', str(order + 1)) boot_element.set('order', str(order + 1))
try: self._defineDomain(tree)
with libvirt_open(self._uri) as conn:
conn.defineXML(ET.tostring(tree).decode('utf-8'))
except libvirt.libvirtError as e:
msg = ('Error changing boot device at libvirt URI "%(uri)s": '
'%(error)s' % {'uri': self._uri, 'error': e})
raise error.FishyError(msg)
def get_boot_mode(self, identity): def get_boot_mode(self, identity):
"""Get computer system boot mode. """Get computer system boot mode.

View File

@ -214,6 +214,27 @@ class LibvirtDriverTestCase(base.BaseTestCase):
conn_mock.defineXML.assert_called_once_with(mock.ANY) conn_mock.defineXML.assert_called_once_with(mock.ANY)
@mock.patch('libvirt.open', autospec=True)
def test_set_boot_device_ignored(self, libvirt_mock):
with open('sushy_tools/tests/unit/emulator/'
'domain_boot_os.xml', 'r') as f:
data = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByUUID.return_value
domain_mock.XMLDesc.return_value = data
self.test_driver.SUSHY_EMULATOR_IGNORE_BOOT_DEVICE = True
self.test_driver.set_boot_device(self.uuid, 'Hdd')
conn_mock.defineXML.assert_called_once_with(mock.ANY)
tree = ET.fromstring(conn_mock.defineXML.call_args[0][0])
self.assertEqual(1, len(tree.findall('.//boot')))
os_element = tree.find('os')
boot_element = os_element.find('boot')
self.assertEqual('fd', boot_element.get('dev'))
@mock.patch('libvirt.openReadOnly', autospec=True) @mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_boot_device_disk(self, libvirt_mock): def test_get_boot_device_disk(self, libvirt_mock):
with open('sushy_tools/tests/unit/emulator/' with open('sushy_tools/tests/unit/emulator/'