Merge "Add configurable libvirt firmware"
This commit is contained in:
commit
4b707299e0
|
@ -18,3 +18,16 @@ SUSHY_EMULATOR_OS_CLOUD = None
|
|||
|
||||
# The libvirt URI to use. This option enables libvirt driver.
|
||||
SUSHY_EMULATOR_LIBVIRT_URI = 'qemu:///system'
|
||||
|
||||
# The map of firmware loaders dependant on the boot mode and
|
||||
# system architecture
|
||||
SUSHY_EMULATOR_BOOT_LOADER_MAP = {
|
||||
'Uefi': {
|
||||
'x86_64': '/usr/share/OVMF/OVMF_CODE.fd',
|
||||
'aarch64': '/usr/share/AAVMF/AAVMF_CODE.fd'
|
||||
},
|
||||
'Legacy': {
|
||||
'x86_64': None,
|
||||
'aarch64': None
|
||||
}
|
||||
}
|
|
@ -85,16 +85,16 @@ class LibvirtDriver(AbstractDriver):
|
|||
|
||||
BOOT_MODE_MAP_REV = {v: k for k, v in BOOT_MODE_MAP.items()}
|
||||
|
||||
# NOTE(etingof): we have these firmware blobs hardcoded here
|
||||
# which seems to work for CentOS, for instance.
|
||||
# What's not clear is how to adapt to possible different
|
||||
# boot loaders paths dependent on libvirt packaging and custom
|
||||
# domain configuration...
|
||||
BOOT_LOADER_MAP = {
|
||||
'Uefi': {
|
||||
'x86_64': '/usr/share/OVMF/OVMF_CODE.fd',
|
||||
'aarch64': '/usr/share/AAVMF/AAVMF_CODE.fd'
|
||||
},
|
||||
'Legacy': {
|
||||
'x86_64': None,
|
||||
'aarch64': None
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DEFAULT_BIOS_ATTRIBUTES = {"BootMode": "Uefi",
|
||||
|
@ -102,8 +102,14 @@ class LibvirtDriver(AbstractDriver):
|
|||
"NicBoot1": "NetworkBoot",
|
||||
"ProcTurboMode": "Enabled"}
|
||||
|
||||
def __init__(self, uri=None):
|
||||
def __init__(self, config, uri=None):
|
||||
self._config = config
|
||||
self._uri = uri or self.LIBVIRT_URI
|
||||
self.BOOT_LOADER_MAP = self._config.get(
|
||||
'SUSHY_EMULATOR_BOOT_LOADER_MAP', self.BOOT_LOADER_MAP)
|
||||
self.KNOWN_BOOT_LOADERS = set(y
|
||||
for x in self.BOOT_LOADER_MAP.values()
|
||||
for y in x.values())
|
||||
|
||||
def _get_domain(self, identity, readonly=False):
|
||||
with libvirt_open(self._uri, readonly=readonly) as conn:
|
||||
|
@ -325,6 +331,8 @@ class LibvirtDriver(AbstractDriver):
|
|||
|
||||
raise error.FishyError(msg)
|
||||
|
||||
loaders = []
|
||||
|
||||
for os_element in tree.findall('os'):
|
||||
type_element = os_element.find('type')
|
||||
if type_element is None:
|
||||
|
@ -333,34 +341,57 @@ class LibvirtDriver(AbstractDriver):
|
|||
os_arch = type_element.get('arch')
|
||||
|
||||
try:
|
||||
loader_path = self.BOOT_LOADER_MAP[boot_mode][os_arch]
|
||||
loader_path = self.BOOT_DEVICE_MAP[boot_mode][os_arch]
|
||||
|
||||
except KeyError:
|
||||
# NOTE(etingof): assume no specific boot loader
|
||||
logger.warning('Boot loader is not configured for '
|
||||
'boot mode %s and OS architecture %s. '
|
||||
'Assuming no specific boot loader.',
|
||||
boot_mode, os_arch)
|
||||
loader_path = ''
|
||||
|
||||
# Update all "loader" elements
|
||||
# NOTE(etingof): here we collect all tree nodes to be
|
||||
# updated, but do not update them yet. The reason is to
|
||||
# make sure that previously configured boot loaders are
|
||||
# all present in our configuration, so we won't lose it
|
||||
# when setting ours.
|
||||
|
||||
for loader_element in os_element.findall('loader'):
|
||||
loader_element.set('type', loader_type)
|
||||
# NOTE(etingof): here we override previous boot loader for
|
||||
# for the domain. If it's different than what we have
|
||||
# hardcoded in the BOOT_LOADER_MAP, we won't be able to
|
||||
# revert back to the original boor loader should we change
|
||||
# domain boot mode.
|
||||
loader_element.text = loader_path
|
||||
|
||||
with libvirt_open(self._uri) as conn:
|
||||
|
||||
try:
|
||||
conn.defineXML(ET.tostring(tree).decode('utf-8'))
|
||||
|
||||
except libvirt.libvirtError as e:
|
||||
msg = ('Error changing boot mode at libvirt URI '
|
||||
'"%(uri)s": %(error)s' % {'uri': self._uri,
|
||||
'error': e})
|
||||
|
||||
if loader_element.text not in self.KNOWN_BOOT_LOADERS:
|
||||
msg = ('Unknown boot loader path "%(path)s" in domain '
|
||||
'"%(identity)s" configuration encountered while '
|
||||
'setting boot mode "%(mode)s", system architecture '
|
||||
'"%(arch)s". Consider adding this loader path to '
|
||||
'emulator config.' % {'identity': identity,
|
||||
'mode': boot_mode,
|
||||
'arch': os_arch,
|
||||
'path': loader_element.text})
|
||||
raise error.FishyError(msg)
|
||||
|
||||
loaders.append((loader_element, loader_path))
|
||||
|
||||
if not loaders:
|
||||
msg = ('Can\'t set boot mode because no "os" elements are present '
|
||||
'in domain "%(identity)s" or not a single "os" element has '
|
||||
'"loader" configured.' % {'identity': identity})
|
||||
raise error.FishyError(msg)
|
||||
|
||||
for loader_element, loader_path in loaders:
|
||||
loader_element.set('type', loader_type)
|
||||
loader_element.text = loader_path
|
||||
|
||||
with libvirt_open(self._uri) as conn:
|
||||
|
||||
try:
|
||||
conn.defineXML(ET.tostring(tree).decode('utf-8'))
|
||||
|
||||
except libvirt.libvirtError as e:
|
||||
msg = ('Error changing boot mode at libvirt URI '
|
||||
'"%(uri)s": %(error)s' % {'uri': self._uri,
|
||||
'error': e})
|
||||
|
||||
raise error.FishyError(msg)
|
||||
|
||||
def get_total_memory(self, identity):
|
||||
"""Get computer system total memory
|
||||
|
||||
|
|
|
@ -51,9 +51,10 @@ class OpenStackDriver(AbstractDriver):
|
|||
|
||||
BOOT_MODE_MAP_REV = {v: k for k, v in BOOT_MODE_MAP.items()}
|
||||
|
||||
def __init__(self, os_cloud, readonly=False):
|
||||
def __init__(self, config, os_cloud, readonly=False):
|
||||
self._cc = openstack.connect(cloud=os_cloud)
|
||||
self._os_cloud = os_cloud
|
||||
self._config = config
|
||||
|
||||
def _get_instance(self, identity):
|
||||
instance = self._cc.get_server(identity)
|
||||
|
|
|
@ -46,7 +46,8 @@ def init_virt_driver(decorated_func):
|
|||
app.logger.error('Nova driver not loaded')
|
||||
sys.exit(1)
|
||||
|
||||
driver = novadriver.OpenStackDriver(os.environ['OS_CLOUD'])
|
||||
driver = novadriver.OpenStackDriver(
|
||||
app.config, os.environ['OS_CLOUD'])
|
||||
|
||||
else:
|
||||
if not libvirtdriver.is_loaded:
|
||||
|
@ -54,6 +55,7 @@ def init_virt_driver(decorated_func):
|
|||
sys.exit(1)
|
||||
|
||||
driver = libvirtdriver.LibvirtDriver(
|
||||
app.config,
|
||||
os.environ.get(
|
||||
'SUSHY_EMULATOR_LIBVIRT_URI',
|
||||
# NOTE(etingof): left for backward compatibility
|
||||
|
@ -310,7 +312,7 @@ def main():
|
|||
app.logger.error('Nova driver not loaded')
|
||||
return 1
|
||||
|
||||
driver = novadriver.OpenStackDriver(os_cloud)
|
||||
driver = novadriver.OpenStackDriver(app.config, os_cloud)
|
||||
|
||||
else:
|
||||
if not libvirtdriver.is_loaded:
|
||||
|
@ -318,6 +320,7 @@ def main():
|
|||
return 1
|
||||
|
||||
driver = libvirtdriver.LibvirtDriver(
|
||||
app.config,
|
||||
args.libvirt_uri or
|
||||
app.config.get('SUSHY_EMULATOR_LIBVIRT_URI', '')
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<currentMemory>219200</currentMemory>
|
||||
<vcpu>2</vcpu>
|
||||
<os>
|
||||
<type arch='i686' machine='pc'>hvm</type>
|
||||
<type arch='x86_64' machine='pc'>hvm</type>
|
||||
<boot dev='cdrom'/>
|
||||
<loader type='rom'/>
|
||||
</os>
|
||||
|
|
|
@ -25,7 +25,7 @@ class LibvirtDriverTestCase(base.BaseTestCase):
|
|||
uuid = 'c7a5fdbd-cdaf-9455-926a-d65c16db1809'
|
||||
|
||||
def setUp(self):
|
||||
self.test_driver = LibvirtDriver()
|
||||
self.test_driver = LibvirtDriver({})
|
||||
super(LibvirtDriverTestCase, self).setUp()
|
||||
|
||||
@mock.patch('libvirt.open', autospec=True)
|
||||
|
@ -211,6 +211,22 @@ class LibvirtDriverTestCase(base.BaseTestCase):
|
|||
conn_mock = libvirt_rw_mock.return_value
|
||||
conn_mock.defineXML.assert_called_once_with(mock.ANY)
|
||||
|
||||
@mock.patch('libvirt.open', autospec=True)
|
||||
@mock.patch('libvirt.openReadOnly', autospec=True)
|
||||
def test_set_boot_mode_unknown_path(self, libvirt_mock, libvirt_rw_mock):
|
||||
with open('sushy_tools/tests/unit/emulator/domain.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
|
||||
|
||||
with mock.patch.dict(
|
||||
self.test_driver.KNOWN_BOOT_LOADERS, {}, clear=True):
|
||||
self.assertRaises(
|
||||
error.FishyError, self.test_driver.set_boot_mode,
|
||||
self.uuid, 'Uefi')
|
||||
|
||||
@mock.patch('libvirt.openReadOnly', autospec=True)
|
||||
def test_get_total_memory(self, libvirt_mock):
|
||||
conn_mock = libvirt_mock.return_value
|
||||
|
|
|
@ -30,7 +30,7 @@ class NovaDriverTestCase(base.BaseTestCase):
|
|||
self.nova_patcher = mock.patch('openstack.connect', autospec=True)
|
||||
self.nova_mock = self.nova_patcher.start()
|
||||
|
||||
self.test_driver = OpenStackDriver('fake-cloud')
|
||||
self.test_driver = OpenStackDriver({}, 'fake-cloud')
|
||||
|
||||
super(NovaDriverTestCase, self).setUp()
|
||||
|
||||
|
@ -216,10 +216,7 @@ class NovaDriverTestCase(base.BaseTestCase):
|
|||
|
||||
server = mock.Mock(id=self.uuid, addresses=addresses)
|
||||
self.nova_mock.return_value.get_server.return_value = server
|
||||
|
||||
test_driver = OpenStackDriver('fake-cloud')
|
||||
nics = test_driver.get_nics(self.uuid)
|
||||
|
||||
nics = self.test_driver.get_nics(self.uuid)
|
||||
self.assertEqual([{'id': 'fa:16:3e:22:18:31',
|
||||
'mac': 'fa:16:3e:22:18:31'},
|
||||
{'id': 'fa:16:3e:46:e3:ac',
|
||||
|
@ -229,8 +226,7 @@ class NovaDriverTestCase(base.BaseTestCase):
|
|||
def test_get_nics_empty(self):
|
||||
server = mock.Mock(id=self.uuid, addresses=None)
|
||||
self.nova_mock.return_value.get_server.return_value = server
|
||||
test_driver = OpenStackDriver('fake-cloud')
|
||||
nics = test_driver.get_nics(self.uuid)
|
||||
nics = self.test_driver.get_nics(self.uuid)
|
||||
self.assertEqual(set(), nics)
|
||||
|
||||
def test_get_nics_error(self):
|
||||
|
|
Loading…
Reference in New Issue