qemu/tests/avocado/virtiofs_submounts.py
<<
>>
Prefs
   1import logging
   2import re
   3import os
   4import subprocess
   5import time
   6
   7from avocado import skipUnless
   8from avocado_qemu import LinuxTest, BUILD_DIR
   9from avocado_qemu import has_cmds
  10from avocado_qemu import run_cmd
  11from avocado_qemu import wait_for_console_pattern
  12from avocado.utils import ssh
  13
  14
  15class VirtiofsSubmountsTest(LinuxTest):
  16    """
  17    :avocado: tags=arch:x86_64
  18    :avocado: tags=accel:kvm
  19    """
  20
  21    def run(self, args, ignore_error=False):
  22        stdout, stderr, ret = run_cmd(args)
  23
  24        if ret != 0:
  25            cmdline = ' '.join(args)
  26            if not ignore_error:
  27                self.fail(f'{cmdline}: Returned {ret}: {stderr}')
  28            else:
  29                self.log.warn(f'{cmdline}: Returned {ret}: {stderr}')
  30
  31        return (stdout, stderr, ret)
  32
  33    def set_up_shared_dir(self):
  34        self.shared_dir = os.path.join(self.workdir, 'virtiofs-shared')
  35
  36        os.mkdir(self.shared_dir)
  37
  38        self.run(('cp', self.get_data('guest.sh'),
  39                 os.path.join(self.shared_dir, 'check.sh')))
  40
  41        self.run(('cp', self.get_data('guest-cleanup.sh'),
  42                 os.path.join(self.shared_dir, 'cleanup.sh')))
  43
  44    def set_up_virtiofs(self):
  45        attmp = os.getenv('AVOCADO_TESTS_COMMON_TMPDIR')
  46        self.vfsdsock = os.path.join(attmp, 'vfsdsock')
  47
  48        self.run(('sudo', '-n', 'rm', '-f', self.vfsdsock), ignore_error=True)
  49
  50        self.virtiofsd = \
  51            subprocess.Popen(('sudo', '-n',
  52                              'tools/virtiofsd/virtiofsd',
  53                              f'--socket-path={self.vfsdsock}',
  54                              '-o', f'source={self.shared_dir}',
  55                              '-o', 'cache=always',
  56                              '-o', 'xattr',
  57                              '-o', 'announce_submounts',
  58                              '-f'),
  59                             stdout=subprocess.DEVNULL,
  60                             stderr=subprocess.PIPE,
  61                             universal_newlines=True)
  62
  63        while not os.path.exists(self.vfsdsock):
  64            if self.virtiofsd.poll() is not None:
  65                self.fail('virtiofsd exited prematurely: ' +
  66                          self.virtiofsd.communicate()[1])
  67            time.sleep(0.1)
  68
  69        self.run(('sudo', '-n', 'chmod', 'go+rw', self.vfsdsock))
  70
  71        self.vm.add_args('-chardev',
  72                         f'socket,id=vfsdsock,path={self.vfsdsock}',
  73                         '-device',
  74                         'vhost-user-fs-pci,queue-size=1024,chardev=vfsdsock' \
  75                             ',tag=host',
  76                         '-object',
  77                         'memory-backend-file,id=mem,size=1G,' \
  78                             'mem-path=/dev/shm,share=on',
  79                         '-numa',
  80                         'node,memdev=mem')
  81
  82    def set_up_nested_mounts(self):
  83        scratch_dir = os.path.join(self.shared_dir, 'scratch')
  84        try:
  85            os.mkdir(scratch_dir)
  86        except FileExistsError:
  87            pass
  88
  89        args = ['bash', self.get_data('host.sh'), scratch_dir]
  90        if self.seed:
  91            args += [self.seed]
  92
  93        out, _, _ = self.run(args)
  94        seed = re.search(r'^Seed: \d+', out)
  95        self.log.info(seed[0])
  96
  97    def mount_in_guest(self):
  98        self.ssh_command('mkdir -p /mnt/host')
  99        self.ssh_command('mount -t virtiofs host /mnt/host')
 100
 101    def check_in_guest(self):
 102        self.ssh_command('bash /mnt/host/check.sh /mnt/host/scratch/share')
 103
 104    def live_cleanup(self):
 105        self.ssh_command('bash /mnt/host/cleanup.sh /mnt/host/scratch')
 106
 107        # It would be nice if the above was sufficient to make virtiofsd clear
 108        # all references to the mounted directories (so they can be unmounted
 109        # on the host), but unfortunately it is not.  To do so, we have to
 110        # resort to a remount.
 111        self.ssh_command('mount -o remount /mnt/host')
 112
 113        scratch_dir = os.path.join(self.shared_dir, 'scratch')
 114        self.run(('bash', self.get_data('cleanup.sh'), scratch_dir))
 115
 116    @skipUnless(*has_cmds(('sudo -n', ('sudo', '-n', 'true')),
 117                          'ssh-keygen', 'bash', 'losetup', 'mkfs.xfs', 'mount'))
 118    def setUp(self):
 119        vmlinuz = self.params.get('vmlinuz')
 120        if vmlinuz is None:
 121            """
 122            The Linux kernel supports FUSE auto-submounts only as of 5.10.
 123            boot_linux.py currently provides Fedora 31, whose kernel is too
 124            old, so this test cannot pass with the on-image kernel (you are
 125            welcome to try, hence the option to force such a test with
 126            -p vmlinuz='').  Therefore, for now the user must provide a
 127            sufficiently new custom kernel, or effectively explicitly
 128            request failure with -p vmlinuz=''.
 129            Once an image with a sufficiently new kernel is available
 130            (probably Fedora 34), we can make -p vmlinuz='' the default, so
 131            that this parameter no longer needs to be specified.
 132            """
 133            self.cancel('vmlinuz parameter not set; you must point it to a '
 134                        'Linux kernel binary to test (to run this test with ' \
 135                        'the on-image kernel, set it to an empty string)')
 136
 137        self.seed = self.params.get('seed')
 138
 139        self.ssh_key = os.path.join(self.workdir, 'id_ed25519')
 140
 141        self.run(('ssh-keygen', '-N', '', '-t', 'ed25519', '-f', self.ssh_key))
 142
 143        pubkey = self.ssh_key + '.pub'
 144
 145        super(VirtiofsSubmountsTest, self).setUp(pubkey)
 146
 147        if vmlinuz:
 148            self.vm.add_args('-kernel', vmlinuz,
 149                             '-append', 'console=ttyS0 root=/dev/sda1')
 150
 151        self.require_accelerator("kvm")
 152        self.vm.add_args('-accel', 'kvm')
 153
 154    def tearDown(self):
 155        try:
 156            self.vm.shutdown()
 157        except:
 158            pass
 159
 160        scratch_dir = os.path.join(self.shared_dir, 'scratch')
 161        self.run(('bash', self.get_data('cleanup.sh'), scratch_dir),
 162                 ignore_error=True)
 163
 164    def test_pre_virtiofsd_set_up(self):
 165        self.set_up_shared_dir()
 166
 167        self.set_up_nested_mounts()
 168
 169        self.set_up_virtiofs()
 170        self.launch_and_wait()
 171        self.mount_in_guest()
 172        self.check_in_guest()
 173
 174    def test_pre_launch_set_up(self):
 175        self.set_up_shared_dir()
 176        self.set_up_virtiofs()
 177
 178        self.set_up_nested_mounts()
 179
 180        self.launch_and_wait()
 181        self.mount_in_guest()
 182        self.check_in_guest()
 183
 184    def test_post_launch_set_up(self):
 185        self.set_up_shared_dir()
 186        self.set_up_virtiofs()
 187        self.launch_and_wait()
 188
 189        self.set_up_nested_mounts()
 190
 191        self.mount_in_guest()
 192        self.check_in_guest()
 193
 194    def test_post_mount_set_up(self):
 195        self.set_up_shared_dir()
 196        self.set_up_virtiofs()
 197        self.launch_and_wait()
 198        self.mount_in_guest()
 199
 200        self.set_up_nested_mounts()
 201
 202        self.check_in_guest()
 203
 204    def test_two_runs(self):
 205        self.set_up_shared_dir()
 206
 207        self.set_up_nested_mounts()
 208
 209        self.set_up_virtiofs()
 210        self.launch_and_wait()
 211        self.mount_in_guest()
 212        self.check_in_guest()
 213
 214        self.live_cleanup()
 215        self.set_up_nested_mounts()
 216
 217        self.check_in_guest()
 218