Skip to content

Commit b900463

Browse files
committed
Add CVM boot test suite
Signed-off-by: Thien Trung Vuong <[email protected]>
1 parent 2d64f61 commit b900463

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

microsoft/testsuites/cvm/cvm_boot.py

+176
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT license.
3+
4+
from pathlib import Path
5+
from typing import Any, List, cast
6+
7+
from assertpy.assertpy import assert_that, assert_warn
8+
9+
from lisa import (
10+
Environment,
11+
Logger,
12+
Node,
13+
RemoteNode,
14+
TestCaseMetadata,
15+
TestSuite,
16+
TestSuiteMetadata,
17+
)
18+
from lisa.features.security_profile import (
19+
CvmEnabled,
20+
SecurityProfile,
21+
SecurityProfileSettings,
22+
)
23+
from lisa.operating_system import CBLMariner, Posix
24+
from lisa.sut_orchestrator import AZURE
25+
from lisa.testsuite import TestResult, simple_requirement
26+
from lisa.tools import Lsblk, Reboot, Tpm2
27+
from lisa.tools.lsblk import PartitionInfo
28+
from lisa.util import (
29+
SkippedException,
30+
TcpConnectionException,
31+
UnsupportedDistroException,
32+
constants,
33+
)
34+
from lisa.util.shell import wait_tcp_port_ready
35+
36+
37+
@TestSuiteMetadata(
38+
area="cvm",
39+
category="functional",
40+
description="""This test suite covers some common scenarios related to
41+
CVM boot on Azure.
42+
""",
43+
)
44+
class CVMBootTestSuite(TestSuite):
45+
def before_case(self, log: Logger, **kwargs: Any) -> None:
46+
node: Node = kwargs["node"]
47+
if not isinstance(node.os, CBLMariner):
48+
raise SkippedException(
49+
UnsupportedDistroException(
50+
node.os, "CVM boot test supports only Azure Linux."
51+
)
52+
)
53+
54+
@TestCaseMetadata(
55+
description="""This test verifies that TPM enrollment is done correctly on
56+
a CVM with encrypted root partition
57+
""",
58+
priority=2,
59+
requirement=simple_requirement(
60+
supported_features=[CvmEnabled()],
61+
supported_platform_type=[AZURE],
62+
),
63+
)
64+
def verify_encrypted_root_partition(
65+
self,
66+
log: Logger,
67+
node: RemoteNode,
68+
environment: Environment,
69+
log_path: Path,
70+
result: TestResult,
71+
) -> None:
72+
security_profile_settings = cast(
73+
SecurityProfileSettings, node.features[SecurityProfile].get_settings()
74+
)
75+
if not security_profile_settings.encrypt_disk:
76+
raise SkippedException("This test requires disk encryption to be enabled")
77+
lsblk = node.tools[Lsblk]
78+
disks = lsblk.get_disks(force_run=True)
79+
partitions: List[PartitionInfo] = next(
80+
(d.partitions for d in disks if d.name == "sda"), []
81+
)
82+
assert_that(partitions, "Cannot find a disk named 'sda'").is_not_empty()
83+
root_partition = next((p for p in partitions if p.name == "sda2"), None)
84+
assert_that(root_partition, "Cannot locate root partition").is_not_none()
85+
assert isinstance(root_partition, PartitionInfo)
86+
assert_that(root_partition.fstype).is_equal_to("crypto_LUKS")
87+
88+
@TestCaseMetadata(
89+
description="""This test case verifies that a CVM can still boot if any boot
90+
component is upgraded.
91+
92+
Steps:
93+
1. On first boot, check current PCR values for PCR4 and PCR7
94+
2. Get current boot components versions (e.g. shim, grub, systemd-boot, uki)
95+
3. Run a package upgrade to update boot components
96+
4. Get new boot components versions to see if anything has changed
97+
5. Reboot the CVM, make sure the CVM can boot up again
98+
6. PCR4 should change if any of the boot components is upgraded
99+
7. PCR7 may change (for example, if a signing certificate is changed)
100+
""",
101+
priority=1,
102+
requirement=simple_requirement(
103+
supported_features=[CvmEnabled()],
104+
supported_platform_type=[AZURE],
105+
),
106+
)
107+
def verify_boot_success_after_component_upgrade(
108+
self,
109+
log: Logger,
110+
node: RemoteNode,
111+
environment: Environment,
112+
log_path: Path,
113+
result: TestResult,
114+
**kwargs: Any,
115+
) -> None:
116+
posix_os: Posix = cast(Posix, node.os)
117+
# First boot
118+
# - Check PCR values (PCR4, PCR7)
119+
pcrs_before_reboot = node.tools[Tpm2].pcrread(pcrs=[4, 7])
120+
121+
# - Get current boot components versions (shim, systemd-boot, kernel-uki)
122+
boot_components = ["shim", "systemd-boot", "kernel-uki"]
123+
boot_components_versions = dict()
124+
for pkg in boot_components:
125+
pkg_info = posix_os.query_package(pkg)
126+
boot_components_versions[pkg] = pkg_info.version_str
127+
128+
# - Upgrade boot components
129+
posix_os.update_packages(boot_components)
130+
131+
# - Get new boot components versions
132+
boot_components_new_versions = dict()
133+
for pkg in boot_components:
134+
pkg_info = posix_os.query_package(pkg)
135+
boot_components_new_versions[pkg] = pkg_info.version_str
136+
137+
# Reboot
138+
# - Make sure VM boots up again
139+
reboot_tool = node.tools[Reboot]
140+
reboot_tool.reboot_and_check_panic(log_path)
141+
is_ready, tcp_error_code = wait_tcp_port_ready(
142+
node.connection_info[constants.ENVIRONMENTS_NODES_REMOTE_ADDRESS],
143+
node.connection_info[constants.ENVIRONMENTS_NODES_REMOTE_PORT],
144+
log=log,
145+
)
146+
if not is_ready:
147+
raise TcpConnectionException(
148+
node.connection_info[constants.ENVIRONMENTS_NODES_REMOTE_ADDRESS],
149+
node.connection_info[constants.ENVIRONMENTS_NODES_REMOTE_PORT],
150+
tcp_error_code,
151+
"no panic found in serial log",
152+
)
153+
154+
pcrs_after_reboot = node.tools[Tpm2].pcrread(pcrs=[4, 7])
155+
boot_component_changed = any(
156+
boot_components_versions[pkg] != boot_components_new_versions[pkg]
157+
for pkg in boot_components
158+
)
159+
160+
# - PCR4 should change if any of the boot components is upgraded
161+
# - PCR7 may change if a signing cert is changed
162+
if boot_component_changed:
163+
assert_that(
164+
pcrs_after_reboot[4],
165+
"PCR4 value is still the same even though a boot component changed",
166+
).is_not_equal_to(pcrs_before_reboot[4])
167+
assert_warn(
168+
pcrs_after_reboot[7],
169+
"PCR7 changed after a boot component changed, this may happen if a"
170+
" signing certificate was updated",
171+
).is_equal_to(pcrs_before_reboot[7])
172+
else:
173+
assert_that(
174+
pcrs_after_reboot,
175+
"PCR values changed even though no boot component was updated",
176+
).is_equal_to(pcrs_before_reboot)

0 commit comments

Comments
 (0)