libvirt: Report available TPM models
Libvirt 8.0.0 introduced the new domain capabilities API filed to present available TPM models. This introduces the logic to report available TPM models as compute node traits, and use that trait for scheduling to ensure a request tpm model is available at the compute node where the instance is being launched. Depends-on: https://review.opendev.org/c/openstack/os-traits/+/909107 Implements: blueprint libvirt-detect-vtpm-support Change-Id: Iec98e7b0d19f37f094152a61a26790fcdf3328d9
This commit is contained in:
+13
-7
@@ -295,14 +295,20 @@ class ResourceRequest(object):
|
||||
if not vtpm_config:
|
||||
return
|
||||
|
||||
# Require the appropriate vTPM version support trait on a host.
|
||||
if vtpm_config.version == obj_fields.TPMVersion.v1_2:
|
||||
trait = os_traits.COMPUTE_SECURITY_TPM_1_2
|
||||
else:
|
||||
trait = os_traits.COMPUTE_SECURITY_TPM_2_0
|
||||
# Require the appropriate vTPM model support trait on a host.
|
||||
model_trait = os_traits.COMPUTE_SECURITY_TPM_TIS
|
||||
if vtpm_config.model == obj_fields.TPMModel.CRB:
|
||||
model_trait = os_traits.COMPUTE_SECURITY_TPM_CRB
|
||||
|
||||
self._add_trait(trait, 'required')
|
||||
LOG.debug("Requiring emulated TPM support via trait %s.", trait)
|
||||
# Require the appropriate vTPM version support trait on a host.
|
||||
version_trait = os_traits.COMPUTE_SECURITY_TPM_1_2
|
||||
if vtpm_config.version == obj_fields.TPMVersion.v2_0:
|
||||
version_trait = os_traits.COMPUTE_SECURITY_TPM_2_0
|
||||
|
||||
self._add_trait(model_trait, 'required')
|
||||
self._add_trait(version_trait, 'required')
|
||||
LOG.debug("Requiring emulated TPM support via trait %s and %s.",
|
||||
version_trait, model_trait)
|
||||
|
||||
def _translate_memory_encryption(self, flavor, image):
|
||||
"""When the hw:mem_encryption extra spec or the hw_mem_encryption
|
||||
|
||||
Vendored
-1
@@ -2122,7 +2122,6 @@ class Connection(object):
|
||||
<tpm supported='yes'>
|
||||
<enum name='model'>
|
||||
<value>tpm-tis</value>
|
||||
<value>tpm-crb</value>
|
||||
</enum>
|
||||
<enum name='backendModel'>
|
||||
<value>passthrough</value>
|
||||
|
||||
@@ -1308,6 +1308,33 @@ class TestUtils(TestUtilsBase):
|
||||
rr = utils.ResourceRequest.from_request_spec(rs)
|
||||
self.assertResourceRequestsEqual(expected, rr)
|
||||
|
||||
def test_resource_request_from_request_spec_with_vtpm_version_only(self):
|
||||
flavor = objects.Flavor(
|
||||
vcpus=1, memory_mb=1024, root_gb=10, ephemeral_gb=5, swap=0,
|
||||
extra_specs={'hw:tpm_version': '1.2'},
|
||||
)
|
||||
image = objects.ImageMeta(
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_tpm_version='1.2',
|
||||
)
|
||||
)
|
||||
expected = FakeResourceRequest()
|
||||
expected._rg_by_id[None] = objects.RequestGroup(
|
||||
use_same_provider=False,
|
||||
required_traits={
|
||||
'COMPUTE_SECURITY_TPM_1_2',
|
||||
'COMPUTE_SECURITY_TPM_TIS',
|
||||
},
|
||||
resources={
|
||||
'VCPU': 1,
|
||||
'MEMORY_MB': 1024,
|
||||
'DISK_GB': 15,
|
||||
},
|
||||
)
|
||||
rs = objects.RequestSpec(flavor=flavor, image=image, is_bfv=False)
|
||||
rr = utils.ResourceRequest.from_request_spec(rs)
|
||||
self.assertResourceRequestsEqual(expected, rr)
|
||||
|
||||
def test_resource_request_from_request_spec_with_vtpm_1_2(self):
|
||||
flavor = objects.Flavor(
|
||||
vcpus=1, memory_mb=1024, root_gb=10, ephemeral_gb=5, swap=0,
|
||||
@@ -1322,7 +1349,10 @@ class TestUtils(TestUtilsBase):
|
||||
expected = FakeResourceRequest()
|
||||
expected._rg_by_id[None] = objects.RequestGroup(
|
||||
use_same_provider=False,
|
||||
required_traits={'COMPUTE_SECURITY_TPM_1_2'},
|
||||
required_traits={
|
||||
'COMPUTE_SECURITY_TPM_1_2',
|
||||
'COMPUTE_SECURITY_TPM_TIS',
|
||||
},
|
||||
resources={
|
||||
'VCPU': 1,
|
||||
'MEMORY_MB': 1024,
|
||||
@@ -1347,7 +1377,10 @@ class TestUtils(TestUtilsBase):
|
||||
expected = FakeResourceRequest()
|
||||
expected._rg_by_id[None] = objects.RequestGroup(
|
||||
use_same_provider=False,
|
||||
required_traits={'COMPUTE_SECURITY_TPM_2_0'},
|
||||
required_traits={
|
||||
'COMPUTE_SECURITY_TPM_2_0',
|
||||
'COMPUTE_SECURITY_TPM_CRB',
|
||||
},
|
||||
resources={
|
||||
'VCPU': 1,
|
||||
'MEMORY_MB': 1024,
|
||||
|
||||
@@ -997,6 +997,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
'COMPUTE_NET_VIRTIO_PACKED': True,
|
||||
'COMPUTE_SECURITY_TPM_1_2': False,
|
||||
'COMPUTE_SECURITY_TPM_2_0': False,
|
||||
'COMPUTE_SECURITY_TPM_TIS': False,
|
||||
'COMPUTE_SECURITY_TPM_CRB': False,
|
||||
'COMPUTE_STORAGE_BUS_VIRTIO': True,
|
||||
'COMPUTE_VIOMMU_MODEL_AUTO': True,
|
||||
'COMPUTE_VIOMMU_MODEL_INTEL': True,
|
||||
@@ -1049,6 +1051,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
'COMPUTE_NET_VIRTIO_PACKED': True,
|
||||
'COMPUTE_SECURITY_TPM_1_2': False,
|
||||
'COMPUTE_SECURITY_TPM_2_0': False,
|
||||
'COMPUTE_SECURITY_TPM_TIS': False,
|
||||
'COMPUTE_SECURITY_TPM_CRB': False,
|
||||
'COMPUTE_VIOMMU_MODEL_AUTO': True,
|
||||
'COMPUTE_VIOMMU_MODEL_INTEL': True,
|
||||
'COMPUTE_VIOMMU_MODEL_SMMUV3': True,
|
||||
@@ -22506,7 +22510,9 @@ class TestUpdateProviderTree(test.NoDBTestCase):
|
||||
def test_update_provider_tree_with_tpm_traits(self):
|
||||
self.flags(swtpm_enabled=True, group='libvirt')
|
||||
self._test_update_provider_tree()
|
||||
for trait in ('COMPUTE_SECURITY_TPM_2_0', 'COMPUTE_SECURITY_TPM_1_2'):
|
||||
for trait in (
|
||||
'COMPUTE_SECURITY_TPM_TIS', 'COMPUTE_SECURITY_TPM_CRB',
|
||||
'COMPUTE_SECURITY_TPM_2_0', 'COMPUTE_SECURITY_TPM_1_2'):
|
||||
self.assertIn(trait, self.pt.data(self.cn_rp['uuid']).traits)
|
||||
|
||||
@mock.patch.object(
|
||||
@@ -22516,7 +22522,9 @@ class TestUpdateProviderTree(test.NoDBTestCase):
|
||||
def test_update_provider_tree_with_tpm_traits_supported(self):
|
||||
self.flags(swtpm_enabled=True, group='libvirt')
|
||||
self._test_update_provider_tree()
|
||||
for trait in ('COMPUTE_SECURITY_TPM_2_0', 'COMPUTE_SECURITY_TPM_1_2'):
|
||||
for trait in (
|
||||
'COMPUTE_SECURITY_TPM_TIS', 'COMPUTE_SECURITY_TPM_CRB',
|
||||
'COMPUTE_SECURITY_TPM_2_0', 'COMPUTE_SECURITY_TPM_1_2'):
|
||||
self.assertIn(trait, self.pt.data(self.cn_rp['uuid']).traits)
|
||||
|
||||
@mock.patch.object(
|
||||
@@ -22527,9 +22535,9 @@ class TestUpdateProviderTree(test.NoDBTestCase):
|
||||
def test_update_provider_tree_with_tpm_traits_versions(self):
|
||||
self.flags(swtpm_enabled=True, group='libvirt')
|
||||
self._test_update_provider_tree()
|
||||
for trait in ('COMPUTE_SECURITY_TPM_2_0',):
|
||||
for trait in ('COMPUTE_SECURITY_TPM_TIS', 'COMPUTE_SECURITY_TPM_2_0'):
|
||||
self.assertIn(trait, self.pt.data(self.cn_rp['uuid']).traits)
|
||||
for trait in ('COMPUTE_SECURITY_TPM_1_2',):
|
||||
for trait in ('COMPUTE_SECURITY_TPM_CRB', 'COMPUTE_SECURITY_TPM_1_2',):
|
||||
self.assertNotIn(trait, self.pt.data(self.cn_rp['uuid']).traits)
|
||||
|
||||
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver.'
|
||||
|
||||
@@ -920,7 +920,7 @@ class HostTestCase(test.NoDBTestCase):
|
||||
type(caps.devices.tpm))
|
||||
self.assertTrue(caps.devices.tpm.supported)
|
||||
self.assertEqual(
|
||||
['tpm-tis', 'tpm-crb'],
|
||||
['tpm-tis'],
|
||||
caps.devices.tpm.models
|
||||
)
|
||||
self.assertEqual(
|
||||
|
||||
@@ -12902,23 +12902,43 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
return {
|
||||
ot.COMPUTE_SECURITY_TPM_2_0: False,
|
||||
ot.COMPUTE_SECURITY_TPM_1_2: False,
|
||||
ot.COMPUTE_SECURITY_TPM_TIS: False,
|
||||
ot.COMPUTE_SECURITY_TPM_CRB: False,
|
||||
}
|
||||
|
||||
tpm_models = self._host.tpm_models
|
||||
tpm_versions = self._host.tpm_versions
|
||||
# libvirt < 8.6 does not provide supported versions in domain
|
||||
# capabilities
|
||||
|
||||
# TODO(tkajinam): Remove this once libvirt>=8.6.0 is required.
|
||||
tr = {}
|
||||
if tpm_models is None:
|
||||
# TODO(tkajinam): Remove this fallback once libvirt>=8.0.0 is
|
||||
# required.
|
||||
tr.update({
|
||||
ot.COMPUTE_SECURITY_TPM_TIS: True,
|
||||
ot.COMPUTE_SECURITY_TPM_CRB: True,
|
||||
})
|
||||
else:
|
||||
tr.update({
|
||||
ot.COMPUTE_SECURITY_TPM_TIS: 'tpm-tis' in tpm_models,
|
||||
ot.COMPUTE_SECURITY_TPM_CRB: 'tpm-crb' in tpm_models,
|
||||
})
|
||||
|
||||
if tpm_versions is None:
|
||||
return {
|
||||
# TODO(tkajinam): Remove this fallback once libvirt>=8.6.0 is
|
||||
# required.
|
||||
tr.update({
|
||||
ot.COMPUTE_SECURITY_TPM_2_0: True,
|
||||
ot.COMPUTE_SECURITY_TPM_1_2: True,
|
||||
}
|
||||
})
|
||||
else:
|
||||
tr.update({
|
||||
ot.COMPUTE_SECURITY_TPM_2_0: '2.0' in tpm_versions,
|
||||
ot.COMPUTE_SECURITY_TPM_1_2: '1.2' in tpm_versions,
|
||||
})
|
||||
|
||||
return {
|
||||
ot.COMPUTE_SECURITY_TPM_2_0: '2.0' in tpm_versions,
|
||||
ot.COMPUTE_SECURITY_TPM_1_2: '1.2' in tpm_versions,
|
||||
}
|
||||
return tr
|
||||
|
||||
def _get_vif_model_traits(self) -> ty.Dict[str, bool]:
|
||||
"""Get vif model traits based on the currently enabled virt_type.
|
||||
|
||||
@@ -1884,6 +1884,24 @@ class Host(object):
|
||||
# safe guard
|
||||
return []
|
||||
|
||||
@property
|
||||
def tpm_models(self) -> ty.Optional[ty.List[str]]:
|
||||
# we only check the host architecture and the first machine type
|
||||
# because vtpm support is independent from cpu architecture
|
||||
arch = self.get_capabilities().host.cpu.arch
|
||||
domain_caps = self.get_domain_capabilities()
|
||||
for machine_type in domain_caps[arch]:
|
||||
_tpm = domain_caps[arch][machine_type].devices.tpm
|
||||
# TODO(tkajinam): Remove first check once libvirt >= 8.0.0 is
|
||||
# required
|
||||
# TODO(tkajinam): Remove second check once libvirt >= 8.6.0 is
|
||||
# required
|
||||
if _tpm is None or _tpm.models is None:
|
||||
return None
|
||||
return _tpm.models
|
||||
# safe guard
|
||||
return []
|
||||
|
||||
def _kernel_supports_amd_sev(self) -> bool:
|
||||
if not os.path.exists(SEV_KERNEL_PARAM_FILE):
|
||||
LOG.debug("%s does not exist", SEV_KERNEL_PARAM_FILE)
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ psutil>=3.2.2 # BSD
|
||||
oslo.versionedobjects>=1.35.0 # Apache-2.0
|
||||
os-brick>=5.2 # Apache-2.0
|
||||
os-resource-classes>=1.1.0 # Apache-2.0
|
||||
os-traits>=3.0.0 # Apache-2.0
|
||||
os-traits>=3.1.0 # Apache-2.0
|
||||
os-vif>=3.1.0 # Apache-2.0
|
||||
castellan>=0.16.0 # Apache-2.0
|
||||
microversion-parse>=0.2.1 # Apache-2.0
|
||||
|
||||
Reference in New Issue
Block a user