enospc.py 7.7 KB
Newer Older
L
Lucas Meneghel Rodrigues 已提交
1 2 3 4
import logging
import time
import re
import os
5 6 7 8 9

from virttest import virt_vm
from virttest import utils_misc
from virttest import qemu_storage
from virttest import data_dir
10 11 12
from virttest import error_context

from avocado.utils import process
13 14 15


class EnospcConfig(object):
L
Lucas Meneghel Rodrigues 已提交
16

17 18 19 20 21 22
    """
    Performs setup for the test enospc. This is a borg class, similar to a
    singleton. The idea is to keep state in memory for when we call cleanup()
    on postprocessing.
    """
    __shared_state = {}
L
Lucas Meneghel Rodrigues 已提交
23

24 25 26 27
    def __init__(self, test, params):
        self.__dict__ = self.__shared_state
        root_dir = test.bindir
        self.tmpdir = test.tmpdir
C
Cong Li 已提交
28
        self.qemu_img_binary = utils_misc.get_qemu_img_binary(params)
29 30 31
        self.raw_file_path = os.path.join(self.tmpdir, 'enospc.raw')
        # Here we're trying to choose fairly explanatory names so it's less
        # likely that we run in conflict with other devices in the system
32 33
        self.vgtest_name = params["vgtest_name"]
        self.lvtest_name = params["lvtest_name"]
L
Lucas Meneghel Rodrigues 已提交
34 35
        self.lvtest_device = "/dev/%s/%s" % (
            self.vgtest_name, self.lvtest_name)
36 37
        image_dir = os.path.join(data_dir.get_data_dir(),
                                 os.path.dirname(params["image_name"]))
38 39 40 41 42 43
        self.qcow_file_path = os.path.join(image_dir, 'enospc.qcow2')
        try:
            getattr(self, 'loopback')
        except AttributeError:
            self.loopback = ''

44
    @error_context.context_aware
45 46
    def setup(self):
        logging.debug("Starting enospc setup")
47
        error_context.context("performing enospc setup", logging.info)
48 49 50 51
        utils_misc.display_attributes(self)
        # Double check if there aren't any leftovers
        self.cleanup()
        try:
52 53
            process.run("%s create -f raw %s 10G" %
                        (self.qemu_img_binary, self.raw_file_path))
54 55 56
            # Associate a loopback device with the raw file.
            # Subject to race conditions, that's why try here to associate
            # it with the raw file as quickly as possible
57 58
            l_result = process.run("losetup -f")
            process.run("losetup -f %s" % self.raw_file_path)
59 60 61
            self.loopback = l_result.stdout.strip()
            # Add the loopback device configured to the list of pvs
            # recognized by LVM
62 63
            process.run("pvcreate %s" % self.loopback)
            process.run("vgcreate %s %s" % (self.vgtest_name, self.loopback))
64
            # Create an lv inside the vg with starting size of 200M
65 66
            process.run("lvcreate -L 200M -n %s %s" %
                        (self.lvtest_name, self.vgtest_name))
67
            # Create a 10GB qcow2 image in the logical volume
68 69
            process.run("%s create -f qcow2 %s 10G" %
                        (self.qemu_img_binary, self.lvtest_device))
70 71 72 73
            # Let's symlink the logical volume with the image name that autotest
            # expects this device to have
            os.symlink(self.lvtest_device, self.qcow_file_path)
        except Exception:
74 75 76 77
            try:
                self.cleanup()
            except Exception, e:
                logging.warn(e)
78 79
            raise

80
    @error_context.context_aware
81
    def cleanup(self):
82
        error_context.context("performing enospc cleanup", logging.info)
83
        if os.path.islink(self.lvtest_device):
84
            process.run("fuser -k %s" % self.lvtest_device, ignore_status=True)
85
            time.sleep(2)
86
        l_result = process.run("lvdisplay")
87 88
        # Let's remove all volumes inside the volume group created
        if self.lvtest_name in l_result.stdout:
89
            process.run("lvremove -f %s" % self.lvtest_device)
90
        # Now, removing the volume group itself
91
        v_result = process.run("vgdisplay")
92
        if self.vgtest_name in v_result.stdout:
93
            process.run("vgremove -f %s" % self.vgtest_name)
94 95
        # Now, if we can, let's remove the physical volume from lvm list
        if self.loopback:
96
            p_result = process.run("pvdisplay")
97
            if self.loopback in p_result.stdout:
98 99
                process.run("pvremove -f %s" % self.loopback)
        l_result = process.run('losetup -a')
100 101
        if self.loopback and (self.loopback in l_result.stdout):
            try:
102 103
                process.run("losetup -d %s" % self.loopback)
            except process.CmdError:
104 105 106 107 108 109
                logging.error("Failed to liberate loopback %s", self.loopback)
        if os.path.islink(self.qcow_file_path):
            os.remove(self.qcow_file_path)
        if os.path.isfile(self.raw_file_path):
            os.remove(self.raw_file_path)

L
Lucas Meneghel Rodrigues 已提交
110

111
@error_context.context_aware
112
def run(test, params, env):
113 114 115 116 117 118 119 120 121 122
    """
    ENOSPC test

    1) Create a virtual disk on lvm
    2) Boot up guest with two disks
    3) Continually write data to second disk
    4) Check images and extend second disk when no space
    5) Continue paused guest
    6) Repeat step 3~5 several times

L
Lucas Meneghel Rodrigues 已提交
123 124 125
    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
126
    """
127
    error_context.context("Create a virtual disk on lvm", logging.info)
128 129
    enospc_config = EnospcConfig(test, params)
    enospc_config.setup()
130

131
    error_context.context("Boot up guest with two disks", logging.info)
132 133 134 135 136
    vm = env.get_vm(params["main_vm"])
    vm.create()
    login_timeout = int(params.get("login_timeout", 360))
    session_serial = vm.wait_for_serial_login(timeout=login_timeout)

137 138
    vgtest_name = params["vgtest_name"]
    lvtest_name = params["lvtest_name"]
139 140
    logical_volume = "/dev/%s/%s" % (vgtest_name, lvtest_name)

141
    drive_format = params["drive_format"]
142 143
    output = session_serial.cmd_output("dir /dev")
    devname = "/dev/" + re.findall("([shv]db)\s", output)[0]
144
    cmd = params["background_cmd"]
145
    cmd %= devname
146

147
    error_context.context("Continually write data to second disk", logging.info)
148 149 150 151 152 153 154 155 156
    logging.info("Sending background cmd '%s'", cmd)
    session_serial.sendline(cmd)

    iterations = int(params.get("repeat_time", 40))
    i = 0
    pause_n = 0
    while i < iterations:
        if vm.monitor.verify_status("paused"):
            pause_n += 1
157 158
            error_context.context("Checking all images in use by %s" % vm.name,
                                  logging.info)
159 160 161
            for image_name in vm.params.objects("images"):
                image_params = vm.params.object_params(image_name)
                try:
162
                    image = qemu_storage.QemuImg(image_params,
L
Lucas Meneghel Rodrigues 已提交
163
                                                 data_dir.get_data_dir(), image_name)
164 165
                    image.check_image(image_params, data_dir.get_data_dir(), force_share=True)
                except virt_vm.VMError, e:
166
                    logging.error(e)
167 168
            error_context.context("Guest paused, extending Logical Volume size",
                                  logging.info)
169
            try:
170 171
                process.run("lvextend -L +200M %s" % logical_volume)
            except process.CmdError, e:
X
Xu Han 已提交
172
                logging.debug(e.result.stdout)
173
            error_context.context("Continue paused guest", logging.info)
174 175 176
            vm.resume()
        elif not vm.monitor.verify_status("running"):
            status = str(vm.monitor.info("status"))
177
            test.error("Unexpected guest status: %s" % status)
178 179 180
        time.sleep(10)
        i += 1

181 182 183 184 185 186 187 188
    logging.info("Final %s", str(vm.monitor.info("status")))
    # Shutdown guest before remove the image on LVM.
    vm.destroy(gracefully=vm.monitor.verify_status("running"))
    try:
        enospc_config.cleanup()
    except Exception, e:
        logging.warn(e)

189
    if pause_n == 0:
190
        test.fail("Guest didn't pause during loop")
191 192 193
    else:
        logging.info("Guest paused %s times from %s iterations",
                     pause_n, iterations)