Skip to content

Commit 33c7a1a

Browse files
block_hotplug_luks_detached: new case
1. Boot the VM (images are assumed to be created by the framework) 2. Hotplug the LUKS device with QMP (detached header) 3. Do read/write IO in the guest 4. Unplug and verify 5. Clean up image Signed-off-by: Tingting Mao <[email protected]>
1 parent 2639fb1 commit 33c7a1a

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import time
2+
3+
from virttest import error_context, utils_disk, utils_misc
4+
from virttest.qemu_monitor import QMPCmdError
5+
6+
7+
@error_context.context_aware
8+
def run(test, params, env):
9+
"""
10+
Hotplug a LUKS device with a detached header to a running VM (Linux or Windows),
11+
do IO, then unplug and verify.
12+
Steps:
13+
1. Boot the VM (images are assumed to be created by the framework)
14+
2. Hotplug the LUKS device with QMP (detached header)
15+
3. Do read/write IO in the guest
16+
4. Unplug and verify
17+
5. Clean up images
18+
"""
19+
20+
vm = env.get_vm(params["main_vm"])
21+
vm.verify_alive()
22+
login_timeout = int(params.get("login_timeout", 360))
23+
disk_op_cmd = params.get("disk_op_cmd")
24+
disk_op_timeout = int(params.get("disk_op_timeout", 360))
25+
luks_secret = params.get("image_secret_header", "redhat")
26+
luks_header = params.get("luks_header_img", "test-header.img")
27+
luks_payload = params.get("luks_payload_img", "test-payload.img")
28+
os_type = params.get("os_type", "linux").lower()
29+
windows = os_type == "windows"
30+
31+
# 1. Boot VM
32+
session = vm.wait_for_login(timeout=login_timeout)
33+
if windows:
34+
disks_before = set(session.cmd("wmic diskdrive get index").split()[1:])
35+
else:
36+
disks_before = set(utils_misc.list_linux_guest_disks(session))
37+
session.close()
38+
39+
# 2. QMP hotplug sequence
40+
try:
41+
# blockdev-add for payload
42+
vm.monitor.cmd(
43+
"blockdev-add",
44+
{
45+
"node-name": "libvirt-1-storage",
46+
"driver": "file",
47+
"filename": luks_payload,
48+
},
49+
)
50+
# blockdev-add for header
51+
vm.monitor.cmd(
52+
"blockdev-add",
53+
{
54+
"node-name": "libvirt-2-storage",
55+
"driver": "file",
56+
"filename": luks_header,
57+
},
58+
)
59+
# object-add secret
60+
vm.monitor.cmd(
61+
"object-add",
62+
{
63+
"qom-type": "secret",
64+
"id": "libvirt-2-storage-secret0",
65+
"data": luks_secret,
66+
},
67+
)
68+
# blockdev-add for raw
69+
vm.monitor.cmd(
70+
"blockdev-add",
71+
{
72+
"node-name": "libvirt-1-format",
73+
"driver": "raw",
74+
"file": "libvirt-1-storage",
75+
},
76+
)
77+
# blockdev-add for luks
78+
vm.monitor.cmd(
79+
"blockdev-add",
80+
{
81+
"node-name": "libvirt-2-format",
82+
"driver": "luks",
83+
"file": "libvirt-1-format",
84+
"header": "libvirt-2-storage",
85+
"key-secret": "libvirt-2-storage-secret0",
86+
},
87+
)
88+
# device_add
89+
vm.monitor.cmd(
90+
"device_add",
91+
{
92+
"num-queues": "1",
93+
"driver": "virtio-blk-pci",
94+
"drive": "libvirt-2-format",
95+
"id": "virtio-disk2",
96+
},
97+
)
98+
except QMPCmdError as e:
99+
test.fail("QMP hotplug failed: %s" % e)
100+
except Exception as e:
101+
test.fail("QMP hotplug failed: %s" % e)
102+
103+
# 3. IO in guest
104+
session = vm.wait_for_login(timeout=login_timeout)
105+
time.sleep(5) # Wait for device to appear
106+
if windows:
107+
disks_after = set(session.cmd("wmic diskdrive get index").split()[1:])
108+
new_disks = list(disks_after - disks_before)
109+
if not new_disks:
110+
test.fail("No new disk detected after hotplug!")
111+
new_disk = new_disks[0]
112+
error_context.context(
113+
"New disk detected (Windows index): %s" % new_disk, test.log.info
114+
)
115+
# Format the disk if needed and get drive letter
116+
disk_index = params.objects("disk_index")
117+
disk_letter = params.objects("disk_letter")
118+
drive_letters = []
119+
if disk_index and disk_letter:
120+
idx = 0
121+
utils_misc.format_windows_disk(session, disk_index[idx], disk_letter[idx])
122+
drive_letters.append(disk_letter[idx])
123+
drive_letter = drive_letters[0]
124+
else:
125+
# Try to auto format and get letter
126+
drive_letter = utils_disk.configure_empty_windows_disk(
127+
session, new_disk, params.get("luks_payload_size", "5G")
128+
)[0]
129+
test_cmd = disk_op_cmd % (drive_letter, drive_letter)
130+
test_cmd = utils_misc.set_winutils_letter(session, test_cmd)
131+
else:
132+
disks_after = set(utils_misc.list_linux_guest_disks(session))
133+
new_disks = list(disks_after - disks_before)
134+
if not new_disks:
135+
test.fail("No new disk detected after hotplug!")
136+
new_disk = new_disks[0]
137+
error_context.context("New disk detected: %s" % new_disk, test.log.info)
138+
test_cmd = disk_op_cmd % (new_disk, new_disk)
139+
try:
140+
session.cmd(test_cmd, timeout=disk_op_timeout)
141+
except Exception as e:
142+
test.fail(f"IO on hotplugged disk failed: {e}")
143+
session.close()
144+
145+
# 4. Unplug
146+
try:
147+
vm.monitor.cmd("device_del", {"id": "virtio-disk2"})
148+
# Wait for disk to disappear
149+
session = vm.wait_for_login(timeout=login_timeout)
150+
151+
def disk_gone():
152+
if windows:
153+
return (
154+
new_disk not in session.cmd("wmic diskdrive get index").split()[1:]
155+
)
156+
else:
157+
return new_disk not in utils_misc.list_linux_guest_disks(session)
158+
159+
utils_misc.wait_for(disk_gone, 60, step=2)
160+
session.close()
161+
except Exception as e:
162+
test.fail(f"Unplug failed: {e}")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
- block_hotplug_luks_detached: install setup image_copy unattended_install.cdrom
2+
only Linux Windows
3+
virt_test_type = qemu
4+
type = block_hotplug_luks_detached
5+
bootindex_image1 = 0
6+
# Define the payload image (raw data disk)
7+
images += " payload"
8+
image_name_payload = test-payload.img
9+
image_format_payload = raw
10+
image_size_payload = 5G
11+
force_create_image_payload = yes
12+
remove_image_payload = yes
13+
# Define the LUKS header image (detached header)
14+
images += " header"
15+
image_name_header = test-header.img
16+
image_format_header = luks
17+
image_size_header = 2M
18+
force_create_image_header = yes
19+
remove_image_header = yes
20+
image_secret_header = redhat
21+
# These params are used by the test logic
22+
luks_header_img = test-header.img
23+
luks_payload_img = test-payload.img
24+
luks_payload_size = 5G
25+
remove_image = yes
26+
force_create_image = yes
27+
disk_op_cmd = "dd if=%s of=/dev/null bs=1k count=1000 iflag=direct && dd if=/dev/zero of=%s bs=1k count=1000 oflag=direct"
28+
kill_vm_on_error = yes
29+
login_timeout = 360
30+
disk_op_timeout = 360
31+
# Windows-specific variant
32+
Windows:
33+
os_type = windows
34+
disk_index = "1"
35+
disk_letter = "I"
36+
disk_op_cmd = "WIN_UTILS:\\Iozone\\iozone.exe -azR -r 64k -n 125M -g 512M -M -i 0 -i 1 -b %s:\\iozone_test -f %s:\\testfile"

0 commit comments

Comments
 (0)