Skip to content

Commit e3b0412

Browse files
committed
libvirt: Add vTPM config support
There are two changes to our XML element generation code needed for vTPM support: the '<secret>' element needs to gain support for the 'vtpm' usage type, and a wholly new '<tpm>' element [1]. None of this is actually used yet, outside of tests. That will come later. Part of blueprint add-emulated-virtual-tpm [1] https://libvirt.org/formatsecret.html [2] https://libvirt.org/formatdomain.html#elementsTpm Change-Id: I8b7d2d45963160bc8acf19f36f7945c7545570b3 Signed-off-by: Stephen Finucane <[email protected]>
1 parent 969a6d4 commit e3b0412

File tree

5 files changed

+121
-14
lines changed

5 files changed

+121
-14
lines changed

nova/tests/unit/virt/libvirt/test_config.py

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from nova.objects import fields as obj_fields
2020
from nova import test
2121
from nova.tests.unit.virt.libvirt import fake_libvirt_data
22+
from nova.virt import hardware
2223
from nova.virt.libvirt import config
2324

2425

@@ -3729,16 +3730,16 @@ class LibvirtConfigSecretTest(LibvirtConfigBaseTest):
37293730

37303731
def test_config_secret_volume(self):
37313732
secret = config.LibvirtConfigSecret()
3732-
secret.ephemeral = True
3733-
secret.private = True
3733+
secret.ephemeral = False
3734+
secret.private = False
37343735
secret.description = 'sample desc'
37353736
secret.uuid = 'c7a5fdbd-edaf-9455-926a-d65c16db1809'
37363737
secret.usage_type = 'volume'
37373738
secret.usage_id = 'sample_volume'
37383739

37393740
xml = secret.to_xml()
37403741
expected_xml = """
3741-
<secret ephemeral="yes" private="yes">
3742+
<secret ephemeral="no" private="no">
37423743
<description>sample desc</description>
37433744
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
37443745
<usage type="volume">
@@ -3750,15 +3751,15 @@ def test_config_secret_volume(self):
37503751

37513752
def test_config_secret_ceph(self):
37523753
secret = config.LibvirtConfigSecret()
3753-
secret.ephemeral = True
3754-
secret.private = True
3754+
secret.ephemeral = False
3755+
secret.private = False
37553756
secret.description = 'sample desc'
37563757
secret.usage_type = 'ceph'
37573758
secret.usage_id = 'sample_name'
37583759

37593760
xml = secret.to_xml()
37603761
expected_xml = """
3761-
<secret ephemeral="yes" private="yes">
3762+
<secret ephemeral="no" private="no">
37623763
<description>sample desc</description>
37633764
<usage type="ceph">
37643765
<name>sample_name</name>
@@ -3767,17 +3768,36 @@ def test_config_secret_ceph(self):
37673768

37683769
self.assertXmlEqual(expected_xml, xml)
37693770

3770-
def test_config_secret_iscsi(self):
3771+
def test_config_secret_vtpm(self):
37713772
secret = config.LibvirtConfigSecret()
37723773
secret.ephemeral = True
37733774
secret.private = True
3775+
secret.usage_type = 'vtpm'
3776+
secret.usage_id = 'sample_name'
3777+
secret.uuid = uuids.vtpm
3778+
3779+
xml = secret.to_xml()
3780+
expected_xml = f"""
3781+
<secret ephemeral="yes" private="yes">
3782+
<uuid>{uuids.vtpm}</uuid>
3783+
<usage type="vtpm">
3784+
<name>sample_name</name>
3785+
</usage>
3786+
</secret>"""
3787+
3788+
self.assertXmlEqual(expected_xml, xml)
3789+
3790+
def test_config_secret_iscsi(self):
3791+
secret = config.LibvirtConfigSecret()
3792+
secret.ephemeral = False
3793+
secret.private = False
37743794
secret.description = 'sample desc'
37753795
secret.usage_type = 'iscsi'
37763796
secret.usage_id = 'sample_target'
37773797

37783798
xml = secret.to_xml()
37793799
expected_xml = """
3780-
<secret ephemeral="yes" private="yes">
3800+
<secret ephemeral="no" private="no">
37813801
<description>sample desc</description>
37823802
<usage type="iscsi">
37833803
<target>sample_target</target>
@@ -3937,3 +3957,51 @@ def test_parse_domain_caps_devices(self):
39373957
obj.disk, config.LibvirtConfigDomainCapsDiskBuses)
39383958
self.assertIsInstance(
39393959
obj.video, config.LibvirtConfigDomainCapsVideoModels)
3960+
3961+
3962+
class LibvirtConfigTPMTest(LibvirtConfigBaseTest):
3963+
3964+
def test_config_tpm_tis_1_2(self):
3965+
vtpm_config = hardware.VTPMConfig('1.2', 'tpm-tis')
3966+
vtpm_secret_uuid = 'b028130c-bdcb-4d5f-9bca-b9175ca6c28c'
3967+
expected_xml = """
3968+
<tpm model='tpm-tis'>
3969+
<backend type='emulator' version='1.2'>
3970+
<encryption secret='b028130c-bdcb-4d5f-9bca-b9175ca6c28c'/>
3971+
</backend>
3972+
</tpm>"""
3973+
3974+
tpm = config.LibvirtConfigGuestVTPM(vtpm_config, vtpm_secret_uuid)
3975+
xml = tpm.to_xml()
3976+
3977+
self.assertXmlEqual(expected_xml, xml)
3978+
3979+
def test_config_tpm_tis_2_0(self):
3980+
vtpm_config = hardware.VTPMConfig('2.0', 'tpm-tis')
3981+
vtpm_secret_uuid = 'b028130c-bdcb-4d5f-9bca-b9175ca6c28c'
3982+
expected_xml = """
3983+
<tpm model='tpm-tis'>
3984+
<backend type='emulator' version='2.0'>
3985+
<encryption secret='b028130c-bdcb-4d5f-9bca-b9175ca6c28c'/>
3986+
</backend>
3987+
</tpm>"""
3988+
3989+
tpm = config.LibvirtConfigGuestVTPM(vtpm_config, vtpm_secret_uuid)
3990+
xml = tpm.to_xml()
3991+
3992+
self.assertXmlEqual(expected_xml, xml)
3993+
3994+
def test_config_tpm_crb_2_0(self):
3995+
vtpm_config = hardware.VTPMConfig('2.0', 'tpm-crb')
3996+
vtpm_secret_uuid = 'b028130c-bdcb-4d5f-9bca-b9175ca6c28c'
3997+
expected_xml = """
3998+
<tpm model='tpm-crb'>
3999+
<backend type='emulator' version='2.0'>
4000+
<encryption secret='b028130c-bdcb-4d5f-9bca-b9175ca6c28c'/>
4001+
</backend>
4002+
</tpm>"""
4003+
4004+
tpm = config.LibvirtConfigGuestVTPM(vtpm_config, vtpm_secret_uuid)
4005+
xml = tpm.to_xml()
4006+
4007+
self.assertXmlEqual(expected_xml, xml)

nova/tests/unit/virt/libvirt/test_host.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ def test_create_secret(self, mock_sec):
917917
self.host.create_secret('ceph', 'cephvol')
918918
self.host.create_secret('iscsi', 'iscsivol')
919919
self.host.create_secret('volume', 'vol')
920+
self.host.create_secret('vtpm', 'vtpmdev')
920921
self.assertRaises(exception.NovaException,
921922
self.host.create_secret, "foo", "foovol")
922923

nova/virt/hardware.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
MEMPAGES_ANY = -3
4343

4444

45+
class VTPMConfig(ty.NamedTuple):
46+
version: str
47+
model: str
48+
49+
4550
def get_vcpu_pin_set():
4651
"""Parse ``vcpu_pin_set`` config.
4752

nova/virt/libvirt/config.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,33 @@ def uses_virtio(self):
958958
return False
959959

960960

961+
class LibvirtConfigGuestVTPM(LibvirtConfigGuestDevice):
962+
963+
def __init__(self, vtpm_config, vtpm_secret_uuid, **kwargs):
964+
super(LibvirtConfigGuestVTPM, self).__init__(root_name="tpm", **kwargs)
965+
966+
self.version = vtpm_config.version
967+
self.model = vtpm_config.model
968+
self.secret_uuid = vtpm_secret_uuid
969+
970+
def format_dom(self):
971+
# <tpm model='$model'>
972+
dev = super(LibvirtConfigGuestVTPM, self).format_dom()
973+
dev.set("model", self.model)
974+
# <backend type='emulator' version='$version'>
975+
back = etree.Element("backend")
976+
back.set("type", "emulator")
977+
back.set("version", self.version)
978+
# <encryption secret='$secret_uuid'/>
979+
enc = etree.Element("encryption")
980+
enc.set("secret", self.secret_uuid)
981+
982+
back.append(enc)
983+
dev.append(back)
984+
985+
return dev
986+
987+
961988
class LibvirtConfigGuestDisk(LibvirtConfigGuestDevice):
962989

963990
def __init__(self, **kwargs):
@@ -3272,7 +3299,7 @@ def format_dom(self):
32723299
root.append(self._text_node("uuid", str(self.uuid)))
32733300
usage = self._new_node("usage")
32743301
usage.set("type", self.usage_type)
3275-
if self.usage_type == 'ceph':
3302+
if self.usage_type in ('ceph', 'vtpm'):
32763303
usage.append(self._text_node('name', str(self.usage_id)))
32773304
elif self.usage_type == 'iscsi':
32783305
usage.append(self._text_node('target', str(self.usage_id)))

nova/virt/libvirt/host.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -996,24 +996,30 @@ def find_secret(self, usage_type, usage_id):
996996
if e.get_error_code() == libvirt.VIR_ERR_NO_SECRET:
997997
return None
998998

999-
def create_secret(self, usage_type, usage_id, password=None):
999+
def create_secret(self, usage_type, usage_id, password=None, uuid=None):
10001000
"""Create a secret.
10011001
1002-
:param usage_type: one of 'iscsi', 'ceph', 'rbd' or 'volume'
1003-
'rbd' will be converted to 'ceph'.
1002+
:param usage_type: one of 'iscsi', 'ceph', 'rbd', 'volume', 'vtpm'.
1003+
'rbd' will be converted to 'ceph'. 'vtpm' secrets
1004+
are private and ephemeral; others are not.
10041005
:param usage_id: name of resource in secret
10051006
:param password: optional secret value to set
1007+
:param uuid: optional UUID of the secret; else one is generated by
1008+
libvirt
10061009
"""
10071010
secret_conf = vconfig.LibvirtConfigSecret()
1008-
secret_conf.ephemeral = False
1009-
secret_conf.private = False
1011+
secret_conf.ephemeral = usage_type == 'vtpm'
1012+
secret_conf.private = usage_type == 'vtpm'
10101013
secret_conf.usage_id = usage_id
1014+
secret_conf.uuid = uuid
10111015
if usage_type in ('rbd', 'ceph'):
10121016
secret_conf.usage_type = 'ceph'
10131017
elif usage_type == 'iscsi':
10141018
secret_conf.usage_type = 'iscsi'
10151019
elif usage_type == 'volume':
10161020
secret_conf.usage_type = 'volume'
1021+
elif usage_type == 'vtpm':
1022+
secret_conf.usage_type = 'vtpm'
10171023
else:
10181024
msg = _("Invalid usage_type: %s")
10191025
raise exception.InternalError(msg % usage_type)

0 commit comments

Comments
 (0)