Merge "libvirt: Use domain capabilities to get supported device models"
This commit is contained in:
commit
15f0215df5
|
@ -133,6 +133,9 @@ class LibvirtReportNoSevTraitsTests(LibvirtReportTraitsTestBase):
|
|||
) as (mock_exists, mock_open, mock_features):
|
||||
# Retrigger the detection code. In the real world this
|
||||
# would be a restart of the compute service.
|
||||
# As we are changing the domain caps we need to clear the
|
||||
# cache in the host object.
|
||||
self.compute.driver._host._domain_caps = None
|
||||
self.compute.driver._host._set_amd_sev_support()
|
||||
self.assertTrue(self.compute.driver._host.supports_amd_sev)
|
||||
|
||||
|
@ -142,6 +145,8 @@ class LibvirtReportNoSevTraitsTests(LibvirtReportTraitsTestBase):
|
|||
# However it won't disappear in the provider tree and get synced
|
||||
# back to placement until we force a reinventory:
|
||||
self.compute.manager.reset()
|
||||
# reset cached traits so they are recalculated.
|
||||
self.compute.driver._static_traits = None
|
||||
self._run_periodics()
|
||||
|
||||
traits = self._get_provider_traits(self.host_uuid)
|
||||
|
@ -200,6 +205,7 @@ class LibvirtReportSevTraitsTests(LibvirtReportTraitsTestBase):
|
|||
with self.patch_exists(SEV_KERNEL_PARAM_FILE, False) as mock_exists:
|
||||
# Retrigger the detection code. In the real world this
|
||||
# would be a restart of the compute service.
|
||||
self.compute.driver._host._domain_caps = None
|
||||
self.compute.driver._host._set_amd_sev_support()
|
||||
self.assertFalse(self.compute.driver._host.supports_amd_sev)
|
||||
|
||||
|
@ -208,6 +214,8 @@ class LibvirtReportSevTraitsTests(LibvirtReportTraitsTestBase):
|
|||
# However it won't disappear in the provider tree and get synced
|
||||
# back to placement until we force a reinventory:
|
||||
self.compute.manager.reset()
|
||||
# reset cached traits so they are recalculated.
|
||||
self.compute.driver._static_traits = None
|
||||
self._run_periodics()
|
||||
|
||||
traits = self._get_provider_traits(self.host_uuid)
|
||||
|
|
|
@ -3808,3 +3808,132 @@ class LibvirtConfigGuestVPMEMTest(LibvirtConfigBaseTest):
|
|||
</label>
|
||||
</target>
|
||||
</memory>""")
|
||||
|
||||
|
||||
class LibvirtConfigVideoModelsTests(LibvirtConfigBaseTest):
|
||||
|
||||
def test_parse_video_model(self):
|
||||
|
||||
xml = """
|
||||
<video supported='yes'>
|
||||
<enum name='modelType'>
|
||||
<value>vga</value>
|
||||
<value>cirrus</value>
|
||||
<value>vmvga</value>
|
||||
<value>qxl</value>
|
||||
<value>virtio</value>
|
||||
</enum>
|
||||
</video>
|
||||
"""
|
||||
obj = config.LibvirtConfigDomainCapsVideoModels()
|
||||
obj.parse_str(xml)
|
||||
expected_models = ('vga', 'cirrus', 'vmvga', 'qxl', 'virtio')
|
||||
self.assertTrue(obj.supported)
|
||||
for model in expected_models:
|
||||
self.assertIn(model, obj.models)
|
||||
self.assertNotIn('gop', obj.models)
|
||||
|
||||
|
||||
class LibvirtConfigDiskBusesTests(LibvirtConfigBaseTest):
|
||||
|
||||
def test_parse_disk_buses(self):
|
||||
|
||||
xml = """
|
||||
<disk supported='yes'>
|
||||
<enum name='diskDevice'>
|
||||
<value>disk</value>
|
||||
<value>cdrom</value>
|
||||
<value>floppy</value>
|
||||
<value>lun</value>
|
||||
</enum>
|
||||
<enum name='bus'>
|
||||
<value>ide</value>
|
||||
<value>scsi</value>
|
||||
<value>virtio</value>
|
||||
<value>usb</value>
|
||||
<value>sata</value>
|
||||
</enum>
|
||||
</disk>
|
||||
"""
|
||||
obj = config.LibvirtConfigDomainCapsDiskBuses()
|
||||
obj.parse_str(xml)
|
||||
expected_buses = ('ide', 'scsi', 'virtio', 'usb', 'sata')
|
||||
self.assertTrue(obj.supported)
|
||||
for bus in expected_buses:
|
||||
self.assertIn(bus, obj.buses)
|
||||
self.assertNotIn('fdc', obj.buses)
|
||||
|
||||
|
||||
class LibvirtConfigDomainCapsDevicesTests(LibvirtConfigBaseTest):
|
||||
|
||||
def test_parse_domain_caps_devices(self):
|
||||
|
||||
xml = """
|
||||
<devices>
|
||||
<disk supported='yes'>
|
||||
<enum name='diskDevice'>
|
||||
<value>disk</value>
|
||||
<value>cdrom</value>
|
||||
<value>floppy</value>
|
||||
<value>lun</value>
|
||||
</enum>
|
||||
<enum name='bus'>
|
||||
<value>ide</value>
|
||||
<value>fdc</value>
|
||||
<value>scsi</value>
|
||||
<value>virtio</value>
|
||||
<value>usb</value>
|
||||
<value>sata</value>
|
||||
</enum>
|
||||
</disk>
|
||||
<graphics supported='yes'>
|
||||
<enum name='type'>
|
||||
<value>sdl</value>
|
||||
<value>vnc</value>
|
||||
<value>spice</value>
|
||||
</enum>
|
||||
</graphics>
|
||||
<video supported='yes'>
|
||||
<enum name='modelType'>
|
||||
<value>vga</value>
|
||||
<value>cirrus</value>
|
||||
<value>vmvga</value>
|
||||
<value>qxl</value>
|
||||
<value>virtio</value>
|
||||
</enum>
|
||||
</video>
|
||||
<hostdev supported='yes'>
|
||||
<enum name='mode'>
|
||||
<value>subsystem</value>
|
||||
</enum>
|
||||
<enum name='startupPolicy'>
|
||||
<value>default</value>
|
||||
<value>mandatory</value>
|
||||
<value>requisite</value>
|
||||
<value>optional</value>
|
||||
</enum>
|
||||
<enum name='subsysType'>
|
||||
<value>usb</value>
|
||||
<value>pci</value>
|
||||
<value>scsi</value>
|
||||
</enum>
|
||||
<enum name='capsType'/>
|
||||
<enum name='pciBackend'/>
|
||||
</hostdev>
|
||||
</devices>
|
||||
"""
|
||||
obj = config.LibvirtConfigDomainCapsDevices()
|
||||
obj.parse_str(xml)
|
||||
# we only use the video and disk devices today.
|
||||
device_types = [config.LibvirtConfigDomainCapsDiskBuses,
|
||||
config.LibvirtConfigDomainCapsVideoModels]
|
||||
# so we assert there are only two device types parsed
|
||||
self.assertEqual(2, len(obj.devices))
|
||||
# we then assert that the parsed devices are of the correct type
|
||||
for dev in obj.devices:
|
||||
self.assertIn(type(dev), device_types)
|
||||
# and that the sub-devices are accessible directly via properties.
|
||||
self.assertIsInstance(
|
||||
obj.disk, config.LibvirtConfigDomainCapsDiskBuses)
|
||||
self.assertIsInstance(
|
||||
obj.video, config.LibvirtConfigDomainCapsVideoModels)
|
||||
|
|
|
@ -120,6 +120,7 @@ from nova.virt.libvirt.storage import dmcrypt
|
|||
from nova.virt.libvirt.storage import lvm
|
||||
from nova.virt.libvirt.storage import rbd_utils
|
||||
from nova.virt.libvirt import utils as libvirt_utils
|
||||
from nova.virt.libvirt import vif as libvirt_vif
|
||||
from nova.virt.libvirt.volume import volume as volume_drivers
|
||||
|
||||
|
||||
|
@ -1107,6 +1108,82 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
self.assertFalse(drvr.need_legacy_block_device_info)
|
||||
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_cpu_traits')
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_storage_bus_traits')
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_video_model_traits')
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_vif_model_traits')
|
||||
def test_static_traits(
|
||||
self, mock_vif_traits, mock_video_traits, mock_storage_traits,
|
||||
mock_cpu_traits,
|
||||
):
|
||||
"""Ensure driver capabilities are correctly retrieved and cached."""
|
||||
|
||||
# we don't mock out calls to os_traits intentionally, so we need to
|
||||
# return valid traits here
|
||||
mock_cpu_traits.return_value = {'HW_CPU_HYPERTHREADING': True}
|
||||
mock_storage_traits.return_value = {'COMPUTE_STORAGE_BUS_VIRTIO': True}
|
||||
mock_video_traits.return_value = {'COMPUTE_GRAPHICS_MODEL_VGA': True}
|
||||
mock_vif_traits.return_value = {'COMPUTE_NET_VIF_MODEL_VIRTIO': True}
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
expected = {
|
||||
'HW_CPU_HYPERTHREADING': True,
|
||||
'COMPUTE_STORAGE_BUS_VIRTIO': True,
|
||||
'COMPUTE_GRAPHICS_MODEL_VGA': True,
|
||||
'COMPUTE_NET_VIF_MODEL_VIRTIO': True,
|
||||
}
|
||||
|
||||
static_traits = drvr.static_traits
|
||||
|
||||
# check that results are as expected and the individual helper
|
||||
# functions were called once each
|
||||
self.assertEqual(expected, static_traits)
|
||||
for mock_traits in (
|
||||
mock_vif_traits, mock_video_traits, mock_storage_traits,
|
||||
mock_cpu_traits,
|
||||
):
|
||||
mock_traits.assert_called_once_with()
|
||||
mock_traits.reset_mock()
|
||||
|
||||
static_traits = drvr.static_traits
|
||||
|
||||
# now check that the results are still as expected but the helpers
|
||||
# weren't called since the value was cached
|
||||
self.assertEqual(expected, static_traits)
|
||||
for mock_traits in (
|
||||
mock_vif_traits, mock_video_traits, mock_storage_traits,
|
||||
mock_cpu_traits,
|
||||
):
|
||||
mock_traits.assert_not_called()
|
||||
|
||||
@mock.patch.object(libvirt_driver.LOG, 'debug')
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_cpu_traits')
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_storage_bus_traits')
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_video_model_traits')
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_vif_model_traits')
|
||||
def test_static_traits__invalid_trait(
|
||||
self, mock_vif_traits, mock_video_traits, mock_storage_traits,
|
||||
mock_cpu_traits, mock_log,
|
||||
):
|
||||
"""Ensure driver capabilities are correctly retrieved and cached."""
|
||||
mock_cpu_traits.return_value = {'foo': True}
|
||||
mock_storage_traits.return_value = {'bar': True}
|
||||
mock_video_traits.return_value = {'baz': True}
|
||||
mock_vif_traits.return_value = {'COMPUTE_NET_VIF_MODEL_VIRTIO': True}
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
expected = {'COMPUTE_NET_VIF_MODEL_VIRTIO': True}
|
||||
|
||||
static_traits = drvr.static_traits
|
||||
|
||||
self.assertEqual(expected, static_traits)
|
||||
mock_log.assert_has_calls([
|
||||
mock.call("Trait '%s' is not valid; ignoring.", "foo"),
|
||||
mock.call("Trait '%s' is not valid; ignoring.", "bar"),
|
||||
mock.call("Trait '%s' is not valid; ignoring.", "baz"),
|
||||
],
|
||||
any_order=True)
|
||||
|
||||
@mock.patch.object(host.Host, "has_min_version")
|
||||
def test_min_version_start_ok(self, mock_version):
|
||||
mock_version.return_value = True
|
||||
|
@ -23488,16 +23565,35 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
self.assertRaises(test.TestingException,
|
||||
self._test_detach_mediated_devices, exc)
|
||||
|
||||
def test_storage_bus_traits(self):
|
||||
def test_storage_bus_traits__qemu_kvm(self):
|
||||
"""Test getting storage bus traits per virt type.
|
||||
|
||||
This also ensures that nova and os-traits are in sync with respect to
|
||||
COMPUTE_STORAGE_BUS_*.
|
||||
"""
|
||||
all_traits = set(ot.get_traits('COMPUTE_STORAGE_BUS_'))
|
||||
self.flags(hw_machine_type='pc', group='libvirt')
|
||||
for virt_type in ('qemu', 'kvm'):
|
||||
self.flags(virt_type=virt_type, group='libvirt')
|
||||
bus_traits = self.drvr._get_storage_bus_traits()
|
||||
dom_caps = self.drvr._host.get_domain_capabilities()
|
||||
buses = dom_caps['x86_64']['pc'].devices.disk.buses
|
||||
for bus in buses:
|
||||
name = bus.replace('-', '_').upper()
|
||||
trait = f'COMPUTE_STORAGE_BUS_{name}'
|
||||
self.assertIn(trait, bus_traits)
|
||||
self.assertTrue(bus_traits[trait])
|
||||
bus_traits.pop(trait)
|
||||
self.assertTrue(all(not bus for bus in bus_traits.values()))
|
||||
|
||||
valid_traits = ot.check_traits(bus_traits)
|
||||
self.assertEqual(len(bus_traits), len(valid_traits[0]))
|
||||
self.assertEqual(0, len(valid_traits[1]))
|
||||
|
||||
def test_storage_bus_traits__non_qemu_kvm(self):
|
||||
"""Test getting storage bus traits per virt type."""
|
||||
all_traits = set(ot.get_traits('COMPUTE_STORAGE_BUS_'))
|
||||
# ensure each virt type reports the correct bus types
|
||||
for virt_type, buses in blockinfo.SUPPORTED_STORAGE_BUSES.items():
|
||||
if virt_type in ('qemu', 'kvm'):
|
||||
continue
|
||||
|
||||
self.flags(virt_type=virt_type, group='libvirt')
|
||||
bus_traits = self.drvr._get_storage_bus_traits()
|
||||
# Ensure all bus traits are accounted for
|
||||
|
@ -23506,6 +23602,32 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
bus_from_trait = trait.rsplit('_', 1)[1].lower()
|
||||
self.assertEqual(bus_from_trait in buses, bus_traits[trait])
|
||||
|
||||
def test_vif_model_traits(self):
|
||||
"""Test getting vif model traits per virt type."""
|
||||
for virt_type, models in libvirt_vif.SUPPORTED_VIF_MODELS.items():
|
||||
self.flags(virt_type=virt_type, group='libvirt')
|
||||
vif_models = self.drvr._get_vif_model_traits()
|
||||
for model in models:
|
||||
trait = 'COMPUTE_NET_VIF_MODEL_%s' % (
|
||||
model.replace('-', '_').upper()
|
||||
)
|
||||
self.assertIn(trait, vif_models)
|
||||
self.assertTrue(vif_models[trait])
|
||||
vif_models.pop(trait)
|
||||
self.assertTrue(all(not model for model in vif_models.values()))
|
||||
|
||||
def test_video_model_traits(self):
|
||||
"""Test getting video model traits per virt type."""
|
||||
# NOTE(sean-k-mooney): we do not have a static tables of which video
|
||||
# models are supported by each virt type so just assert that traits are
|
||||
# available for all models but not if the traits are mapped to true or
|
||||
# false.
|
||||
self.flags(virt_type='qemu', group='libvirt')
|
||||
model_traits = self.drvr._get_video_model_traits()
|
||||
for model in fields.VideoModel.ALL:
|
||||
trait = f'COMPUTE_GRAPHICS_MODEL_{model.upper()}'
|
||||
self.assertIn(trait, model_traits)
|
||||
|
||||
@mock.patch.object(libvirt_driver.LibvirtDriver, '_get_cpu_feature_traits',
|
||||
new=mock.Mock(return_value={}))
|
||||
def test_cpu_traits__sev_support(self):
|
||||
|
|
|
@ -122,6 +122,7 @@ class LibvirtConfigDomainCaps(LibvirtConfigObject):
|
|||
self._features = None
|
||||
self._machine = None
|
||||
self._alias = None
|
||||
self._devices = None
|
||||
|
||||
def parse_dom(self, xmldoc):
|
||||
super(LibvirtConfigDomainCaps, self).parse_dom(xmldoc)
|
||||
|
@ -133,6 +134,10 @@ class LibvirtConfigDomainCaps(LibvirtConfigObject):
|
|||
self._features = features
|
||||
elif c.tag == "machine":
|
||||
self._machine = c.text
|
||||
elif c.tag == "devices":
|
||||
devices = LibvirtConfigDomainCapsDevices()
|
||||
devices.parse_dom(c)
|
||||
self._devices = devices
|
||||
|
||||
@property
|
||||
def features(self):
|
||||
|
@ -156,6 +161,79 @@ class LibvirtConfigDomainCaps(LibvirtConfigObject):
|
|||
def machine_type_alias(self, alias):
|
||||
self._alias = alias
|
||||
|
||||
@property
|
||||
def devices(self):
|
||||
if self._devices is None:
|
||||
return []
|
||||
return self._devices
|
||||
|
||||
|
||||
class LibvirtConfigDomainCapsVideoModels(LibvirtConfigObject):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(root_name='video', **kwargs)
|
||||
self.supported = False
|
||||
self.models = set()
|
||||
|
||||
def parse_dom(self, xmldoc):
|
||||
super().parse_dom(xmldoc)
|
||||
|
||||
if xmldoc.get('supported') == 'yes':
|
||||
self.supported = True
|
||||
self.models = {str(node) for node in
|
||||
xmldoc.xpath("//enum[@name='modelType']/value/text()")}
|
||||
|
||||
|
||||
class LibvirtConfigDomainCapsDiskBuses(LibvirtConfigObject):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(root_name='disk', **kwargs)
|
||||
self.supported = False
|
||||
self.buses = set()
|
||||
|
||||
def parse_dom(self, xmldoc):
|
||||
super(LibvirtConfigDomainCapsDiskBuses, self).parse_dom(xmldoc)
|
||||
|
||||
if xmldoc.get('supported') == 'yes':
|
||||
self.supported = True
|
||||
self.buses = {str(node) for node in
|
||||
xmldoc.xpath("//enum[@name='bus']/value/text()")}
|
||||
|
||||
|
||||
class LibvirtConfigDomainCapsDevices(LibvirtConfigObject):
|
||||
DEVICE_PARSERS = {
|
||||
'video': LibvirtConfigDomainCapsVideoModels,
|
||||
'disk': LibvirtConfigDomainCapsDiskBuses,
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(root_name='devices', **kwargs)
|
||||
self.devices = set()
|
||||
|
||||
def parse_dom(self, xmldoc):
|
||||
super().parse_dom(xmldoc)
|
||||
|
||||
for c in xmldoc.getchildren():
|
||||
device = self.DEVICE_PARSERS.get(c.tag)
|
||||
if device:
|
||||
device = device()
|
||||
device.parse_dom(c)
|
||||
self.devices.add(device)
|
||||
|
||||
def _get_device(self, device_type):
|
||||
for device in self.devices:
|
||||
if type(device) == self.DEVICE_PARSERS.get(device_type):
|
||||
return device
|
||||
return None
|
||||
|
||||
@property
|
||||
def disk(self):
|
||||
return self._get_device('disk')
|
||||
|
||||
@property
|
||||
def video(self):
|
||||
return self._get_device('video')
|
||||
|
||||
|
||||
class LibvirtConfigDomainCapsFeatures(LibvirtConfigObject):
|
||||
|
||||
|
|
|
@ -415,6 +415,10 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
# intended to be updatable directly
|
||||
self.provider_tree = None
|
||||
|
||||
# driver traits will not change during the runtime of the agent
|
||||
# so calcuate them once and save them
|
||||
self._static_traits = None
|
||||
|
||||
# The CPU models in the configuration are case-insensitive, but the CPU
|
||||
# model in the libvirt is case-sensitive, therefore create a mapping to
|
||||
# map the lower case CPU model name to normal CPU model name.
|
||||
|
@ -7352,15 +7356,12 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
provider_tree.update_inventory(nodename, result)
|
||||
provider_tree.update_resources(nodename, resources)
|
||||
|
||||
# _get_cpu_traits and _get_storage_bus_traits return a dict of trait
|
||||
# names mapped to boolean values...
|
||||
traits = self._get_cpu_traits()
|
||||
traits.update(self._get_storage_bus_traits())
|
||||
|
||||
# ..and we add traits equal to True to provider tree while removing
|
||||
# those equal to False
|
||||
traits_to_add = [t for t in traits if traits[t]]
|
||||
traits_to_remove = set(traits) - set(traits_to_add)
|
||||
# Add supported traits i.e. those equal to True to provider tree while
|
||||
# removing the unsupported ones
|
||||
traits_to_add = [
|
||||
t for t in self.static_traits if self.static_traits[t]
|
||||
]
|
||||
traits_to_remove = set(self.static_traits) - set(traits_to_add)
|
||||
provider_tree.add_traits(nodename, *traits_to_add)
|
||||
provider_tree.remove_traits(nodename, *traits_to_remove)
|
||||
|
||||
|
@ -7418,6 +7419,26 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
else:
|
||||
return db_const.MAX_INT
|
||||
|
||||
@property
|
||||
def static_traits(self):
|
||||
if self._static_traits is not None:
|
||||
return self._static_traits
|
||||
|
||||
traits = {}
|
||||
traits.update(self._get_cpu_traits())
|
||||
traits.update(self._get_storage_bus_traits())
|
||||
traits.update(self._get_video_model_traits())
|
||||
traits.update(self._get_vif_model_traits())
|
||||
|
||||
_, invalid_traits = ot.check_traits(traits)
|
||||
for invalid_trait in invalid_traits:
|
||||
LOG.debug("Trait '%s' is not valid; ignoring.", invalid_trait)
|
||||
del traits[invalid_trait]
|
||||
|
||||
self._static_traits = traits
|
||||
|
||||
return self._static_traits
|
||||
|
||||
@staticmethod
|
||||
def _is_reshape_needed_vgpu_on_root(provider_tree, nodename):
|
||||
"""Determine if root RP has VGPU inventories.
|
||||
|
@ -10451,21 +10472,83 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
nova.privsep.fs.FS_FORMAT_EXT4,
|
||||
nova.privsep.fs.FS_FORMAT_XFS]
|
||||
|
||||
def _get_vif_model_traits(self):
|
||||
"""Get vif model traits based on the currently enabled virt_type.
|
||||
|
||||
Not all traits generated by this function may be valid and the result
|
||||
should be validated.
|
||||
|
||||
:return: A dict of trait names mapped to boolean values.
|
||||
"""
|
||||
all_models = set(itertools.chain(
|
||||
*libvirt_vif.SUPPORTED_VIF_MODELS.values()
|
||||
))
|
||||
supported_models = libvirt_vif.SUPPORTED_VIF_MODELS.get(
|
||||
CONF.libvirt.virt_type, []
|
||||
)
|
||||
# construct the corresponding standard trait from the VIF model name
|
||||
return {
|
||||
f'COMPUTE_NET_VIF_MODEL_{model.replace("-", "_").upper()}': model
|
||||
in supported_models for model in all_models
|
||||
}
|
||||
|
||||
def _get_storage_bus_traits(self):
|
||||
"""Get storage bus traits based on the currently enabled virt_type.
|
||||
|
||||
For QEMU and KVM this function uses the information returned by the
|
||||
libvirt domain capabilities API. For other virt types we generate the
|
||||
traits based on the static information in the blockinfo module.
|
||||
|
||||
Not all traits generated by this function may be valid and the result
|
||||
should be validated.
|
||||
|
||||
:return: A dict of trait names mapped to boolean values.
|
||||
"""
|
||||
all_buses = set(itertools.chain(
|
||||
*blockinfo.SUPPORTED_STORAGE_BUSES.values()
|
||||
))
|
||||
supported_buses = blockinfo.SUPPORTED_STORAGE_BUSES.get(
|
||||
CONF.libvirt.virt_type, []
|
||||
)
|
||||
|
||||
if CONF.libvirt.virt_type in ('qemu', 'kvm'):
|
||||
dom_caps = self._host.get_domain_capabilities()
|
||||
supported_buses = set()
|
||||
for arch_type in dom_caps:
|
||||
for machine_type in dom_caps[arch_type]:
|
||||
supported_buses.update(
|
||||
dom_caps[arch_type][machine_type].devices.disk.buses
|
||||
)
|
||||
else:
|
||||
supported_buses = blockinfo.SUPPORTED_STORAGE_BUSES.get(
|
||||
CONF.libvirt.virt_type, []
|
||||
)
|
||||
|
||||
# construct the corresponding standard trait from the storage bus name
|
||||
return {
|
||||
f'COMPUTE_STORAGE_BUS_{bus.upper()}': bus in supported_buses
|
||||
for bus in all_buses
|
||||
f'COMPUTE_STORAGE_BUS_{bus.replace("-", "_").upper()}': bus in
|
||||
supported_buses for bus in all_buses
|
||||
}
|
||||
|
||||
def _get_video_model_traits(self):
|
||||
"""Get video model traits from libvirt.
|
||||
|
||||
Not all traits generated by this function may be valid and the result
|
||||
should be validated.
|
||||
|
||||
:return: A dict of trait names mapped to boolean values.
|
||||
"""
|
||||
all_models = fields.VideoModel.ALL
|
||||
|
||||
dom_caps = self._host.get_domain_capabilities()
|
||||
supported_models = set()
|
||||
for arch_type in dom_caps:
|
||||
for machine_type in dom_caps[arch_type]:
|
||||
supported_models.update(
|
||||
dom_caps[arch_type][machine_type].devices.video.models
|
||||
)
|
||||
|
||||
# construct the corresponding standard trait from the video model name
|
||||
return {
|
||||
f'COMPUTE_GRAPHICS_MODEL_{model.replace("-", "_").upper()}': model
|
||||
in supported_models for model in all_models
|
||||
}
|
||||
|
||||
def _get_cpu_traits(self):
|
||||
|
|
|
@ -58,41 +58,46 @@ MIN_QEMU_INTERFACE_MTU = (2, 9, 0)
|
|||
MIN_LIBVIRT_TX_QUEUE_SIZE = (3, 7, 0)
|
||||
MIN_QEMU_TX_QUEUE_SIZE = (2, 10, 0)
|
||||
|
||||
SUPPORTED_VIF_MODELS = {
|
||||
'qemu': [
|
||||
network_model.VIF_MODEL_VIRTIO,
|
||||
network_model.VIF_MODEL_NE2K_PCI,
|
||||
network_model.VIF_MODEL_PCNET,
|
||||
network_model.VIF_MODEL_RTL8139,
|
||||
network_model.VIF_MODEL_E1000,
|
||||
network_model.VIF_MODEL_LAN9118,
|
||||
network_model.VIF_MODEL_SPAPR_VLAN],
|
||||
'kvm': [
|
||||
network_model.VIF_MODEL_VIRTIO,
|
||||
network_model.VIF_MODEL_NE2K_PCI,
|
||||
network_model.VIF_MODEL_PCNET,
|
||||
network_model.VIF_MODEL_RTL8139,
|
||||
network_model.VIF_MODEL_E1000,
|
||||
network_model.VIF_MODEL_SPAPR_VLAN],
|
||||
'xen': [
|
||||
network_model.VIF_MODEL_NETFRONT,
|
||||
network_model.VIF_MODEL_NE2K_PCI,
|
||||
network_model.VIF_MODEL_PCNET,
|
||||
network_model.VIF_MODEL_RTL8139,
|
||||
network_model.VIF_MODEL_E1000],
|
||||
'lxc': [],
|
||||
'uml': [],
|
||||
'parallels': [
|
||||
network_model.VIF_MODEL_VIRTIO,
|
||||
network_model.VIF_MODEL_RTL8139,
|
||||
network_model.VIF_MODEL_E1000],
|
||||
}
|
||||
|
||||
|
||||
def is_vif_model_valid_for_virt(virt_type, vif_model):
|
||||
valid_models = {
|
||||
'qemu': [network_model.VIF_MODEL_VIRTIO,
|
||||
network_model.VIF_MODEL_NE2K_PCI,
|
||||
network_model.VIF_MODEL_PCNET,
|
||||
network_model.VIF_MODEL_RTL8139,
|
||||
network_model.VIF_MODEL_E1000,
|
||||
network_model.VIF_MODEL_LAN9118,
|
||||
network_model.VIF_MODEL_SPAPR_VLAN],
|
||||
'kvm': [network_model.VIF_MODEL_VIRTIO,
|
||||
network_model.VIF_MODEL_NE2K_PCI,
|
||||
network_model.VIF_MODEL_PCNET,
|
||||
network_model.VIF_MODEL_RTL8139,
|
||||
network_model.VIF_MODEL_E1000,
|
||||
network_model.VIF_MODEL_SPAPR_VLAN],
|
||||
'xen': [network_model.VIF_MODEL_NETFRONT,
|
||||
network_model.VIF_MODEL_NE2K_PCI,
|
||||
network_model.VIF_MODEL_PCNET,
|
||||
network_model.VIF_MODEL_RTL8139,
|
||||
network_model.VIF_MODEL_E1000],
|
||||
'lxc': [],
|
||||
'uml': [],
|
||||
'parallels': [network_model.VIF_MODEL_VIRTIO,
|
||||
network_model.VIF_MODEL_RTL8139,
|
||||
network_model.VIF_MODEL_E1000],
|
||||
}
|
||||
|
||||
if vif_model is None:
|
||||
return True
|
||||
|
||||
if virt_type not in valid_models:
|
||||
if virt_type not in SUPPORTED_VIF_MODELS:
|
||||
raise exception.UnsupportedVirtType(virt=virt_type)
|
||||
|
||||
return vif_model in valid_models[virt_type]
|
||||
return vif_model in SUPPORTED_VIF_MODELS[virt_type]
|
||||
|
||||
|
||||
def set_vf_interface_vlan(pci_addr, mac_addr, vlan=0):
|
||||
|
|
Loading…
Reference in New Issue