[PATCH 5/6] KVM test: Turn enospc test pre/post actions into infrastructure

Lucas Meneghel Rodrigues
2011-01-22T01:30:49Z

So we can get rid of the pre/post scripts. Wit the rearrangement
we were able to achieve several advantages:

- More rigorous and paranoid cleanup phase
- Better identification of the lvm devices, less likely to
originate conflicts with devices in the host
- Use the shared autotest API avoiding code duplication

Signed-off-by: Lucas Meneghel Rodrigues <lmr@redhat.com>
---
client/tests/kvm/kvm_preprocessing.py | 8 ++
client/tests/kvm/test_setup.py | 116 +++++++++++++++++++++++++++++--
client/tests/kvm/tests/enospc.py | 6 ++-
client/tests/kvm/tests_base.cfg.sample | 5 +-
4 files changed, 124 insertions(+), 11 deletions(-)

diff --git a/client/tests/kvm/kvm_preprocessing.py b/client/tests/kvm/kvm_preprocessing.py
index 081a13f..2713805 100644
--- a/client/tests/kvm/kvm_preprocessing.py
+++ b/client/tests/kvm/kvm_preprocessing.py
@@ -262,6 +262,10 @@ def preprocess(test, params, env):
u = test_setup.UnattendedInstallConfig(test, params)
u.setup()

+ if params.get("type") == "enospc":
+ e = test_setup.EnospcConfig(test, params)
+ e.setup()
+
# Execute any pre_commands
if params.get("pre_command"):
process_command(test, params, env, params.get("pre_command"),
@@ -362,6 +366,10 @@ def postprocess(test, params, env):
h = kvm_utils.HugePageConfig(params)
h.cleanup()

+ if params.get("type") == "enospc":
+ e = test_setup.EnospcConfig(test, params)
+ e.cleanup()
+
# Execute any post_commands
if params.get("post_command"):
process_command(test, params, env, params.get("post_command"),
diff --git a/client/tests/kvm/test_setup.py b/client/tests/kvm/test_setup.py
index b17c473..e906e18 100644
--- a/client/tests/kvm/test_setup.py
+++ b/client/tests/kvm/test_setup.py
@@ -2,7 +2,7 @@
Library to perform pre/post test setup for KVM autotest.
"""
import os, sys, shutil, tempfile, re, ConfigParser, glob, inspect, commands
-import logging
+import logging, time
from autotest_lib.client.common_lib import error
from autotest_lib.client.bin import utils

@@ -42,6 +42,19 @@ def clean_old_image(image):
os.remove(image)

+def display_attributes(instance):
+ """
+ Inspects a given class instance attributes and displays them, convenient
+ for debugging.
+ """
+ logging.debug("Attributes set:")
+ for member in inspect.getmembers(instance):
+ name, value = member
+ attribute = getattr(instance, name)
+ if not (name.startswith("__") or callable(attribute) or not value):
+ logging.debug(" %s: %s", name, value)
+
+
class Disk(object):
"""
Abstract class for Disk objects, with the common methods implemented.
@@ -472,13 +485,7 @@ class UnattendedInstallConfig(object):
Uses an appropriate strategy according to each install model.
"""
logging.info("Starting unattended install setup")
-
- logging.debug("Variables set:")
- for member in inspect.getmembers(self):
- name, value = member
- attribute = getattr(self, name)
- if not (name.startswith("__") or callable(attribute) or not value):
- logging.debug(" %s: %s", name, value)
+ display_attributes(self)

if self.unattended_file and (self.floppy or self.cdrom_unattended):
self.setup_boot_disk()
@@ -593,3 +600,96 @@ class HugePageConfig(object):
return
utils.system("echo 0 > %s" % self.kernel_hp_file)
logging.debug("Hugepage memory successfuly dealocated")
+
+
+class EnospcConfig(object):
+ """
+ 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 = {}
+ def __init__(self, test, params):
+ self.__dict__ = self.__shared_state
+ root_dir = test.bindir
+ self.tmpdir = test.tmpdir
+ self.qemu_img_binary = params.get('qemu_img_binary')
+ if not os.path.isfile(self.qemu_img_binary):
+ self.qemu_img_binary = os.path.join(root_dir,
+ self.qemu_img_binary)
+ 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
+ self.vgtest_name = params.get("vgtest_name")
+ self.lvtest_name = params.get("lvtest_name")
+ self.lvtest_device = "/dev/%s/%s" % (self.vgtest_name, self.lvtest_name)
+ image_dir = os.path.dirname(params.get("image_name"))
+ self.qcow_file_path = os.path.join(image_dir, 'enospc.qcow2')
+ try:
+ getattr(self, 'loopback')
+ except AttributeError:
+ self.loopback = ''
+
+
+ @error.context_aware
+ def setup(self):
+ logging.debug("Starting enospc setup")
+ error.context("performing enospc setup")
+ display_attributes(self)
+ # Double check if there aren't any leftovers
+ self.cleanup()
+ try:
+ utils.run("%s create -f raw %s 10G" %
+ (self.qemu_img_binary, self.raw_file_path))
+ # 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
+ l_result = utils.run("losetup -f")
+ utils.run("losetup -f %s" % self.raw_file_path)
+ self.loopback = l_result.stdout.strip()
+ # Add the loopback device configured to the list of pvs
+ # recognized by LVM
+ utils.run("pvcreate %s" % self.loopback)
+ utils.run("vgcreate %s %s" % (self.vgtest_name, self.loopback))
+ # Create an lv inside the vg with starting size of 200M
+ utils.run("lvcreate -L 200M -n %s %s" %
+ (self.lvtest_name, self.vgtest_name))
+ # Create a 10GB qcow2 image in the logical volume
+ utils.run("%s create -f qcow2 %s 10G" %
+ (self.qemu_img_binary, self.lvtest_device))
+ # 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, e:
+ self.cleanup()
+ raise
+
+ @error.context_aware
+ def cleanup(self):
+ error.context("performing enospc cleanup")
+ if os.path.isfile(self.lvtest_device):
+ utils.run("fuser -k %s" % self.lvtest_device)
+ time.sleep(2)
+ l_result = utils.run("lvdisplay")
+ # Let's remove all volumes inside the volume group created
+ if self.lvtest_name in l_result.stdout:
+ utils.run("lvremove -f %s" % self.lvtest_device)
+ # Now, removing the volume group itself
+ v_result = utils.run("vgdisplay")
+ if self.vgtest_name in v_result.stdout:
+ utils.run("vgremove -f %s" % self.vgtest_name)
+ # Now, if we can, let's remove the physical volume from lvm list
+ if self.loopback:
+ p_result = utils.run("pvdisplay")
+ if self.loopback in p_result.stdout:
+ utils.run("pvremove -f %s" % self.loopback)
+ l_result = utils.run('losetup -a')
+ if self.loopback and (self.loopback in l_result.stdout):
+ try:
+ utils.run("losetup -d %s" % self.loopback)
+ except error.CmdError:
+ 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)
diff --git a/client/tests/kvm/tests/enospc.py b/client/tests/kvm/tests/enospc.py
index 6a149f9..3868cc4 100644
--- a/client/tests/kvm/tests/enospc.py
+++ b/client/tests/kvm/tests/enospc.py
@@ -24,6 +24,10 @@ def run_enospc(test, params, env):
login_timeout = int(params.get("login_timeout", 360))
session_serial = vm.wait_for_serial_login(timeout=login_timeout)

+ vgtest_name = params.get("vgtest_name")
+ lvtest_name = params.get("lvtest_name")
+ logical_volume = "/dev/%s/%s" % (vgtest_name, lvtest_name)
+
drive_format = params.get("drive_format")
if drive_format == "virtio":
devname = "/dev/vdb"
@@ -54,7 +58,7 @@ def run_enospc(test, params, env):
logging.error(e)
logging.info("Guest paused, extending Logical Volume size")
try:
- cmd_result = utils.run("lvextend -L +200M /dev/vgtest/lvtest")
+ cmd_result = utils.run("lvextend -L +200M %s" % logical_volume)
except error.CmdError, e:
logging.debug(e.result_obj.stdout)
vm.monitor.cmd("cont")
diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kvm/tests_base.cfg.sample
index f90d551..bd2f720 100644
--- a/client/tests/kvm/tests_base.cfg.sample
+++ b/client/tests/kvm/tests_base.cfg.sample
@@ -601,9 +601,10 @@ variants:
image_format_stg = qcow2
image_boot_stg = no
image_snapshot_stg = no
+ check_image_stg = no
+ vgtest_name = vg_kvm_test_enospc
+ lvtest_name = lv_kvm_test_enospc
background_cmd = "nohup dd if=/dev/zero of=%s bs=1024 &"
- pre_command += " scripts/enospc-pre.py;"
- post_command += " scripts/enospc-post.py;"
kill_vm = yes

- qmp_basic: install setup unattended_install.cdrom
--
1.7.3.4