Skip to content

Commit 6935f62

Browse files
committed
Virtual disk: add new case to make I/O error due to enospc
Automate case: VIRT-303987 - [io-error] Make disk produce I/O error due to "enospc" Scenario 1: Make disk produce I/O error due to "enospc", then check the error in "virsh event", vm log and "virsh dominfo". Scenario 2: Based on scenario 1, create disk snapshot, then query domain info again. Signed-off-by: Meina Li <[email protected]>
1 parent 9aa7dea commit 6935f62

File tree

2 files changed

+78
-24
lines changed

2 files changed

+78
-24
lines changed

libvirt/tests/cfg/virtual_disks/virtual_disks_io_error.cfg

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,21 @@
1515
event_msg = "/dev/mapper/${device_manager}.*report due to message"
1616
guest_log_msg = "IO error device=.*Input/output error"
1717
dominfo_msg = "I/O error:.*path='/dev/mapper/${device_manager}'.*message='Input/output error'"
18-
18+
- enospc:
19+
enospc_test = "yes"
20+
disk_device = "vdb"
21+
partition_path = "/tmp/small.disk"
22+
mount_point = "/mnt/enospc_test"
23+
disk_path = "${mount_point}/disk.img"
24+
prepare_file = "truncate -s 11M ${partition_path}; mkfs.ext3 -F ${partition_path}; mkdir -p ${mount_point}; mount ${partition_path} ${mount_point}; qemu-img create -f qcow2 ${disk_path} 20M"
25+
disk_dict = '{"type_name": "file", "source": {"attrs": {"file": "${disk_path}"}}, "target": {"dev": "vdb", "bus": "virtio"}, "driver": {"name": "qemu", "type": "qcow2"}}'
26+
dd_msg = "No space left on device"
27+
event_msg = "${disk_path}.*pause due to enospc"
28+
guest_log_msg = "IO error.*No space left on device"
29+
dominfo_msg = "I/O error:.*path='${disk_path}'.*message='No space left on device'"
30+
cleanup_cmd = "umount ${mount_point} || true; rm -rf ${mount_point}; rm -f ${partition_path}"
31+
variants:
32+
- default:
33+
- with_snapshot:
34+
with_snapshot = "yes"
35+
snapshot_name = "sn1"

libvirt/tests/src/virtual_disks/virtual_disks_io_error.py

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,66 +16,87 @@
1616

1717
from virttest import virsh
1818
from virttest import libvirt_version
19+
from virttest import data_dir
20+
from virttest import utils_disk
1921

2022
from virttest.libvirt_xml import vm_xml
2123
from virttest.libvirt_xml.devices import disk
2224
from virttest.utils_test import libvirt
25+
from virttest.utils_libvirt import libvirt_disk
26+
2327

2428
virsh_dargs = {"ignore_status": False, "shell": True}
2529

2630

2731
def run(test, params, env):
2832
"""
29-
Make disk produce I/O error due to "message", then check the error
33+
Make disk produce I/O error due to "message" or "enospc", then check the error
3034
in "virsh event", vm log and "virsh dominfo"
3135
3236
Note: "message" is a kind of I/O error reason. It means that the hypervisor
3337
reported a string description of the I/O error. The errors are usually logged
3438
into the domain log file or the last instance of the error string can be
3539
queried via virDomainGetMessages().
40+
"enospc" means the host filesystem is full.
3641
"""
3742

3843
def setup_test():
3944
"""
40-
Prepare one error device mapper。
45+
Prepare env for test.
4146
"""
4247
test.log.info("Setup env.")
43-
process.run(prepare_file, **virsh_dargs)
44-
# Find a free loop device
45-
global free_loop_dev
46-
free_loop_dev = process.run("losetup --find", **virsh_dargs).stdout_text.strip()
47-
# Setup a loop device and create error device mapper
48-
process.run('losetup %s %s' % (free_loop_dev, device_manager_path), **virsh_dargs)
49-
dm_table = """0 261144 linear %s 0
50-
261144 5 error
51-
261149 787427 linear %s 261139""" % (free_loop_dev, free_loop_dev)
52-
try:
53-
subprocess.run(["sudo", "dmsetup", "create", device_manager],
54-
input=dm_table.encode('utf-8'), stderr=subprocess.PIPE, check=True)
55-
except subprocess.CalledProcessError as e:
56-
test.log.debug("create device manager failed :%s", e.stderr.decode('utf-8'))
48+
if enospc_test:
49+
process.run(prepare_file, **virsh_dargs)
50+
else:
51+
process.run(prepare_file, **virsh_dargs)
52+
# Find a free loop device
53+
global free_loop_dev
54+
free_loop_dev = process.run("losetup --find", **virsh_dargs).stdout_text.strip()
55+
# Setup a loop device and create error device mapper
56+
process.run('losetup %s %s' % (free_loop_dev, device_manager_path),
57+
**virsh_dargs)
58+
dm_table = """0 261144 linear %s 0
59+
261144 5 error
60+
261149 787427 linear %s 261139""" % (free_loop_dev, free_loop_dev)
61+
try:
62+
subprocess.run(["sudo", "dmsetup", "create", device_manager],
63+
input=dm_table.encode('utf-8'), stderr=subprocess.PIPE, check=True)
64+
except subprocess.CalledProcessError as e:
65+
test.log.debug("create device manager failed :%s", e.stderr.decode('utf-8'))
5766

5867
def run_test():
5968
"""
6069
Attach disk and check error message.
6170
"""
71+
nonlocal session
6272
test.log.info("TEST_STEP1: Attach a new disk")
6373
vm.start()
6474
session = vm.wait_for_login()
6575
new_disk = disk.Disk()
6676
new_disk.setup_attrs(**disk_dict)
6777
virsh.attach_device(vm_name, new_disk.xml, flagstr="--current",
6878
wait_for_event=True, event_timeout=100, **virsh_dargs)
79+
test.log.debug("The current guest xml is: %s" % virsh.dumpxml(vm_name).stdout_text)
6980

7081
test.log.info("TEST_STEP2: Write file in guest and check I/O error message.")
7182
virsh_session = virsh.EventTracker.start_get_event(vm_name)
7283
try:
73-
output = session.cmd(dd_in_guest)
84+
if enospc_test:
85+
disk_names = libvirt_disk.get_non_root_disk_name(session)
86+
if not disk_names:
87+
test.fail("Can't find the non-root disk as expected!")
88+
disk_name = disk_names[0]
89+
utils_disk.dd_data_to_vm_disk(session, "/dev/%s" % disk_name)
90+
else:
91+
session.cmd(dd_in_guest)
7492
except Exception as e:
7593
if dd_msg not in str(e):
76-
test.fail("Write data in guest should produce error: %s in %s" % (dd_msg, output))
94+
test.fail("Write data in guest should produce error: %s in %s"
95+
% (dd_msg, str(e)))
96+
elif dd_msg in str(e):
97+
test.log.debug("Get expected error: %s in %s" % (dd_msg, str(e)))
7798
else:
78-
test.fail("Except error: in %s" % output)
99+
test.fail("Get unexpected result!")
79100

80101
test.log.info("TEST_STEP3: Check event output.")
81102
event_output = virsh.EventTracker.finish_get_event(virsh_session)
@@ -87,6 +108,12 @@ def run_test():
87108
if not libvirt.check_logfile(guest_log_msg, qemu_log, str_in_log=True):
88109
test.fail('Find unexpected error:%s in log file:%s' % (guest_log_msg, qemu_log))
89110

111+
if with_snapshot:
112+
test.log.info("TEST_STEP6: Create disk snapshot and check I/O error.")
113+
snapshot_file = os.path.join(data_dir.get_data_dir(), "vdb.snap")
114+
snap_options = ("%s --diskspec %s,snapshot=external,file=%s --disk-only"
115+
% (snapshot_name, target_disk, snapshot_file))
116+
virsh.snapshot_create_as(vm_name, snap_options, debug=True)
90117
test.log.info("TEST_STEP5: Check about I/O error in virsh domain info.")
91118
dominfo = virsh.dominfo(vm_name, debug=True)
92119
libvirt.check_result(dominfo, expected_match=dominfo_msg)
@@ -98,11 +125,17 @@ def teardown_test():
98125
test.log.info("TEST_TEARDOWN: Clean up env.")
99126
if session:
100127
session.close()
128+
if with_snapshot:
129+
virsh.snapshot_delete(vm_name, snapshot_name, debug=True)
101130
bkxml.sync()
102-
process.run('sudo losetup -d %s' % free_loop_dev, **virsh_dargs)
103-
process.run('sudo dmsetup remove %s' % device_manager, **virsh_dargs)
104-
if os.path.exists(device_manager_path):
105-
os.remove(device_manager_path)
131+
if enospc_test:
132+
process.run(params.get("cleanup_cmd"), **virsh_dargs)
133+
else:
134+
process.run('sudo losetup -d %s' % free_loop_dev, **virsh_dargs)
135+
process.run('sudo dmsetup remove %s' % params.get("device_manager"),
136+
**virsh_dargs)
137+
if os.path.exists(params.get("device_manager_path")):
138+
os.remove(params.get("device_manager_path"))
106139

107140
libvirt_version.is_libvirt_feature_supported(params)
108141

@@ -119,6 +152,10 @@ def teardown_test():
119152
event_msg = params.get("event_msg")
120153
guest_log_msg = params.get("guest_log_msg")
121154
dominfo_msg = params.get("dominfo_msg")
155+
enospc_test = "yes" == params.get("enospc_test", "no")
156+
target_disk = params.get("target_disk")
157+
with_snapshot = "yes" == params.get("with_snapshot", "no")
158+
snapshot_name = params.get("snapshot_name")
122159
session = None
123160

124161
try:

0 commit comments

Comments
 (0)