block_hotplug.py 10.5 KB
Newer Older
1 2
import logging
import re
3
import random
4 5 6 7

from virttest import data_dir
from virttest import storage
from virttest import error_context
8
from virttest import utils_misc
9 10
from virttest import utils_test
from virttest.qemu_devices import qdevices
11
from virttest import qemu_qtree
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35


@error_context.context_aware
def run(test, params, env):
    """
    Test hotplug of block devices.

    1) Boot up guest with/without block device(s).
    2) Hoplug block device and verify
    3) Do read/write data on hotplug block.
    4) Unplug block device and verify

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    def find_image(image_name):
        """
        Find the path of the iamge.
        """
        image_params = params.object_params(image_name)
        o = storage.get_image_filename(image_params, data_dir.get_data_dir())
        return o

36
    def find_disk(vm, cmd):
37 38 39 40 41
        """
        Find all disks in guest.
        """
        if params.get("os_type") == "linux":
            pattern = params.get("get_disk_pattern", "^/dev/vd[a-z]*$")
42
        elif params.get("os_type") == "windows":
X
Xu Han 已提交
43
            pattern = r"^\d+"
44
            cmd = params.get("get_disk_index", "wmic diskdrive get index")
45 46
        else:
            test.cancel("Unsupported OS type '%s'" % params.get("os_type"))
47

48
        session = vm.wait_for_login(timeout=timeout)
49 50
        output = session.cmd_output_safe(cmd)
        disks = re.findall(pattern, output, re.M)
51
        session.close()
52 53 54 55 56 57 58 59 60
        return disks

    def get_new_disk(disk1, disk2):
        """
        Get the different disk between disk1 and disk2.
        """
        disk = list(set(disk2).difference(set(disk1)))
        return disk

61 62 63 64 65 66 67 68 69 70 71
    def unplug_device(vm, get_disk_cmd, device):
        """
        Unplug device
        """
        disks_before_unplug = find_disk(vm, get_disk_cmd)
        device.unplug(vm.monitor)
        device.verify_unplug("", vm.monitor)
        unplug_status = utils_misc.wait_for(lambda: len(get_new_disk(find_disk
                                            (vm, get_disk_cmd), disks_before_unplug)) != 0, pause)
        return unplug_status

72 73 74
    img_list = params.get("images").split()
    img_format_type = params.get("img_format_type", "qcow2")
    pci_type = params.get("pci_type", "virtio-blk-pci")
75 76
    #sometimes, ppc can't get new plugged disk in 5s, so time to 10s
    pause = float(params.get("virtio_block_pause", 10.0))
77 78 79 80 81 82
    blk_num = int(params.get("blk_num", 1))
    repeat_times = int(params.get("repeat_times", 3))
    timeout = int(params.get("login_timeout", 360))
    disk_op_timeout = int(params.get("disk_op_timeout", 360))
    get_disk_cmd = params.get("get_disk_cmd")
    context_msg = "Running sub test '%s' %s"
83 84
    disk_index = params.objects("disk_index")
    disk_letter = params.objects("disk_letter")
85 86 87 88

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

X
Xu Han 已提交
89
    for iteration in range(repeat_times):
90 91 92
        device_list = []
        controller_list = []
        controller_device_dict = {}
93
        error_context.context("Hotplug block device (iteration %d)" % iteration,
94 95 96 97 98 99 100 101
                              logging.info)

        sub_type = params.get("sub_type_before_plug")
        if sub_type:
            error_context.context(context_msg % (sub_type, "before hotplug"),
                                  logging.info)
            utils_test.run_virt_sub_test(test, params, env, sub_type)

X
Xu Han 已提交
102
        for num in range(blk_num):
103 104
            device = qdevices.QDevice(pci_type)
            if params.get("need_plug") == "yes":
105 106
                disks_before_plug = find_disk(vm, get_disk_cmd)

107 108
                if params.get("need_controller", "no") == "yes":
                    controller_model = params.get("controller_model")
109 110
                    controller = qdevices.QDevice(controller_model, params={"id":
                                                  "hotadded_scsi%s" % num})
111
                    bus_extra_param = params.get("bus_extra_params_%s" % img_list[num + 1])
112 113 114 115
                    if bus_extra_param:
                        for item in bus_extra_param.split():
                            key, value = item.split("=", 1)
                            qdevice_params = {key: value}
116
                            controller.params.update(qdevice_params)
117 118 119 120
                    controller.hotplug(vm.monitor)
                    ver_out = controller.verify_hotplug("", vm.monitor)
                    if not ver_out:
                        err = "%s is not in qtree after hotplug" % controller_model
121
                        test.fail(err)
122 123
                    else:
                        controller_list.append(controller)
124 125 126 127 128 129 130 131 132

                drive = qdevices.QRHDrive("block%d" % num)
                drive.set_param("file", find_image(img_list[num + 1]))
                drive.set_param("format", img_format_type)
                drive_id = drive.get_param("id")
                drive.hotplug(vm.monitor)

                device.set_param("drive", drive_id)
                device.set_param("id", "block%d" % num)
133 134
                if params.get("need_controller", "no") == "yes" and bool(random.randrange(2)):
                    device.set_param("bus", controller.get_param("id")+'.0')
135
                blk_extra_param = params.get("blk_extra_params_%s" % img_list[num + 1])
136 137 138 139
                if blk_extra_param:
                    for item in blk_extra_param.split():
                        key, value = item.split("=", 1)
                        device.set_param(key, value)
140 141 142 143
                device.hotplug(vm.monitor)
                ver_out = device.verify_hotplug("", vm.monitor)
                if not ver_out:
                    err = "%s is not in qtree after hotplug" % pci_type
144
                    test.fail(err)
145 146 147 148 149 150 151
                plug_status = utils_misc.wait_for(lambda: len(get_new_disk(disks_before_plug,
                                                  find_disk(vm, get_disk_cmd))) != 0, pause)
                if plug_status:
                    disks_after_plug = find_disk(vm, get_disk_cmd)
                    new_disks = get_new_disk(disks_before_plug, disks_after_plug)
                else:
                    test.fail("Can't get new disks")
152 153 154 155 156 157 158 159 160 161 162 163 164 165
                if params.get("need_controller", "no") == "yes":
                    info_qtree = vm.monitor.info('qtree', False)
                    qtree = qemu_qtree.QtreeContainer()
                    qtree.parse_info_qtree(info_qtree)
                    for node in qtree.get_nodes():
                        if node.qtree.get("id") == device.get_param("id"):
                            try:
                                controller_id = node.parent.qtree.get("id").split(".")[0]
                            except AttributeError:
                                test.fail("can't get parent of:\n%s" % node)
                            controller_device_dict.setdefault(controller_id, []).append(device)
                            break
                    else:
                        test.fail("Can't find device '%s' in qtree" % device.get_param("id"))
166 167 168 169 170
            else:
                if params.get("drive_format") in pci_type:
                    get_disk_cmd += " | egrep -v '^/dev/[hsv]da[0-9]*$'"

                device.set_param("id", img_list[num + 1])
171
                new_disks = find_disk(vm, get_disk_cmd)
172 173 174

            device_list.append(device)
            if not new_disks:
175
                test.fail("Cannot find new disk after hotplug.")
176 177 178 179 180 181

            if params.get("need_plug") == "yes":
                disk = new_disks[0]
            else:
                disk = new_disks[num]

182 183 184 185 186 187
            session = vm.wait_for_login(timeout=timeout)
            if params.get("os_type") == "windows":
                if iteration == 0:
                    error_context.context("Format disk", logging.info)
                    utils_misc.format_windows_disk(session, disk_index[num],
                                                   mountpoint=disk_letter[num])
188 189
            error_context.context("Check block device after hotplug.",
                                  logging.info)
190
            if params.get("disk_op_cmd"):
191
                if params.get("os_type") == "linux":
192 193 194 195 196
                    test_cmd = params.get("disk_op_cmd") % (disk, disk)
                elif params.get("os_type") == "windows":
                    test_cmd = params.get("disk_op_cmd") % (disk_letter[num],
                                                            disk_letter[num])
                    test_cmd = utils_misc.set_winutils_letter(session, test_cmd)
197
                else:
198 199 200 201 202 203 204 205
                    test.cancel("Unsupported OS type '%s'" % params.get("os_type"))

                status, output = session.cmd_status_output(test_cmd,
                                                           timeout=disk_op_timeout)
                if status:
                    test.fail("Check for block device failed "
                              "after hotplug, Output: %r" % output)
            session.close()
206 207 208 209 210 211

        sub_type = params.get("sub_type_after_plug")
        if sub_type:
            error_context.context(context_msg % (sub_type, "after hotplug"),
                                  logging.info)
            utils_test.run_virt_sub_test(test, params, env, sub_type)
212
            if sub_type == "shutdown" and vm.is_dead():
213
                return
214 215 216 217 218 219 220

        sub_type = params.get("sub_type_before_unplug")
        if sub_type:
            error_context.context(context_msg % (sub_type, "before unplug"),
                                  logging.info)
            utils_test.run_virt_sub_test(test, params, env, sub_type)

221 222 223 224 225 226 227 228 229 230 231 232
        error_context.context("Unplug block device (iteration %d)" % iteration,
                              logging.info)
        for controller in controller_list:
            controller_id = controller.get_param("id")
            for device in controller_device_dict.get(controller_id, []):
                unplug_status = unplug_device(vm, get_disk_cmd, device)
                if not unplug_status:
                    test.fail("Failed to unplug disks '%s'" % device.get_param("id"))
                device_list.remove(device)
            controller.unplug(vm.monitor)
        for device in device_list:
            unplug_status = unplug_device(vm, get_disk_cmd, device)
233
            if not unplug_status:
234
                test.fail("Failed to unplug disks '%s'" % device.get_param("id"))
235 236 237 238 239 240

        sub_type = params.get("sub_type_after_unplug")
        if sub_type:
            error_context.context(context_msg % (sub_type, "after unplug"),
                                  logging.info)
            utils_test.run_virt_sub_test(test, params, env, sub_type)