master
py 172 lines 6.43 KB
Raw
1 #!/usr/bin/env python3
2 #
3 # SPDX-License-Identifier: GPL-2.0-or-later
4 #
5 # x86_64 NVMe migration test
6
7 from migration import MigrationTest
8 from qemu_test import QemuSystemTest, Asset
9 from qemu_test import wait_for_console_pattern
10 from qemu_test import exec_command, exec_command_and_wait_for_pattern
11
12
13 class X8664NVMeMigrationTest(MigrationTest):
14 ASSET_KERNEL = Asset(
15 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
16 '/31/Server/x86_64/os/images/pxeboot/vmlinuz'),
17 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
18
19 ASSET_INITRD = Asset(
20 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
21 '/31/Server/x86_64/os/images/pxeboot/initrd.img'),
22 '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b')
23
24 ASSET_DISKIMAGE = Asset(
25 ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
26 '/31/Cloud/x86_64/images/Fedora-Cloud-Base-31-1.9.x86_64.qcow2'),
27 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0')
28
29 DEFAULT_KERNEL_PARAMS = ('root=/dev/nvme0n1p1 console=ttyS0 net.ifnames=0 '
30 'rd.rescue quiet')
31
32 def wait_for_console_pattern(self, success_message, vm):
33 wait_for_console_pattern(
34 self,
35 success_message,
36 failure_message="Kernel panic - not syncing",
37 vm=vm,
38 )
39
40 def exec_command_and_check(self, command, vm):
41 prompt = '# '
42 exec_command_and_wait_for_pattern(self,
43 f"{command} && echo OK || echo FAIL",
44 'FAIL', vm=vm)
45 # Note, that commands we send to the console are echo-ed back,
46 # so if we have a word "FAIL" in the command itself, we should
47 # expect to see it once.
48 wait_for_console_pattern(self, 'OK', failure_message="FAIL", vm=vm)
49 self.wait_for_console_pattern(prompt, vm)
50
51 def configure_machine(self, vm):
52 kernel_path = self.ASSET_KERNEL.fetch()
53 initrd_path = self.ASSET_INITRD.fetch()
54 diskimage_path = self.ASSET_DISKIMAGE.fetch()
55
56 vm.set_console()
57 vm.add_args("-cpu", "max")
58 vm.add_args("-m", "2G")
59 vm.add_args("-accel", "kvm")
60
61 vm.add_args('-drive',
62 f'file={diskimage_path},if=none,id=drv0,snapshot=on')
63 vm.add_args('-device', 'nvme,bus=pcie.0,' +
64 'drive=drv0,id=nvme-disk0,serial=nvmemigtest,bootindex=1')
65
66 vm.add_args(
67 "-kernel",
68 kernel_path,
69 "-initrd",
70 initrd_path,
71 "-append",
72 self.DEFAULT_KERNEL_PARAMS
73 )
74
75 def launch_source_vm(self, vm):
76 vm.launch()
77
78 self.wait_for_console_pattern('Entering emergency mode.', vm)
79 prompt = '# '
80 self.wait_for_console_pattern(prompt, vm)
81
82 # Synchronize on NVMe driver creating the root device
83 exec_command_and_wait_for_pattern(self,
84 "while ! (dmesg -c | grep nvme0n1:) ; do sleep 1 ; done",
85 "nvme0n1", vm=vm)
86 self.wait_for_console_pattern(prompt, vm)
87
88 # prepare system
89 exec_command_and_wait_for_pattern(self, 'mount /dev/nvme0n1p1 /sysroot',
90 prompt, vm=vm)
91 exec_command_and_wait_for_pattern(self, 'chroot /sysroot',
92 prompt, vm=vm)
93 exec_command_and_wait_for_pattern(self, 'mount -t proc proc /proc',
94 prompt, vm=vm)
95 exec_command_and_wait_for_pattern(self, 'mount -t sysfs sysfs /sys',
96 prompt, vm=vm)
97
98 # Run workload before migration to check if it continues
99 # to run properly after migration.
100 #
101 # Workload is simple: it continuously calculates checksums of
102 # all files in /usr/bin to generate some I/O load on
103 # the NVMe disk and at the same time it drops caches to
104 # make sure that we have some read I/O on the disk as well.
105 # If there are any issues with the migration of the NVMe device,
106 # we should see errors in dmesg and consequently in the workload log.
107 exec_command_and_wait_for_pattern(self,
108 "(while [ ! -f /tmp/test_nvme_mig_workload.stop ]; do \
109 rm -f /tmp/test_nvme_mig_workload.iter_finished; \
110 echo 3 > /proc/sys/vm/drop_caches; \
111 find /usr/bin -type f -exec cksum {} \\;; \
112 touch /tmp/test_nvme_mig_workload.iter_finished; \
113 done) > /dev/null 2> /tmp/test_nvme_mig_workload.errors &",
114 prompt, vm=vm)
115 exec_command_and_wait_for_pattern(self,
116 'echo $! > /tmp/test_nvme_mig_workload.pid',
117 prompt, vm=vm)
118
119 # check if process is alive and running
120 self.exec_command_and_check(
121 "kill -0 $(cat /tmp/test_nvme_mig_workload.pid)", vm)
122
123 def assert_dest_vm(self, vm):
124 prompt = '# '
125
126 # check if process is alive and running after migration,
127 # if not - fail the test
128 self.exec_command_and_check(
129 "kill -0 $(cat /tmp/test_nvme_mig_workload.pid)", vm)
130
131 # signal workload to stop
132 exec_command_and_wait_for_pattern(self,
133 'touch /tmp/test_nvme_mig_workload.stop',
134 prompt, vm=vm)
135
136 # wait workload to finish, because we want to examine log
137 # to see if there are any errors
138 exec_command_and_wait_for_pattern(self,
139 "while [ ! -f /tmp/test_nvme_mig_workload.iter_finished ]; do \
140 sleep 1; \
141 done;",
142 prompt, vm=vm)
143
144 exec_command_and_wait_for_pattern(self,
145 'cat /tmp/test_nvme_mig_workload.errors',
146 prompt, vm=vm)
147
148 # fail the test if non-empty
149 self.exec_command_and_check(
150 "[ ! -s /tmp/test_nvme_mig_workload.errors ]", vm)
151
152 def test_migration_with_tcp_localhost(self):
153 self.set_machine('q35')
154 self.require_accelerator("kvm")
155
156 self.migration_with_tcp_localhost()
157
158 def test_migration_with_unix(self):
159 self.set_machine('q35')
160 self.require_accelerator("kvm")
161
162 self.migration_with_unix()
163
164 def test_migration_with_exec(self):
165 self.set_machine('q35')
166 self.require_accelerator("kvm")
167
168 self.migration_with_exec()
169
170
171 if __name__ == '__main__':
172 MigrationTest.main()