usb_storage.py 9.1 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 66
        error_context.context("Verify matched string is same as expected",
                              logging.info)
67
        actual_result = m[0]
68 69 70 71 72 73
        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"

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

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

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

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

X
Xu Han 已提交
98
        for option, value in options.items():
99
            params[option] = value
100
        error_context.context("Restarting VM")
101
        vm.create(params=params)
102 103 104
        vm.verify_alive()

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

107
    def _get_usb_disk_name_in_guest(session):
108 109 110 111 112 113 114 115 116
        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")
X
Xu Han 已提交
117
        devname = re.findall(r"sd\w", output)
118 119 120 121
        if devname:
            return devname[0]
        return "sda"

122
    @error_context.context_aware
123
    def _check_serial_option(serial, regex_str, expect_str):
124 125
        error_context.context("Set serial option to '%s'" % serial,
                              logging.info)
126
        _restart_vm({"blk_extra_params_stg": "serial=" + serial})
127

128
        error_context.context("Check serial option in monitor", logging.info)
129 130 131
        output = str(vm.monitor.info("qtree"))
        _verify_string(regex_str, output, [expect_str], re.S)

132
        error_context.context("Check serial option in guest", logging.info)
133 134
        session = _login()
        output = session.cmd("lsusb -v")
135
        if serial not in ["EMPTY_STRING", "NO_EQUAL_STRING"]:
136 137 138 139
            # Verify in guest when serial is set to empty/null is meaningless.
            _verify_string(serial, output, [serial])
        session.close()

140
    @error_context.context_aware
141
    def _check_removable_option(removable, expect_str):
142 143
        error_context.context("Set removable option to '%s'" % removable,
                              logging.info)
144 145
        _restart_vm({"removable_stg": removable})

146 147
        error_context.context("Check removable option in monitor",
                              logging.info)
148
        output = str(vm.monitor.info("qtree"))
X
Xu Han 已提交
149
        regex_str = r'usb-storage.*?removable = (.*?)\s'
150 151
        _verify_string(regex_str, output, [removable], re.S)

152
        error_context.context("Check removable option in guest", logging.info)
153
        session = _login()
154
        cmd = "dmesg | grep %s" % _get_usb_disk_name_in_guest(session)
155 156 157 158
        output = session.cmd(cmd)
        _verify_string(expect_str, output, [expect_str], re.I)
        session.close()

159
    @error_context.context_aware
160
    def _check_io_size_option(min_io_size="512", opt_io_size="0"):
161 162
        error_context.context("Set min_io_size to %s, opt_io_size to %s" %
                              (min_io_size, opt_io_size), logging.info)
163 164 165 166 167 168
        opt = {}
        opt["min_io_size_stg"] = min_io_size
        opt["opt_io_size_stg"] = opt_io_size

        _restart_vm(opt)

169 170
        error_context.context("Check min/opt io_size option in monitor",
                              logging.info)
171
        output = str(vm.monitor.info("qtree"))
X
Xu Han 已提交
172
        regex_str = r"usb-storage.*?min_io_size = (\d+).*?opt_io_size = (\d+)"
173 174
        _verify_string(regex_str, output, [min_io_size, opt_io_size], re.S)

175 176
        error_context.context("Check min/opt io_size option in guest",
                              logging.info)
177
        session = _login()
178
        d = _get_usb_disk_name_in_guest(session)
179 180 181 182 183 184 185 186 187
        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"
X
Xu Han 已提交
188
        _verify_string(r"(\d+)\n(\d+)", output,
189
                       [expected_min_size, opt_io_size])
190 191 192 193 194
        session.close()

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

195
    login_timeout = int(params.get("login_timeout", 360))
196 197
    error_context.context("Check usb device information in monitor",
                          logging.info)
198 199 200
    output = str(vm.monitor.info("usb"))
    if "Product QEMU USB MSD" not in output:
        logging.debug(output)
201
        test.fail("Could not find mass storage device")
202

203 204
    error_context.context("Check usb device information in guest",
                          logging.info)
205
    session = _login()
206
    output = session.cmd(params["chk_usb_info_cmd"])
207
    # No bus specified, default using "usb.0" for "usb-storage"
208
    for i in params["chk_usb_info_keyword"].split(","):
209 210
        _verify_string(i, output, [i])
    session.close()
211
    _do_io_test_guest()
212

213
    # this part is linux only
214
    if params.get("check_serial_option") == "yes":
215
        error_context.context("Check usb serial option", logging.info)
216
        serial = str(uuid.uuid4())
X
Xu Han 已提交
217
        regex_str = r'usb-storage.*?serial = "(.*?)"\s'
218 219 220 221 222 223
        _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"
X
Xu Han 已提交
224
        regex_str = r'usb-storage.*?serial = (.*?)\s'
225 226 227 228
        _check_serial_option(serial, regex_str, '""')

        logging.info("Leave usb serial option blank")
        serial = "NO_EQUAL_STRING"
X
Xu Han 已提交
229
        regex_str = r'usb-storage.*?serial = (.*?)\s'
230 231 232
        _check_serial_option(serial, regex_str, '"on"')

    if params.get("check_removable_option") == "yes":
233
        error_context.context("Check usb removable option", logging.info)
234 235 236 237 238 239 240 241 242
        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":
243
        error_context.context("Check usb min/opt io_size option", logging.info)
244 245 246
        _check_io_size_option("0", "0")
        # Guest can't recognize correct value which we set now,
        # So comment these test temporary.
247 248
        # _check_io_size_option("1024", "1024")
        # _check_io_size_option("4096", "4096")