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
14 subp
= subprocess
.Popen(args
,
15 stdout
=subprocess
.PIPE
,
16 stderr
=subprocess
.PIPE
,
17 universal_newlines
=True)
18 stdout
, stderr
= subp
.communicate()
21 return (stdout
, stderr
, ret
)
23 def has_cmd(name
, args
=None):
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):
33 args
= ('which', name
)
36 _
, stderr
, exitcode
= run_cmd(args
)
37 except Exception as e
:
42 cmd_line
= ' '.join(args
)
43 err
= f
'{name} required, but "{cmd_line}" failed: {stderr.strip()}'
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')),
55 def test_something_that_needs_cmd1_and_cmd2(self):
60 if isinstance(cmd
, str):
63 ok
, errstr
= has_cmd(*cmd
)
65 return (False, errstr
)
70 class VirtiofsSubmountsTest(LinuxTest
):
72 :avocado: tags=arch:x86_64
73 :avocado: tags=accel:kvm
76 def run(self
, args
, ignore_error
=False):
77 stdout
, stderr
, ret
= run_cmd(args
)
80 cmdline
= ' '.join(args
)
82 self
.fail(f
'{cmdline}: Returned {ret}: {stderr}')
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)
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',
112 '-o', 'announce_submounts',
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])
124 self
.run(('sudo', '-n', 'chmod', 'go+rw', self
.vfsdsock
))
126 self
.vm
.add_args('-chardev',
127 f
'socket,id=vfsdsock,path={self.vfsdsock}',
129 'vhost-user-fs-pci,queue-size=1024,chardev=vfsdsock' \
132 'memory-backend-file,id=mem,size=1G,' \
133 'mem-path=/dev/shm,share=on',
137 def set_up_nested_mounts(self
):
138 scratch_dir
= os
.path
.join(self
.shared_dir
, 'scratch')
140 os
.mkdir(scratch_dir
)
141 except FileExistsError
:
144 args
= ['bash', self
.get_data('host.sh'), scratch_dir
]
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'))
174 vmlinuz
= self
.params
.get('vmlinuz')
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
)
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')
215 scratch_dir
= os
.path
.join(self
.shared_dir
, 'scratch')
216 self
.run(('bash', self
.get_data('cleanup.sh'), scratch_dir
),
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()
270 self
.set_up_nested_mounts()
272 self
.check_in_guest()