Index: client/tests/kvm/test_setup.py |
diff --git a/client/tests/kvm/test_setup.py b/client/tests/kvm/test_setup.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..eebe0c36f188be970404cf5f07a1e2afda506aae |
--- /dev/null |
+++ b/client/tests/kvm/test_setup.py |
@@ -0,0 +1,695 @@ |
+""" |
+Library to perform pre/post test setup for KVM autotest. |
+""" |
+import os, shutil, tempfile, re, ConfigParser, glob, inspect |
+import logging, time |
+from autotest_lib.client.common_lib import error |
+from autotest_lib.client.bin import utils |
+ |
+ |
+@error.context_aware |
+def cleanup(dir): |
+ """ |
+ If dir is a mountpoint, do what is possible to unmount it. Afterwards, |
+ try to remove it. |
+ |
+ @param dir: Directory to be cleaned up. |
+ """ |
+ error.context("cleaning up unattended install directory %s" % dir) |
+ if os.path.ismount(dir): |
+ utils.run('fuser -k %s' % dir, ignore_status=True) |
+ utils.run('umount %s' % dir) |
+ if os.path.isdir(dir): |
+ shutil.rmtree(dir) |
+ |
+ |
+@error.context_aware |
+def clean_old_image(image): |
+ """ |
+ Clean a leftover image file from previous processes. If it contains a |
+ mounted file system, do the proper cleanup procedures. |
+ |
+ @param image: Path to image to be cleaned up. |
+ """ |
+ error.context("cleaning up old leftover image %s" % image) |
+ if os.path.exists(image): |
+ mtab = open('/etc/mtab', 'r') |
+ mtab_contents = mtab.read() |
+ mtab.close() |
+ if image in mtab_contents: |
+ utils.run('fuser -k %s' % image, ignore_status=True) |
+ utils.run('umount %s' % 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. |
+ """ |
+ def __init__(self): |
+ self.path = None |
+ |
+ |
+ def setup_answer_file(self, filename, contents): |
+ utils.open_write_close(os.path.join(self.mount, filename), contents) |
+ |
+ |
+ def copy_to(self, src): |
+ dst = os.path.join(self.mount, os.path.basename(src)) |
+ if os.path.isdir(src): |
+ shutil.copytree(src, dst) |
+ elif os.path.isfile(src): |
+ shutil.copyfile(src, dst) |
+ |
+ |
+ def close(self): |
+ os.chmod(self.path, 0755) |
+ cleanup(self.mount) |
+ logging.debug("Disk %s successfuly set", self.path) |
+ |
+ |
+class FloppyDisk(Disk): |
+ """ |
+ Represents a 1.44 MB floppy disk. We can copy files to it, and setup it in |
+ convenient ways. |
+ """ |
+ @error.context_aware |
+ def __init__(self, path, qemu_img_binary, tmpdir): |
+ error.context("Creating unattended install floppy image %s" % path) |
+ self.tmpdir = tmpdir |
+ self.mount = tempfile.mkdtemp(prefix='floppy_', dir=self.tmpdir) |
+ self.virtio_mount = None |
+ self.path = path |
+ clean_old_image(path) |
+ if not os.path.isdir(os.path.dirname(path)): |
+ os.makedirs(os.path.dirname(path)) |
+ |
+ try: |
+ c_cmd = '%s create -f raw %s 1440k' % (qemu_img_binary, path) |
+ utils.run(c_cmd) |
+ f_cmd = 'mkfs.msdos -s 1 %s' % path |
+ utils.run(f_cmd) |
+ m_cmd = 'mount -o loop,rw %s %s' % (path, self.mount) |
+ utils.run(m_cmd) |
+ except error.CmdError, e: |
+ cleanup(self.mount) |
+ raise |
+ |
+ |
+ def _copy_virtio_drivers(self, virtio_floppy): |
+ """ |
+ Copy the virtio drivers on the virtio floppy to the install floppy. |
+ |
+ 1) Mount the floppy containing the viostor drivers |
+ 2) Copy its contents to the root of the install floppy |
+ """ |
+ virtio_mount = tempfile.mkdtemp(prefix='virtio_floppy_', |
+ dir=self.tmpdir) |
+ |
+ pwd = os.getcwd() |
+ try: |
+ m_cmd = 'mount -o loop %s %s' % (virtio_floppy, virtio_mount) |
+ utils.run(m_cmd) |
+ os.chdir(virtio_mount) |
+ path_list = glob.glob('*') |
+ for path in path_list: |
+ self.copy_to(path) |
+ finally: |
+ os.chdir(pwd) |
+ cleanup(virtio_mount) |
+ |
+ |
+ def setup_virtio_win2003(self, virtio_floppy, virtio_oemsetup_id): |
+ """ |
+ Setup the install floppy with the virtio storage drivers, win2003 style. |
+ |
+ Win2003 and WinXP depend on the file txtsetup.oem file to install |
+ the virtio drivers from the floppy, which is a .ini file. |
+ Process: |
+ |
+ 1) Copy the virtio drivers on the virtio floppy to the install floppy |
+ 2) Parse the ini file with config parser |
+ 3) Modify the identifier of the default session that is going to be |
+ executed on the config parser object |
+ 4) Re-write the config file to the disk |
+ """ |
+ self._copy_virtio_drivers(virtio_floppy) |
+ txtsetup_oem = os.path.join(self.mount, 'txtsetup.oem') |
+ if not os.path.isfile(txtsetup_oem): |
+ raise IOError('File txtsetup.oem not found on the install ' |
+ 'floppy. Please verify if your floppy virtio ' |
+ 'driver image has this file') |
+ parser = ConfigParser.ConfigParser() |
+ parser.read(txtsetup_oem) |
+ if not parser.has_section('Defaults'): |
+ raise ValueError('File txtsetup.oem does not have the session ' |
+ '"Defaults". Please check txtsetup.oem') |
+ default_driver = parser.get('Defaults', 'SCSI') |
+ if default_driver != virtio_oemsetup_id: |
+ parser.set('Defaults', 'SCSI', virtio_oemsetup_id) |
+ fp = open(txtsetup_oem, 'w') |
+ parser.write(fp) |
+ fp.close() |
+ |
+ |
+ def setup_virtio_win2008(self, virtio_floppy): |
+ """ |
+ Setup the install floppy with the virtio storage drivers, win2008 style. |
+ |
+ Win2008, Vista and 7 require people to point out the path to the drivers |
+ on the unattended file, so we just need to copy the drivers to the |
+ driver floppy disk. |
+ Process: |
+ |
+ 1) Copy the virtio drivers on the virtio floppy to the install floppy |
+ """ |
+ self._copy_virtio_drivers(virtio_floppy) |
+ |
+ |
+class CdromDisk(Disk): |
+ """ |
+ Represents a CDROM disk that we can master according to our needs. |
+ """ |
+ def __init__(self, path, tmpdir): |
+ self.mount = tempfile.mkdtemp(prefix='cdrom_unattended_', dir=tmpdir) |
+ self.path = path |
+ clean_old_image(path) |
+ if not os.path.isdir(os.path.dirname(path)): |
+ os.makedirs(os.path.dirname(path)) |
+ |
+ |
+ @error.context_aware |
+ def close(self): |
+ error.context("Creating unattended install CD image %s" % self.path) |
+ g_cmd = ('mkisofs -o %s -max-iso9660-filenames ' |
+ '-relaxed-filenames -D --input-charset iso8859-1 ' |
+ '%s' % (self.path, self.mount)) |
+ utils.run(g_cmd) |
+ |
+ os.chmod(self.path, 0755) |
+ cleanup(self.mount) |
+ logging.debug("unattended install CD image %s successfuly created", |
+ self.path) |
+ |
+ |
+class UnattendedInstallConfig(object): |
+ """ |
+ Creates a floppy disk image that will contain a config file for unattended |
+ OS install. The parameters to the script are retrieved from environment |
+ variables. |
+ """ |
+ def __init__(self, test, params): |
+ """ |
+ Sets class atributes from test parameters. |
+ |
+ @param test: KVM test object. |
+ @param params: Dictionary with test parameters. |
+ """ |
+ root_dir = test.bindir |
+ images_dir = os.path.join(root_dir, 'images') |
+ self.deps_dir = os.path.join(root_dir, 'deps') |
+ self.unattended_dir = os.path.join(root_dir, 'unattended') |
+ |
+ attributes = ['kernel_args', 'finish_program', 'cdrom_cd1', |
+ 'unattended_file', 'medium', 'url', 'kernel', 'initrd', |
+ 'nfs_server', 'nfs_dir', 'install_virtio', 'floppy', |
+ 'cdrom_unattended', 'boot_path', 'extra_params', |
+ 'qemu_img_binary'] |
+ |
+ for a in attributes: |
+ setattr(self, a, params.get(a, '')) |
+ |
+ if self.install_virtio == 'yes': |
+ v_attributes = ['virtio_floppy', 'virtio_storage_path', |
+ 'virtio_network_path', 'virtio_oemsetup_id', |
+ 'virtio_network_installer'] |
+ for va in v_attributes: |
+ setattr(self, va, params.get(va, '')) |
+ |
+ self.tmpdir = test.tmpdir |
+ |
+ if getattr(self, 'unattended_file'): |
+ self.unattended_file = os.path.join(root_dir, self.unattended_file) |
+ |
+ if getattr(self, 'qemu_img_binary'): |
+ if not os.path.isfile(getattr(self, 'qemu_img_binary')): |
+ self.qemu_img_binary = os.path.join(root_dir, |
+ self.qemu_img_binary) |
+ |
+ if getattr(self, 'cdrom_cd1'): |
+ self.cdrom_cd1 = os.path.join(root_dir, self.cdrom_cd1) |
+ self.cdrom_cd1_mount = tempfile.mkdtemp(prefix='cdrom_cd1_', |
+ dir=self.tmpdir) |
+ if self.medium == 'nfs': |
+ self.nfs_mount = tempfile.mkdtemp(prefix='nfs_', |
+ dir=self.tmpdir) |
+ |
+ if getattr(self, 'floppy'): |
+ self.floppy = os.path.join(root_dir, self.floppy) |
+ if not os.path.isdir(os.path.dirname(self.floppy)): |
+ os.makedirs(os.path.dirname(self.floppy)) |
+ |
+ self.image_path = os.path.dirname(self.kernel) |
+ |
+ |
+ @error.context_aware |
+ def render_answer_file(self): |
+ """ |
+ Replace KVM_TEST_CDKEY (in the unattended file) with the cdkey |
+ provided for this test and replace the KVM_TEST_MEDIUM with |
+ the tree url or nfs address provided for this test. |
+ |
+ @return: Answer file contents |
+ """ |
+ error.base_context('Rendering final answer file') |
+ error.context('Reading answer file %s' % self.unattended_file) |
+ unattended_contents = open(self.unattended_file).read() |
+ dummy_cdkey_re = r'\bKVM_TEST_CDKEY\b' |
+ real_cdkey = os.environ.get('KVM_TEST_cdkey') |
+ if re.search(dummy_cdkey_re, unattended_contents): |
+ if real_cdkey: |
+ unattended_contents = re.sub(dummy_cdkey_re, real_cdkey, |
+ unattended_contents) |
+ else: |
+ print ("WARNING: 'cdkey' required but not specified for " |
+ "this unattended installation") |
+ |
+ dummy_medium_re = r'\bKVM_TEST_MEDIUM\b' |
+ if self.medium == "cdrom": |
+ content = "cdrom" |
+ elif self.medium == "url": |
+ content = "url --url %s" % self.url |
+ elif self.medium == "nfs": |
+ content = "nfs --server=%s --dir=%s" % (self.nfs_server, |
+ self.nfs_dir) |
+ else: |
+ raise ValueError("Unexpected installation medium %s" % self.url) |
+ |
+ unattended_contents = re.sub(dummy_medium_re, content, |
+ unattended_contents) |
+ |
+ def replace_virtio_key(contents, dummy_re, env): |
+ """ |
+ Replace a virtio dummy string with contents. |
+ |
+ If install_virtio is not set, replace it with a dummy string. |
+ |
+ @param contents: Contents of the unattended file |
+ @param dummy_re: Regular expression used to search on the. |
+ unattended file contents. |
+ @param env: Name of the environment variable. |
+ """ |
+ dummy_path = "C:" |
+ driver = os.environ.get(env, '') |
+ |
+ if re.search(dummy_re, contents): |
+ if self.install_virtio == "yes": |
+ if driver.endswith("msi"): |
+ driver = 'msiexec /passive /package ' + driver |
+ else: |
+ try: |
+ # Let's escape windows style paths properly |
+ drive, path = driver.split(":") |
+ driver = drive + ":" + re.escape(path) |
+ except: |
+ pass |
+ contents = re.sub(dummy_re, driver, contents) |
+ else: |
+ contents = re.sub(dummy_re, dummy_path, contents) |
+ return contents |
+ |
+ vdict = {r'\bKVM_TEST_STORAGE_DRIVER_PATH\b': |
+ 'KVM_TEST_virtio_storage_path', |
+ r'\bKVM_TEST_NETWORK_DRIVER_PATH\b': |
+ 'KVM_TEST_virtio_network_path', |
+ r'\bKVM_TEST_VIRTIO_NETWORK_INSTALLER\b': |
+ 'KVM_TEST_virtio_network_installer_path'} |
+ |
+ for vkey in vdict: |
+ unattended_contents = replace_virtio_key(unattended_contents, |
+ vkey, vdict[vkey]) |
+ |
+ logging.debug("Unattended install contents:") |
+ for line in unattended_contents.splitlines(): |
+ logging.debug(line) |
+ return unattended_contents |
+ |
+ |
+ def setup_boot_disk(self): |
+ answer_contents = self.render_answer_file() |
+ |
+ if self.unattended_file.endswith('.sif'): |
+ dest_fname = 'winnt.sif' |
+ setup_file = 'winnt.bat' |
+ boot_disk = FloppyDisk(self.floppy, self.qemu_img_binary, |
+ self.tmpdir) |
+ boot_disk.setup_answer_file(dest_fname, answer_contents) |
+ setup_file_path = os.path.join(self.unattended_dir, setup_file) |
+ boot_disk.copy_to(setup_file_path) |
+ if self.install_virtio == "yes": |
+ boot_disk.setup_virtio_win2003(self.virtio_floppy, |
+ self.virtio_oemsetup_id) |
+ boot_disk.copy_to(self.finish_program) |
+ |
+ elif self.unattended_file.endswith('.ks'): |
+ # Red Hat kickstart install |
+ dest_fname = 'ks.cfg' |
+ if self.cdrom_unattended: |
+ boot_disk = CdromDisk(self.cdrom_unattended, self.tmpdir) |
+ elif self.floppy: |
+ boot_disk = FloppyDisk(self.floppy, self.qemu_img_binary, |
+ self.tmpdir) |
+ else: |
+ raise ValueError("Neither cdrom_unattended nor floppy set " |
+ "on the config file, please verify") |
+ boot_disk.setup_answer_file(dest_fname, answer_contents) |
+ |
+ elif self.unattended_file.endswith('.xml'): |
+ if "autoyast" in self.extra_params: |
+ # SUSE autoyast install |
+ dest_fname = "autoinst.xml" |
+ if self.cdrom_unattended: |
+ boot_disk = CdromDisk(self.cdrom_unattended) |
+ elif self.floppy: |
+ boot_disk = FloppyDisk(self.floppy, self.qemu_img_binary, |
+ self.tmpdir) |
+ else: |
+ raise ValueError("Neither cdrom_unattended nor floppy set " |
+ "on the config file, please verify") |
+ boot_disk.setup_answer_file(dest_fname, answer_contents) |
+ |
+ else: |
+ # Windows unattended install |
+ dest_fname = "autounattend.xml" |
+ boot_disk = FloppyDisk(self.floppy, self.qemu_img_binary, |
+ self.tmpdir) |
+ boot_disk.setup_answer_file(dest_fname, answer_contents) |
+ if self.install_virtio == "yes": |
+ boot_disk.setup_virtio_win2008(self.virtio_floppy) |
+ boot_disk.copy_to(self.finish_program) |
+ |
+ else: |
+ raise ValueError('Unknown answer file type: %s' % |
+ self.unattended_file) |
+ |
+ boot_disk.close() |
+ |
+ |
+ @error.context_aware |
+ def setup_cdrom(self): |
+ """ |
+ Mount cdrom and copy vmlinuz and initrd.img. |
+ """ |
+ error.context("Copying vmlinuz and initrd.img from install cdrom %s" % |
+ self.cdrom_cd1) |
+ m_cmd = ('mount -t iso9660 -v -o loop,ro %s %s' % |
+ (self.cdrom_cd1, self.cdrom_cd1_mount)) |
+ utils.run(m_cmd) |
+ |
+ try: |
+ if not os.path.isdir(self.image_path): |
+ os.makedirs(self.image_path) |
+ kernel_fetch_cmd = ("cp %s/%s/%s %s" % |
+ (self.cdrom_cd1_mount, self.boot_path, |
+ os.path.basename(self.kernel), self.kernel)) |
+ utils.run(kernel_fetch_cmd) |
+ initrd_fetch_cmd = ("cp %s/%s/%s %s" % |
+ (self.cdrom_cd1_mount, self.boot_path, |
+ os.path.basename(self.initrd), self.initrd)) |
+ utils.run(initrd_fetch_cmd) |
+ finally: |
+ cleanup(self.cdrom_cd1_mount) |
+ |
+ |
+ @error.context_aware |
+ def setup_url(self): |
+ """ |
+ Download the vmlinuz and initrd.img from URL. |
+ """ |
+ error.context("downloading vmlinuz and initrd.img from %s" % self.url) |
+ os.chdir(self.image_path) |
+ kernel_fetch_cmd = "wget -q %s/%s/%s" % (self.url, self.boot_path, |
+ os.path.basename(self.kernel)) |
+ initrd_fetch_cmd = "wget -q %s/%s/%s" % (self.url, self.boot_path, |
+ os.path.basename(self.initrd)) |
+ |
+ if os.path.exists(self.kernel): |
+ os.remove(self.kernel) |
+ if os.path.exists(self.initrd): |
+ os.remove(self.initrd) |
+ |
+ utils.run(kernel_fetch_cmd) |
+ utils.run(initrd_fetch_cmd) |
+ |
+ |
+ def setup_nfs(self): |
+ """ |
+ Copy the vmlinuz and initrd.img from nfs. |
+ """ |
+ error.context("copying the vmlinuz and initrd.img from NFS share") |
+ |
+ m_cmd = ("mount %s:%s %s -o ro" % |
+ (self.nfs_server, self.nfs_dir, self.nfs_mount)) |
+ utils.run(m_cmd) |
+ |
+ try: |
+ kernel_fetch_cmd = ("cp %s/%s/%s %s" % |
+ (self.nfs_mount, self.boot_path, |
+ os.path.basename(self.kernel), self.image_path)) |
+ utils.run(kernel_fetch_cmd) |
+ initrd_fetch_cmd = ("cp %s/%s/%s %s" % |
+ (self.nfs_mount, self.boot_path, |
+ os.path.basename(self.initrd), self.image_path)) |
+ utils.run(initrd_fetch_cmd) |
+ finally: |
+ cleanup(self.nfs_mount) |
+ |
+ |
+ def setup(self): |
+ """ |
+ Configure the environment for unattended install. |
+ |
+ Uses an appropriate strategy according to each install model. |
+ """ |
+ logging.info("Starting unattended install setup") |
+ display_attributes(self) |
+ |
+ if self.unattended_file and (self.floppy or self.cdrom_unattended): |
+ self.setup_boot_disk() |
+ if self.medium == "cdrom": |
+ if self.kernel and self.initrd: |
+ self.setup_cdrom() |
+ elif self.medium == "url": |
+ self.setup_url() |
+ elif self.medium == "nfs": |
+ self.setup_nfs() |
+ else: |
+ raise ValueError("Unexpected installation method %s" % |
+ self.medium) |
+ |
+ |
+class HugePageConfig(object): |
+ def __init__(self, params): |
+ """ |
+ Gets environment variable values and calculates the target number |
+ of huge memory pages. |
+ |
+ @param params: Dict like object containing parameters for the test. |
+ """ |
+ self.vms = len(params.objects("vms")) |
+ self.mem = int(params.get("mem")) |
+ self.max_vms = int(params.get("max_vms", 0)) |
+ self.hugepage_path = '/mnt/kvm_hugepage' |
+ self.hugepage_size = self.get_hugepage_size() |
+ self.target_hugepages = self.get_target_hugepages() |
+ self.kernel_hp_file = '/proc/sys/vm/nr_hugepages' |
+ |
+ |
+ def get_hugepage_size(self): |
+ """ |
+ Get the current system setting for huge memory page size. |
+ """ |
+ meminfo = open('/proc/meminfo', 'r').readlines() |
+ huge_line_list = [h for h in meminfo if h.startswith("Hugepagesize")] |
+ try: |
+ return int(huge_line_list[0].split()[1]) |
+ except ValueError, e: |
+ raise ValueError("Could not get huge page size setting from " |
+ "/proc/meminfo: %s" % e) |
+ |
+ |
+ def get_target_hugepages(self): |
+ """ |
+ Calculate the target number of hugepages for testing purposes. |
+ """ |
+ if self.vms < self.max_vms: |
+ self.vms = self.max_vms |
+ # memory of all VMs plus qemu overhead of 64MB per guest |
+ vmsm = (self.vms * self.mem) + (self.vms * 64) |
+ return int(vmsm * 1024 / self.hugepage_size) |
+ |
+ |
+ @error.context_aware |
+ def set_hugepages(self): |
+ """ |
+ Sets the hugepage limit to the target hugepage value calculated. |
+ """ |
+ error.context("setting hugepages limit to %s" % self.target_hugepages) |
+ hugepage_cfg = open(self.kernel_hp_file, "r+") |
+ hp = hugepage_cfg.readline() |
+ while int(hp) < self.target_hugepages: |
+ loop_hp = hp |
+ hugepage_cfg.write(str(self.target_hugepages)) |
+ hugepage_cfg.flush() |
+ hugepage_cfg.seek(0) |
+ hp = int(hugepage_cfg.readline()) |
+ if loop_hp == hp: |
+ raise ValueError("Cannot set the kernel hugepage setting " |
+ "to the target value of %d hugepages." % |
+ self.target_hugepages) |
+ hugepage_cfg.close() |
+ logging.debug("Successfuly set %s large memory pages on host ", |
+ self.target_hugepages) |
+ |
+ |
+ @error.context_aware |
+ def mount_hugepage_fs(self): |
+ """ |
+ Verify if there's a hugetlbfs mount set. If there's none, will set up |
+ a hugetlbfs mount using the class attribute that defines the mount |
+ point. |
+ """ |
+ error.context("mounting hugepages path") |
+ if not os.path.ismount(self.hugepage_path): |
+ if not os.path.isdir(self.hugepage_path): |
+ os.makedirs(self.hugepage_path) |
+ cmd = "mount -t hugetlbfs none %s" % self.hugepage_path |
+ utils.system(cmd) |
+ |
+ |
+ def setup(self): |
+ logging.debug("Number of VMs this test will use: %d", self.vms) |
+ logging.debug("Amount of memory used by each vm: %s", self.mem) |
+ logging.debug("System setting for large memory page size: %s", |
+ self.hugepage_size) |
+ logging.debug("Number of large memory pages needed for this test: %s", |
+ self.target_hugepages) |
+ self.set_hugepages() |
+ self.mount_hugepage_fs() |
+ |
+ |
+ @error.context_aware |
+ def cleanup(self): |
+ error.context("trying to dealocate hugepage memory") |
+ try: |
+ utils.system("umount %s" % self.hugepage_path) |
+ except error.CmdError: |
+ 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) |