usb_storage.py 10.0 KB
Newer Older
L
Lucas Meneghel Rodrigues 已提交
1 2 3
import logging
import re
import uuid
4 5

import aexpect
6 7 8
from virttest import (utils_test,
                      utils_misc,
                      error_context)
9 10


11
@error_context.context_aware
12
def run(test, params, env):
13
    """
14
    Test usb storage devices in the guest.
15 16 17 18 19 20 21 22 23

    1) Create a image file by qemu-img
    2) Boot up a guest add this image as a usb device
    3) Check usb device information via monitor
    4) Check usb information by executing guest command
    5) Check usb serial option (optional)
    6) Check usb removable option (optional)
    7) Check usb min_io_size/opt_io_size option (optional)

L
Lucas Meneghel Rodrigues 已提交
24 25 26
    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
27
    """
28
    @error_context.context_aware
29 30 31 32
    def _verify_string(regex_str, string, expect_result, search_opt=0):
        """
        Verify USB storage device in monitor

L
Lucas Meneghel Rodrigues 已提交
33 34 35 36
        :param regex_str: Regex for checking command output
        :param string: The string which will be checked
        :param expect_result: The expected string
        :param search_opt: Search option for re module.
37 38
        """
        def _compare_str(act, exp, ignore_case):
39 40 41 42 43 44 45
            def str_func_1(x):
                return x

            def str_func_2(x):
                return x.lower()

            str_func = str_func_1
46
            if ignore_case:
47 48
                str_func = str_func_2

49 50 51 52 53 54 55 56 57
            if str_func(act) != str_func(exp):
                return ("Expected: '%s', Actual: '%s'" %
                        (str_func(exp), str_func(act)))
            return ""

        ignore_case = False
        if search_opt & re.I == re.I:
            ignore_case = True

58 59
        error_context.context("Finding matched sub-string with regex"
                              " pattern '%s'" % regex_str, logging.info)
60 61 62
        m = re.findall(regex_str, string, search_opt)
        if not m:
            logging.debug(string)
63
            test.error("Could not find matched sub-string")
64

65
        error_context.context("Verify matched string is same as expected")
66
        actual_result = m[0]
67 68 69 70 71 72
        if "removable" in regex_str:
            if actual_result in ["on", "yes", "true"]:
                actual_result = "on"
            if actual_result in ["off", "no", "false"]:
                actual_result = "off"

73 74 75
        fail_log = []
        if isinstance(actual_result, tuple):
            for i, v in enumerate(expect_result):
L
Lucas Meneghel Rodrigues 已提交
76
                ret = _compare_str(actual_result[i], v, ignore_case)
77 78 79
                if ret:
                    fail_log.append(ret)
        else:
L
Lucas Meneghel Rodrigues 已提交
80
            ret = _compare_str(actual_result, expect_result[0], ignore_case)
81 82 83 84 85
            if ret:
                fail_log.append(ret)

        if fail_log:
            logging.debug(string)
86 87
            test.fail("Could not find expected string:\n %s" %
                      ("\n".join(fail_log)))
88 89

    def _do_io_test_guest(session):
90
        utils_test.run_virt_sub_test(test, params, env, "format_disk")
91

92
    @error_context.context_aware
93 94 95 96 97
    def _restart_vm(options):
        if vm.is_alive():
            vm.destroy()

        for option, value in options.iteritems():
98
            params[option] = value
99
        error_context.context("Restarting VM")
100
        vm.create(params=params)
101 102 103
        vm.verify_alive()

    def _login():
104
        return vm.wait_for_login(timeout=login_timeout)
105

106
    def _get_usb_disk_name_in_guest(session):
107 108 109 110 111 112 113 114 115
        def _get_output():
            cmd = "ls -l /dev/disk/by-path/* | grep usb"
            try:
                return session.cmd(cmd).strip()
            except aexpect.ShellCmdError:
                return ""

        output = utils_misc.wait_for(_get_output, login_timeout, step=5,
                                     text="Wait for getting USB disk name")
116 117 118 119 120
        devname = re.findall("sd\w", output)
        if devname:
            return devname[0]
        return "sda"

121
    @error_context.context_aware
122 123 124 125 126
    def _check_and_umount_usb(session):
        chk_status = session.cmd_status(params["chk_mount_cmd"],
                                        timeout=login_timeout)
        if chk_status:
            return
127
        error_context.context("Unmounting usb disk", logging.info)
128 129 130 131 132 133 134
        # choose to umount usb disk instead of ejecting it
        # because if usb is removable it will not available after ejection
        status, output = session.cmd_status_output(params["umount_cmd"],
                                                   timeout=login_timeout)
        if status != 0:
            test.error("Failed to umount with error: %s" % output)

135
    @error_context.context_aware
136
    def _check_serial_option(serial, regex_str, expect_str):
137 138
        error_context.context("Set serial option to '%s'" % serial,
                              logging.info)
139
        _restart_vm({"blk_extra_params_stg": "serial=" + serial})
140

141
        error_context.context("Check serial option in monitor", logging.info)
142 143 144
        output = str(vm.monitor.info("qtree"))
        _verify_string(regex_str, output, [expect_str], re.S)

145
        error_context.context("Check serial option in guest", logging.info)
146 147
        session = _login()
        output = session.cmd("lsusb -v")
148
        if serial not in ["EMPTY_STRING", "NO_EQUAL_STRING"]:
149 150
            # Verify in guest when serial is set to empty/null is meaningless.
            _verify_string(serial, output, [serial])
151
        _check_and_umount_usb(session)
152 153 154 155
        _do_io_test_guest(session)

        session.close()

156
    @error_context.context_aware
157
    def _check_removable_option(removable, expect_str):
158 159
        error_context.context("Set removable option to '%s'" % removable,
                              logging.info)
160 161
        _restart_vm({"removable_stg": removable})

162 163
        error_context.context("Check removable option in monitor",
                              logging.info)
164
        output = str(vm.monitor.info("qtree"))
165
        regex_str = 'usb-storage.*?removable = (.*?)\s'
166 167
        _verify_string(regex_str, output, [removable], re.S)

168
        error_context.context("Check removable option in guest", logging.info)
169
        session = _login()
170
        cmd = "dmesg | grep %s" % _get_usb_disk_name_in_guest(session)
171 172
        output = session.cmd(cmd)
        _verify_string(expect_str, output, [expect_str], re.I)
173
        _check_and_umount_usb(session)
174 175 176 177
        _do_io_test_guest(session)

        session.close()

178
    @error_context.context_aware
179
    def _check_io_size_option(min_io_size="512", opt_io_size="0"):
180 181
        error_context.context("Set min_io_size to %s, opt_io_size to %s" %
                              (min_io_size, opt_io_size), logging.info)
182 183 184 185 186 187
        opt = {}
        opt["min_io_size_stg"] = min_io_size
        opt["opt_io_size_stg"] = opt_io_size

        _restart_vm(opt)

188 189
        error_context.context("Check min/opt io_size option in monitor",
                              logging.info)
190 191 192 193
        output = str(vm.monitor.info("qtree"))
        regex_str = "usb-storage.*?min_io_size = (\d+).*?opt_io_size = (\d+)"
        _verify_string(regex_str, output, [min_io_size, opt_io_size], re.S)

194 195
        error_context.context("Check min/opt io_size option in guest",
                              logging.info)
196
        session = _login()
197
        d = _get_usb_disk_name_in_guest(session)
198 199 200 201 202 203 204 205 206
        cmd = ("cat /sys/block/%s/queue/{minimum,optimal}_io_size" % d)

        output = session.cmd(cmd)
        # Note: If set min_io_size = 0, guest min_io_size would be set to
        # 512 by default.
        if min_io_size != "0":
            expected_min_size = min_io_size
        else:
            expected_min_size = "512"
207 208
        _verify_string("(\d+)\n(\d+)", output,
                       [expected_min_size, opt_io_size])
209
        _check_and_umount_usb(session)
210 211 212 213 214 215 216
        _do_io_test_guest(session)

        session.close()

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

217
    login_timeout = int(params.get("login_timeout", 360))
218 219
    error_context.context("Check usb device information in monitor",
                          logging.info)
220 221 222
    output = str(vm.monitor.info("usb"))
    if "Product QEMU USB MSD" not in output:
        logging.debug(output)
223
        test.fail("Could not find mass storage device")
224

225 226
    error_context.context("Check usb device information in guest",
                          logging.info)
227
    session = _login()
228
    output = session.cmd(params["chk_usb_info_cmd"])
229
    # No bus specified, default using "usb.0" for "usb-storage"
230
    for i in params["chk_usb_info_keyword"].split(","):
231 232 233 234
        _verify_string(i, output, [i])
    _do_io_test_guest(session)
    session.close()

235
    # this part is linux only
236
    if params.get("check_serial_option") == "yes":
237
        error_context.context("Check usb serial option", logging.info)
238
        serial = str(uuid.uuid4())
239
        regex_str = 'usb-storage.*?serial = "(.*?)"\s'
240 241 242 243 244 245
        _check_serial_option(serial, regex_str, serial)

        logging.info("Check this option with some illegal string")
        logging.info("Set usb serial to a empty string")
        # An empty string, ""
        serial = "EMPTY_STRING"
246
        regex_str = 'usb-storage.*?serial = (.*?)\s'
247 248 249 250
        _check_serial_option(serial, regex_str, '""')

        logging.info("Leave usb serial option blank")
        serial = "NO_EQUAL_STRING"
251
        regex_str = 'usb-storage.*?serial = (.*?)\s'
252 253 254
        _check_serial_option(serial, regex_str, '"on"')

    if params.get("check_removable_option") == "yes":
255
        error_context.context("Check usb removable option", logging.info)
256 257 258 259 260 261 262 263 264
        removable = "on"
        expect_str = "Attached SCSI removable disk"
        _check_removable_option(removable, expect_str)

        removable = "off"
        expect_str = "Attached SCSI disk"
        _check_removable_option(removable, expect_str)

    if params.get("check_io_size_option") == "yes":
265
        error_context.context("Check usb min/opt io_size option", logging.info)
266 267 268
        _check_io_size_option("0", "0")
        # Guest can't recognize correct value which we set now,
        # So comment these test temporary.
269 270
        # _check_io_size_option("1024", "1024")
        # _check_io_size_option("4096", "4096")