tests/acceptance: Ignore binary data sent on serial console
[qemu/ar7.git] / tests / acceptance / virtiofs_submounts.py
blob21ad7d792e7069b4dcadba3eebba4da87b91883f
1 import logging
2 import re
3 import os
4 import subprocess
5 import time
7 from avocado import skipUnless
8 from avocado_qemu import LinuxTest, BUILD_DIR
9 from avocado_qemu import wait_for_console_pattern
10 from avocado.utils import ssh
13 def run_cmd(args):
14 subp = subprocess.Popen(args,
15 stdout=subprocess.PIPE,
16 stderr=subprocess.PIPE,
17 universal_newlines=True)
18 stdout, stderr = subp.communicate()
19 ret = subp.returncode
21 return (stdout, stderr, ret)
23 def has_cmd(name, args=None):
24 """
25 This function is for use in a @avocado.skipUnless decorator, e.g.:
27 @skipUnless(*has_cmd('sudo -n', ('sudo', '-n', 'true')))
28 def test_something_that_needs_sudo(self):
29 ...
30 """
32 if args is None:
33 args = ('which', name)
35 try:
36 _, stderr, exitcode = run_cmd(args)
37 except Exception as e:
38 exitcode = -1
39 stderr = str(e)
41 if exitcode != 0:
42 cmd_line = ' '.join(args)
43 err = f'{name} required, but "{cmd_line}" failed: {stderr.strip()}'
44 return (False, err)
45 else:
46 return (True, '')
48 def has_cmds(*cmds):
49 """
50 This function is for use in a @avocado.skipUnless decorator and
51 allows checking for the availability of multiple commands, e.g.:
53 @skipUnless(*has_cmds(('cmd1', ('cmd1', '--some-parameter')),
54 'cmd2', 'cmd3'))
55 def test_something_that_needs_cmd1_and_cmd2(self):
56 ...
57 """
59 for cmd in cmds:
60 if isinstance(cmd, str):
61 cmd = (cmd,)
63 ok, errstr = has_cmd(*cmd)
64 if not ok:
65 return (False, errstr)
67 return (True, '')
70 class VirtiofsSubmountsTest(LinuxTest):
71 """
72 :avocado: tags=arch:x86_64
73 :avocado: tags=accel:kvm
74 """
76 def run(self, args, ignore_error=False):
77 stdout, stderr, ret = run_cmd(args)
79 if ret != 0:
80 cmdline = ' '.join(args)
81 if not ignore_error:
82 self.fail(f'{cmdline}: Returned {ret}: {stderr}')
83 else:
84 self.log.warn(f'{cmdline}: Returned {ret}: {stderr}')
86 return (stdout, stderr, ret)
88 def set_up_shared_dir(self):
89 self.shared_dir = os.path.join(self.workdir, 'virtiofs-shared')
91 os.mkdir(self.shared_dir)
93 self.run(('cp', self.get_data('guest.sh'),
94 os.path.join(self.shared_dir, 'check.sh')))
96 self.run(('cp', self.get_data('guest-cleanup.sh'),
97 os.path.join(self.shared_dir, 'cleanup.sh')))
99 def set_up_virtiofs(self):
100 attmp = os.getenv('AVOCADO_TESTS_COMMON_TMPDIR')
101 self.vfsdsock = os.path.join(attmp, 'vfsdsock')
103 self.run(('sudo', '-n', 'rm', '-f', self.vfsdsock), ignore_error=True)
105 self.virtiofsd = \
106 subprocess.Popen(('sudo', '-n',
107 'tools/virtiofsd/virtiofsd',
108 f'--socket-path={self.vfsdsock}',
109 '-o', f'source={self.shared_dir}',
110 '-o', 'cache=always',
111 '-o', 'xattr',
112 '-o', 'announce_submounts',
113 '-f'),
114 stdout=subprocess.DEVNULL,
115 stderr=subprocess.PIPE,
116 universal_newlines=True)
118 while not os.path.exists(self.vfsdsock):
119 if self.virtiofsd.poll() is not None:
120 self.fail('virtiofsd exited prematurely: ' +
121 self.virtiofsd.communicate()[1])
122 time.sleep(0.1)
124 self.run(('sudo', '-n', 'chmod', 'go+rw', self.vfsdsock))
126 self.vm.add_args('-chardev',
127 f'socket,id=vfsdsock,path={self.vfsdsock}',
128 '-device',
129 'vhost-user-fs-pci,queue-size=1024,chardev=vfsdsock' \
130 ',tag=host',
131 '-object',
132 'memory-backend-file,id=mem,size=1G,' \
133 'mem-path=/dev/shm,share=on',
134 '-numa',
135 'node,memdev=mem')
137 def set_up_nested_mounts(self):
138 scratch_dir = os.path.join(self.shared_dir, 'scratch')
139 try:
140 os.mkdir(scratch_dir)
141 except FileExistsError:
142 pass
144 args = ['bash', self.get_data('host.sh'), scratch_dir]
145 if self.seed:
146 args += [self.seed]
148 out, _, _ = self.run(args)
149 seed = re.search(r'^Seed: \d+', out)
150 self.log.info(seed[0])
152 def mount_in_guest(self):
153 self.ssh_command('mkdir -p /mnt/host')
154 self.ssh_command('mount -t virtiofs host /mnt/host')
156 def check_in_guest(self):
157 self.ssh_command('bash /mnt/host/check.sh /mnt/host/scratch/share')
159 def live_cleanup(self):
160 self.ssh_command('bash /mnt/host/cleanup.sh /mnt/host/scratch')
162 # It would be nice if the above was sufficient to make virtiofsd clear
163 # all references to the mounted directories (so they can be unmounted
164 # on the host), but unfortunately it is not. To do so, we have to
165 # resort to a remount.
166 self.ssh_command('mount -o remount /mnt/host')
168 scratch_dir = os.path.join(self.shared_dir, 'scratch')
169 self.run(('bash', self.get_data('cleanup.sh'), scratch_dir))
171 @skipUnless(*has_cmds(('sudo -n', ('sudo', '-n', 'true')),
172 'ssh-keygen', 'bash', 'losetup', 'mkfs.xfs', 'mount'))
173 def setUp(self):
174 vmlinuz = self.params.get('vmlinuz')
175 if vmlinuz is None:
177 The Linux kernel supports FUSE auto-submounts only as of 5.10.
178 boot_linux.py currently provides Fedora 31, whose kernel is too
179 old, so this test cannot pass with the on-image kernel (you are
180 welcome to try, hence the option to force such a test with
181 -p vmlinuz=''). Therefore, for now the user must provide a
182 sufficiently new custom kernel, or effectively explicitly
183 request failure with -p vmlinuz=''.
184 Once an image with a sufficiently new kernel is available
185 (probably Fedora 34), we can make -p vmlinuz='' the default, so
186 that this parameter no longer needs to be specified.
188 self.cancel('vmlinuz parameter not set; you must point it to a '
189 'Linux kernel binary to test (to run this test with ' \
190 'the on-image kernel, set it to an empty string)')
192 self.seed = self.params.get('seed')
194 self.ssh_key = os.path.join(self.workdir, 'id_ed25519')
196 self.run(('ssh-keygen', '-N', '', '-t', 'ed25519', '-f', self.ssh_key))
198 pubkey = self.ssh_key + '.pub'
200 super(VirtiofsSubmountsTest, self).setUp(pubkey)
202 if vmlinuz:
203 self.vm.add_args('-kernel', vmlinuz,
204 '-append', 'console=ttyS0 root=/dev/sda1')
206 self.require_accelerator("kvm")
207 self.vm.add_args('-accel', 'kvm')
209 def tearDown(self):
210 try:
211 self.vm.shutdown()
212 except:
213 pass
215 scratch_dir = os.path.join(self.shared_dir, 'scratch')
216 self.run(('bash', self.get_data('cleanup.sh'), scratch_dir),
217 ignore_error=True)
219 def test_pre_virtiofsd_set_up(self):
220 self.set_up_shared_dir()
222 self.set_up_nested_mounts()
224 self.set_up_virtiofs()
225 self.launch_and_wait()
226 self.mount_in_guest()
227 self.check_in_guest()
229 def test_pre_launch_set_up(self):
230 self.set_up_shared_dir()
231 self.set_up_virtiofs()
233 self.set_up_nested_mounts()
235 self.launch_and_wait()
236 self.mount_in_guest()
237 self.check_in_guest()
239 def test_post_launch_set_up(self):
240 self.set_up_shared_dir()
241 self.set_up_virtiofs()
242 self.launch_and_wait()
244 self.set_up_nested_mounts()
246 self.mount_in_guest()
247 self.check_in_guest()
249 def test_post_mount_set_up(self):
250 self.set_up_shared_dir()
251 self.set_up_virtiofs()
252 self.launch_and_wait()
253 self.mount_in_guest()
255 self.set_up_nested_mounts()
257 self.check_in_guest()
259 def test_two_runs(self):
260 self.set_up_shared_dir()
262 self.set_up_nested_mounts()
264 self.set_up_virtiofs()
265 self.launch_and_wait()
266 self.mount_in_guest()
267 self.check_in_guest()
269 self.live_cleanup()
270 self.set_up_nested_mounts()
272 self.check_in_guest()