It also can create a volume group on top of a ramdisk for increased performance. Internally it creates a volume group on top of a "sparse file", so it will only allocate the memory it really needs.
Signed-off-by: Plamen Dimitrov <[email protected]> --- client/tests/lvsetup/lvsetup.py | 249 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 client/tests/lvsetup/lvsetup.py diff --git a/client/tests/lvsetup/lvsetup.py b/client/tests/lvsetup/lvsetup.py new file mode 100644 index 0000000..877f041 --- /dev/null +++ b/client/tests/lvsetup/lvsetup.py @@ -0,0 +1,249 @@ +""" +Test that automatically takes shapshots from existing logical volumes +or creates such. +""" + +import logging +import re, os, shutil, time + +from autotest.client import utils, test +from autotest.client.shared import error + +# size in MB +RAMDISK_VG_SIZE = "40000" +RAMDISK_BASEDIR = "/tmp" +RAMDISK_SPARSE_FILENAME = "virtual_hdd" + +class lvsetup(test.test): + """ + Test class inheriting from test with main method run_once(). + + If this test turns into a library the constants at its beginning should + be converted to class attributes and initiated in a constructor. + """ + version = 1 + + def _vg_ramdisk(self, vg_name): + """ + Create vg on top of ram memory to speed up lv performance. + """ + logging.info("Creating virtual group on top of ram memory") + vg_size = RAMDISK_VG_SIZE + vg_ramdisk_dir = os.path.join(RAMDISK_BASEDIR, vg_name) + ramdisk_filename = os.path.join(vg_ramdisk_dir, + RAMDISK_SPARSE_FILENAME) + + self._vg_ramdisk_cleanup(ramdisk_filename, + vg_ramdisk_dir, vg_name, "") + result = "" + if not os.path.exists(vg_ramdisk_dir): + os.mkdir(vg_ramdisk_dir) + try: + logging.info("Mounting tmpfs") + result = utils.run("mount -t tmpfs tmpfs " + vg_ramdisk_dir) + logging.info("Converting and copying /dev/zero") + cmd = ("dd if=/dev/zero of=" + ramdisk_filename + + " bs=1M count=1 seek=" + vg_size) + result = utils.run(cmd, verbose=True) + logging.info("Finding free loop device") + result = utils.run("losetup --find", verbose=True) + except error.CmdError as ex: + logging.error(ex) + self._vg_ramdisk_cleanup(ramdisk_filename, + vg_ramdisk_dir, vg_name, "") + raise ex + loop_device = result.stdout.rstrip() + + try: + logging.info("Creating loop device") + result = utils.run("losetup " + loop_device + + " " + ramdisk_filename) + logging.info("Creating physical volume %s", loop_device) + result = utils.run("pvcreate " + loop_device) + logging.info("Creating volume group %s", vg_name) + result = utils.run("vgcreate " + vg_name + + " " + loop_device) + except error.CmdError as ex: + logging.error(ex) + self._vg_ramdisk_cleanup(ramdisk_filename, vg_ramdisk_dir, + vg_name, loop_device) + raise ex + + logging.info(result.stdout.rstrip()) + + + def _vg_ramdisk_cleanup(self, ramdisk_filename, vg_ramdisk_dir, + vg_name, loop_device): + """ + Inline cleanup function in case of test error. + """ + result = utils.run("vgremove " + vg_name, ignore_status=True) + if result.exit_status == 0: + logging.info(result.stdout.rstrip()) + else: + logging.debug("%s -> %s", result.command, result.stderr) + result = utils.run("pvremove " + loop_device, ignore_status=True) + if result.exit_status == 0: + logging.info(result.stdout.rstrip()) + else: + logging.debug("%s -> %s", result.command, result.stderr) + for i in range(10): + time.sleep(0.1) + result = utils.run("losetup -d " + loop_device, ignore_status=True) + if "resource busy" not in result.stderr: + if result.exit_status != 0: + logging.debug("%s -> %s", result.command, result.stderr) + else: + logging.info("Loop device %s deleted", loop_device) + break + if os.path.exists(ramdisk_filename): + os.unlink(ramdisk_filename) + logging.info("Ramdisk filename %s deleted", ramdisk_filename) + utils.run("umount " + vg_ramdisk_dir, ignore_status=True) + if result.exit_status == 0: + if loop_device != "": + logging.info("Loop device %s unmounted", loop_device) + else: + logging.debug("%s -> %s", result.command, result.stderr) + if os.path.exists(vg_ramdisk_dir): + try: + shutil.rmtree(vg_ramdisk_dir) + logging.info("Ramdisk directory %s deleted", vg_ramdisk_dir) + except OSError: + pass + + + def _vg_check(self, vg_name): + """ + Check whether provided volume group exists. + """ + cmd = "vgdisplay " + vg_name + result = utils.run(cmd, ignore_status=True) + if result.exit_status == 0: + logging.info("Provided logical group exists: " + vg_name) + return True + else: + return False + + + def _lv_check(self, vg_name, lv_name): + """ + Check whether provided logical volume exists. + """ + cmd = "lvdisplay" + result = utils.run(cmd) + + # unstable approach but currently works + #lvpattern = r'LV Name\s+/dev/' + vg_name + r'/' + lv_name + lvpattern = r"LV Path\s+/dev/" + vg_name + r"/" + lv_name + "\s+" + + match = re.search(lvpattern, result.stdout.rstrip()) + if match: + logging.info("Provided logical volume exists: /dev/" + + vg_name + "/" + lv_name) + return True + else: + return False + + + def _lv_remove(self, vg_name, lv_name): + """ + Create a logical volume. + """ + logging.warning("Removing origin") + cmd = "lvremove -f " + vg_name + "/" + lv_name + result = utils.run(cmd) + logging.info(result.stdout.rstrip()) + + + def _lv_create(self, vg_name, lv_name, lv_size): + """ + Create a logical volume. + """ + logging.warning("Creating lv origin to take snapshot from") + cmd = ("lvcreate --size " + lv_size + + " --name " + lv_name + " " + + vg_name) + result = utils.run(cmd) + logging.info(result.stdout.rstrip()) + + + def _lv_revert(self, vg_name, lv_snapshot_name): + """ + Revert the origin to a snapshot. + """ + logging.info("Reverting origin to snapshot") + cmd = ("lvconvert --merge /dev/%s/%s" + % (vg_name, lv_snapshot_name)) + result = utils.run(cmd) + logging.info(result.stdout.rstrip()) + + + def _lv_take_snapshot(self, vg_name, lv_name, + lv_snapshot_name, lv_snapshot_size): + """ + Take a snapshot of the original logical volume. + """ + logging.info("Taking snapshot from origin") + cmd = ("lvcreate --size " + lv_snapshot_size + " --snapshot " + + " --name " + lv_snapshot_name + + " /dev/" + vg_name + "/" + lv_name) + result = utils.run(cmd) + logging.info(result.stdout.rstrip()) + + + def run_once(self, vg_name, lv_name, lv_size, + lv_snapshot_name, lv_snapshot_size, override_flag = 0): + """ + General logical volume setup. + + The main part of the lvm setup checks whether the provided volume group + exists and if not, creates one from the ramdisk. It then creates a logical + volume if there is no logical volume, takes a snapshot from the logical + if there is logical volume but no snapshot, and merges with the snapshot + if both the snapshot and the logical volume are present. + + @param vg_name: Name of the volume group. + @param lv_name: Name of the logical volume. + @param lv_size: Size of the logical volume as string in the form "#G" + (for example 30G). + @param lv_snapshot_name: Name of the snapshot with origin the logical + volume. + @param lv_snapshot_size: Size of the snapshot with origin the logical + volume also as "#G". + @param override_flag: Flag to override default policy. Override flag + can be set to -1 to force remove, 1 to force create, and 0 + for default. + """ + # if no virtual group is defined create one based on ramdisk + if not self._vg_check(vg_name): + self._vg_ramdisk(vg_name) + + # if no snapshot is defined start fresh logical volume + if override_flag == 1 and self._lv_check(vg_name, lv_name): + self._lv_remove(vg_name, lv_name) + self._lv_create(vg_name, lv_name, lv_size) + elif override_flag == -1 and self._lv_check(vg_name, lv_name): + self._lv_remove(vg_name, lv_name) + else: + + # perform normal check policy + if (self._lv_check(vg_name, lv_snapshot_name) + and self._lv_check(vg_name, lv_name)): + self._lv_revert(vg_name, lv_snapshot_name) + self._lv_take_snapshot(vg_name, lv_name, + lv_snapshot_name, + lv_snapshot_size) + + elif (self._lv_check(vg_name, lv_snapshot_name) + and not self._lv_check(vg_name, lv_name)): + raise error.TestError("Snapshot origin not found") + + elif (not self._lv_check(vg_name, lv_snapshot_name) + and self._lv_check(vg_name, lv_name)): + self._lv_take_snapshot(vg_name, lv_name, + lv_snapshot_name, + lv_snapshot_size) + + else: + self._lv_create(vg_name, lv_name, lv_size) -- 1.7.11.4 _______________________________________________ Autotest-kernel mailing list [email protected] https://www.redhat.com/mailman/listinfo/autotest-kernel
