def copyif(params, nbd_image, target_image, bitmap=None): """ Python implementation of copyif3.sh :params params: utils_params.Params object :params nbd_image: nbd image tag :params target_image: target image tag :params bitmap: bitmap name """ def _qemu_io_read(qemu_io, s, l, img): cmd = '{io} -C -c "r {s} {l}" -f {fmt} {f}'.format( io=qemu_io, s=s, l=l, fmt=img.image_format, f=img.image_filename ) process.system(cmd, ignore_status=False, shell=True) qemu_io = utils_misc.get_qemu_io_binary(params) qemu_img = utils_misc.get_qemu_img_binary(params) img_obj = qemu_storage.QemuImg(params.object_params(target_image), data_dir.get_data_dir(), target_image) nbd_img_obj = qemu_storage.QemuImg(params.object_params(nbd_image), None, nbd_image) max_len = int(params.get('qemu_io_max_len', 2147483136)) if bitmap is None: args = '-f %s %s' % (nbd_img_obj.image_format, nbd_img_obj.image_filename) state = True else: opts = qemu_storage.filename_to_file_opts( nbd_img_obj.image_filename) opt = params.get('dirty_bitmap_opt', 'x-dirty-bitmap') opts[opt] = 'qemu:dirty-bitmap:%s' % bitmap args = "'json:%s'" % json.dumps(opts) state = False img_obj.base_image_filename = nbd_img_obj.image_filename img_obj.base_format = nbd_img_obj.image_format img_obj.base_tag = nbd_img_obj.tag img_obj.rebase(img_obj.params) map_cmd = '{qemu_img} map --output=json {args}'.format( qemu_img=qemu_img, args=args) result = process.run(map_cmd, ignore_status=False, shell=True) for item in json.loads(result.stdout.decode().strip()): if item['data'] is not state: continue # qemu-io can only handle length less than 2147483136, # so here we need to split 'large length' into several parts start, length = item['start'], item['length'] while length > max_len: _qemu_io_read(qemu_io, start, max_len, img_obj) start, length = start+max_len, length-max_len else: if length > 0: _qemu_io_read(qemu_io, start, length, img_obj) img_obj.base_tag = 'null' img_obj.rebase(img_obj.params)
def run_test(qemu_src_dir): """ run QEMU I/O test suite :qemu_src_dir: path of qemu source code """ iotests_root = params.get("iotests_root", "tests/qemu-iotests") extra_options = params.get("qemu_io_extra_options", "") image_format = params.get("qemu_io_image_format") result_pattern = params.get("iotests_result_pattern") error_context.context("running qemu-iotests for image format %s" % image_format, logging.info) os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params) os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params) os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params) os.environ["QEMU_NBD_PROG"] = utils_misc.get_binary('qemu-nbd', params) os.chdir(os.path.join(qemu_src_dir, iotests_root)) cmd = './check' if extra_options: cmd += " %s" % extra_options cmd += " -%s" % image_format output = process.system_output(cmd, ignore_status=True, shell=True) match = re.search(result_pattern, output, re.I | re.M) if match: iotests_log_file = "qemu_iotests_%s.log" % image_format iotests_log_file = utils_misc.get_path(test.debugdir, iotests_log_file) with open(iotests_log_file, 'w+') as log: log.write(output) log.flush() msg = "Total test %s cases, %s failed" raise exceptions.TestFail(msg % (match.group(2), match.group(1)))
def get_image_size(self, image_file): qemu_img = utils_misc.get_qemu_img_binary(self.params) cmd = "%s info %s" % (qemu_img, image_file) info = utils.system_output(cmd) size = re.findall("(\d+) bytes", info) if size: return int(size[0]) return 0
def convert_data_image_with_bitmaps(self): # TODO: bitmap option is not supported by qemu_storage.convert, # so run qemu-img command explictly to convert an qcow2 image to # the target local qcow2 image cmd = '{qemu_img} convert -f {fmt} -O {ofmt} --bitmaps {s} {t}'.format( qemu_img=get_qemu_img_binary(self.params), fmt=self._src_image.image_format, ofmt=self._target_image.image_format, s=self._src_image.image_filename, t=self._target_image.image_filename) process.system(cmd, ignore_status=False, shell=True)
def convert_image_with_bitmaps(src_fmt, tar_fmt, src_name, tar_name): qemu_img = utils_misc.get_qemu_img_binary(params) convert_cmd = params["convert_cmd"] % (qemu_img, src_fmt, tar_fmt, src_name, tar_name) try: process.system(convert_cmd, ignore_status=False, shell=True) except process.CmdError as e: if "Cannot copy inconsistent bitmap" in str(e): convert_cmd += " --skip-broken-bitmaps" process.system(convert_cmd, ignore_status=False, shell=True) else: test.fail("Can convert image with inconsistent bitmap included")
def check_bitmaps_from_export(self): qemu_img = get_qemu_img_binary(self.params) opts = filename_to_file_opts(self._nbd_image_obj.image_filename) for bm in self._bitmaps: opts[self.params['dirty_bitmap_opt']] = 'qemu:dirty-bitmap:%s' % bm args = "'json:%s'" % json.dumps(opts) map_cmd = '{qemu_img} map --output=human {args}'.format( qemu_img=qemu_img, args=args) result = process.run(map_cmd, ignore_status=False, shell=True) if self._nbd_image_obj.image_filename not in result.stdout_text: self.test.fail('Failed to get bitmap info.')
def __init__(self, params, root_dir, tag): """ Init the default value for image object. :param params: Dictionary containing the test parameters. :param root_dir: Base directory for relative filenames. :param tag: Image tag defined in parameter images """ storage.QemuImg.__init__(self, params, root_dir, tag) self.image_cmd = utils_misc.get_qemu_img_binary(params) q_result = process.run(self.image_cmd + ' -h', ignore_status=True, shell=True, verbose=False) self.help_text = results_stdout_52lts(q_result) self.cap_force_share = '-U' in self.help_text
def file_exists(params, filename): """ Check whether the NVMe image file exists. :param params: A dict containing image parameters. :type params: dict :param filename: The NVMe image filename. :type filename: str :return: True if the NVMe image file exists, else False :rtype: bool """ cmd = "%s info %s" % (utils_misc.get_qemu_img_binary(params), filename) o = process.run(cmd, 60, False, True).stdout_text.strip() return params.get('image_format') in o
def get_backingfile(self, method="monitor"): """ return backingfile of the device, if not return None; """ if method == "monitor": return self.vm.monitor.get_backingfile(self.device) qemu_img = utils_misc.get_qemu_img_binary(self.params) cmd = "%s info %s " % (qemu_img, self.get_image_file()) info = utils.system_output(cmd) try: matched = re.search(r"backing file: +(.*)", info, re.M) return matched.group(1) except AttributeError: logging.warn("No backingfile found, cmd output: %s" % info)
def __init__(self, test, params): self.__dict__ = self.__shared_state self.tmpdir = test.tmpdir self.qemu_img_binary = utils_misc.get_qemu_img_binary(params) self.raw_files = ["stg1.raw", "stg2.raw"] self.raw_files = list(map(lambda f: os.path.join(self.tmpdir, f), self.raw_files)) # 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", "vg_kvm_test_qemu_io") self.lvtest_name = params.get("lvtest_name", "lv_kvm_test_qemu_io") self.lvtest_device = "/dev/%s/%s" % ( self.vgtest_name, self.lvtest_name) try: getattr(self, 'loopback') except AttributeError: self.loopback = []
def clean(self): super(DriveMirror, self).clean() params = self.parser_test_args() if params.get("image_type") == "iscsi": params["host_setup_flag"] = int(params["host_setup_flag"]) qemu_img = utils_misc.get_qemu_img_binary(self.params) # Reformat it to avoid impact other test cmd = "%s create -f %s %s %s" % (qemu_img, params["image_format"], self.target_image, params["image_size"]) utils.system(cmd) image = qemu_storage.Iscsidev(params, self.data_dir, params["target_image"]) image.cleanup() elif params.get("image_type") == "nfs": image = nfs.Nfs(params) image.cleanup()
def check_info_from_export_bitmaps(self): qemu_img = utils_misc.get_qemu_img_binary(self.params) for i, nbd_img in enumerate(self.nbd_images): opts = qemu_storage.filename_to_file_opts(nbd_img.image_filename) opts[self.params[ 'dirty_bitmap_opt']] = 'qemu:dirty-bitmap:%s' % self.bitmaps[i] args = "'json:%s'" % json.dumps(opts) map_cmd = '{qemu_img} map --output=human {args}'.format( qemu_img=qemu_img, args=args) result = process.run(map_cmd, ignore_status=True, shell=True) if result.exit_status != 0: self.test.fail('Failed to run map command: %s' % result.stderr.decode()) if nbd_img.image_filename not in result.stdout_text: self.test.fail('Failed to get bitmap info.')
def __init__(self, test, params): self.__dict__ = self.__shared_state self.tmpdir = test.tmpdir self.qemu_img_binary = utils_misc.get_qemu_img_binary(params) self.raw_files = ["stg1.raw", "stg2.raw"] self.raw_files = list( map(lambda f: os.path.join(self.tmpdir, f), self.raw_files)) # 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", "vg_kvm_test_qemu_io") self.lvtest_name = params.get("lvtest_name", "lv_kvm_test_qemu_io") self.lvtest_device = "/dev/%s/%s" % (self.vgtest_name, self.lvtest_name) try: getattr(self, 'loopback') except AttributeError: self.loopback = []
def run(test, params, env): """ Fetch from git and run qemu-iotests using the qemu binaries under test. 1) Fetch qemu-io from git 3) Run test for the file format detected 4) Report any errors found to test :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ # First, let's get qemu-io std = "http://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git" uri = params.get("qemu_io_uri", std) branch = params.get("qemu_io_branch", 'master') lbranch = params.get("qemu_io_lbranch", 'master') commit = params.get("qemu_io_commit", None) base_uri = params.get("qemu_io_base_uri", None) iotests_dir = params.get("qemu_iotests_dir", "tests/qemu-iotests") destination_dir = os.path.join(test.workdir, "qemu_io_tests") git.get_repo(uri=uri, branch=branch, lbranch=lbranch, commit=commit, destination_dir=destination_dir, base_uri=base_uri) # Then, set the qemu paths for the use of the testsuite os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params) os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params) os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params) # qemu-iotests has merged into tests/qemu_iotests folder os.chdir(os.path.join(destination_dir, iotests_dir)) image_format = params["qemu_io_image_format"] extra_options = params.get("qemu_io_extra_options", "") cmd = './check' if extra_options: cmd += extra_options error_context.context("running qemu-iotests for image format %s" % image_format) process.system("%s -%s" % (cmd, image_format), shell=True)
def get_backingfile(self, method="monitor"): """ return backingfile of the device, if not return None; """ backing_file = None if method == "monitor": backing_file = self.vm.monitor.get_backingfile(self.device) else: cmd = utils_misc.get_qemu_img_binary(self.params) image_file = self.get_image_file() cmd += " info %s " % image_file info = utils.system_output(cmd) matched = re.search(r"backing file: +(.*)", info, re.M) if matched: backing_file = matched.group(1) if backing_file: backing_file = os.path.abspath(backing_file) return backing_file
def __init__(self, test, params, env, tag): """ Init the default values for live backup object. :param test: Kvm test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. :param tag: Image tag defined in parameter images """ super(LiveBackup, self).__init__(test, params, env, tag) self.image_chain = self.params.get("image_chain").split() self.image_cmd = utils_misc.get_qemu_img_binary(params) self.source_image = self.params.get("source_image") self.speed = int(self.params.get("speed", 0)) self.bitmap_name = "bitmap0" self.backup_index = 1 self.backup_format = self.params.get("backup_format") self.generate_backup_params()
def clean(self): super(DriveMirror, self).clean() params = self.parser_test_args() if params.get("image_type") == "iscsi": params["host_setup_flag"] = int(params["host_setup_flag"]) qemu_img = utils_misc.get_qemu_img_binary(self.params) # Reformat it to avoid impact other test cmd = "%s create -f %s %s %s" % (qemu_img, params["image_format"], self.target_image, params["image_size"]) process.system(cmd) image = qemu_storage.Iscsidev(params, self.data_dir, params["target_image"]) image.cleanup() elif params.get("image_type") == "nfs": image = nfs.Nfs(params) image.cleanup()
def get_image_size(self, image_file): try: qemu_img = utils_misc.get_qemu_img_binary(self.params) cmd = "%s info %s" % (qemu_img, image_file) logging.info("Try to get image size via qemu-img info") info = process.system_output(cmd) size = int(re.findall(r"(\d+) bytes", info)[0]) except process.CmdError: logging.info("qemu-img info failed(it happens because later qemu" " distributions prevent it access a running image.)." " Now get image size via qmp interface 'query-block'") blocks_info = self.vm.monitor.info("block") for block in blocks_info: info = block["inserted"] if image_file == info["file"]: size = info["image"]["virtual-size"] if size: return size return 0
def check_allocation_depth_from_export(self, zero, data): """ check allocation depth from output of qemu-img map local(base image): zero: false, data: false backing(snapshot): zero: true, data: true """ opts = filename_to_file_opts(self._nbd_image_obj.image_filename) opts[self.params['dirty_bitmap_opt']] = 'qemu:allocation-depth' map_cmd = '{qemu_img} map --output=json {args}'.format( qemu_img=get_qemu_img_binary(self.params), args="'json:%s'" % json.dumps(opts)) result = process.run(map_cmd, ignore_status=False, shell=True) for item in json.loads(result.stdout.decode().strip()): if item['zero'] is zero and item['data'] is data: break else: self.test.fail('Failed to get "zero": %s, "data": %s' % (zero, data))
def get_image_size(self, image_file): try: qemu_img = utils_misc.get_qemu_img_binary(self.params) cmd = "%s info %s" % (qemu_img, image_file) logging.info("Try to get image size via qemu-img info") info = process.system_output(cmd) size = int(re.findall("(\d+) bytes", info)[0]) except process.CmdError: logging.info("qemu-img info failed(it happens because later qemu" " distributions prevent it access a running image.)." " Now get image size via qmp interface 'query-block'") blocks_info = self.vm.monitor.info("block") for block in blocks_info: info = block["inserted"] if image_file == info["file"]: size = info["image"]["virtual-size"] if size: return size return 0
def __init__(self, test, params): self.__dict__ = self.__shared_state root_dir = test.bindir self.tmpdir = test.tmpdir self.qemu_img_binary = utils_misc.get_qemu_img_binary(self.params) 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["vgtest_name"] self.lvtest_name = params["lvtest_name"] self.lvtest_device = "/dev/%s/%s" % ( self.vgtest_name, self.lvtest_name) image_dir = os.path.join(data_dir.get_data_dir(), os.path.dirname(params["image_name"])) self.qcow_file_path = os.path.join(image_dir, 'enospc.qcow2') try: getattr(self, 'loopback') except AttributeError: self.loopback = ''
def run_qemu_iotests(test, params, env): """ Fetch from git and run qemu-iotests using the qemu binaries under test. 1) Fetch qemu-io from git 3) Run test for the file format detected 4) Report any errors found to autotest @param test: QEMU test object. @param params: Dictionary with the test parameters. @param env: Dictionary with test environment. """ # First, let's get qemu-io std = "git://git.kernel.org/pub/scm/linux/kernel/git/hch/qemu-iotests.git" uri = params.get("qemu_io_uri", std) branch = params.get("qemu_io_branch", 'master') lbranch = params.get("qemu_io_lbranch", 'master') commit = params.get("qemu_io_commit", None) base_uri = params.get("qemu_io_base_uri", None) destination_dir = os.path.join(test.srcdir, "qemu_io_tests") git.get_repo(uri=uri, branch=branch, lbranch=lbranch, commit=commit, destination_dir=destination_dir, base_uri=base_uri) # Then, set the qemu paths for the use of the testsuite os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params) os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params) os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params) os.chdir(destination_dir) image_format = params["qemu_io_image_format"] extra_options = params.get("qemu_io_extra_options", "") cmd = './check' if extra_options: cmd += extra_options error.context("running qemu-iotests for image format %s" % image_format) utils.system("%s -%s" % (cmd, image_format))
def backup_img_chain(image_file): """ Backup whole image in a image chain; """ mount_point = tempfile.mkdtemp(dir=test.resultsdir) qemu_img = utils_misc.get_qemu_img_binary(params) if enable_gluster: g_uri = gluster.create_gluster_uri(params) gluster.glusterfs_mount(g_uri, mount_point) image_name = os.path.basename(image_file) image_file = os.path.join(mount_point, image_name) logging.warn("backup %s to %s" % (image_file, test.resultsdir)) shutil.copy(image_file, test.resultsdir) backing_file = _info(qemu_img, image_file, "backing file", None) if backing_file: backup_img_chain(backing_file) elif enable_gluster: utils_misc.umount(g_uri, mount_point, "glusterfs", False, "fuse.glusterfs") shutil.rmtree(mount_point) return None
def copyif(self, nbd_img_obj, img_obj, bitmap=None): qemu_img = utils_misc.get_qemu_img_binary(self.params) qemu_io = utils_misc.get_qemu_io_binary(self.params) args = '' if bitmap is None: args = '-f %s %s' % (nbd_img_obj.image_format, nbd_img_obj.image_filename) else: opts = qemu_storage.filename_to_file_opts( nbd_img_obj.image_filename) opts[self. params['dirty_bitmap_opt']] = 'qemu:dirty-bitmap:%s' % bitmap args = "'json:%s'" % json.dumps(opts) img_obj.base_image_filename = nbd_img_obj.image_filename img_obj.base_format = nbd_img_obj.image_format img_obj.base_tag = nbd_img_obj.tag img_obj.rebase(img_obj.params) map_cmd = '{qemu_img} map --output=json {args}'.format( qemu_img=qemu_img, args=args) result = process.run(map_cmd, ignore_status=True, shell=True) if result.exit_status != 0: self.test.fail('Failed to run map command: %s' % result.stderr.decode()) for item in json.loads(result.stdout.decode().strip()): io_cmd = '{io} -C -c "read {s} {l}" -f {fmt} {fn}'.format( io=qemu_io, s=item['start'], l=item['length'], fmt=img_obj.image_format, fn=img_obj.image_filename) result = process.run(io_cmd, ignore_status=True, shell=True) if result.exit_status != 0: self.test.fail('Failed to run qemu-io command: %s' % result.stderr.decode()) img_obj.base_tag = 'null' img_obj.rebase(img_obj.params)
def run_qemu_iotests(test, params, env): """ Fetch from git and run qemu-iotests using the qemu binaries under test. 1) Fetch qemu-io from git 3) Run test for the file format detected 4) Report any errors found to autotest :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ # First, let's get qemu-io std = "http://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git" uri = params.get("qemu_io_uri", std) branch = params.get("qemu_io_branch", 'master') lbranch = params.get("qemu_io_lbranch", 'master') commit = params.get("qemu_io_commit", None) base_uri = params.get("qemu_io_base_uri", None) iotests_dir = params.get("qemu_iotests_dir", "tests/qemu-iotests") destination_dir = os.path.join(test.srcdir, "qemu_io_tests") git.get_repo(uri=uri, branch=branch, lbranch=lbranch, commit=commit, destination_dir=destination_dir, base_uri=base_uri) # Then, set the qemu paths for the use of the testsuite os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params) os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params) os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params) # qemu-iotests has merged into tests/qemu_iotests folder os.chdir(os.path.join(destination_dir, iotests_dir)) image_format = params["qemu_io_image_format"] extra_options = params.get("qemu_io_extra_options", "") cmd = './check' if extra_options: cmd += extra_options error.context("running qemu-iotests for image format %s" % image_format) utils.system("%s -%s" % (cmd, image_format))
def run_qemu_img(test, params, env): """ 'qemu-img' functions test: 1) Judge what subcommand is going to be tested 2) Run subcommand test @param test: QEMU test object @param params: Dictionary with the test parameters @param env: Dictionary with test environment. """ qemu_img_binary = utils_misc.get_qemu_img_binary(params) cmd = qemu_img_binary if not os.path.exists(cmd): raise error.TestError("Binary of 'qemu-img' not found") image_format = params["image_format"] image_size = params.get("image_size", "10G") image_name = storage.get_image_filename(params, data_dir.get_data_dir()) def _check(cmd, img): """ Simple 'qemu-img check' function implementation. @param cmd: qemu-img base command. @param img: image to be checked """ cmd += " check %s" % img error.context("Checking image '%s' by command '%s'" % (img, cmd), logging.info) try: output = utils.system_output(cmd, verbose=False) except error.CmdError, err: if "does not support checks" in str(err): return (True, "") else: return (False, str(err)) return (True, output)
def run(test, params, env): """ 'qemu-img' functions test: 1) Judge what subcommand is going to be tested 2) Run subcommand test :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ qemu_img_binary = utils_misc.get_qemu_img_binary(params) cmd = qemu_img_binary if not os.path.exists(cmd): raise error.TestError("Binary of 'qemu-img' not found") image_format = params["image_format"] image_size = params.get("image_size", "10G") image_name = storage.get_image_filename(params, data_dir.get_data_dir()) def _check(cmd, img): """ Simple 'qemu-img check' function implementation. :param cmd: qemu-img base command. :param img: image to be checked """ cmd += " check %s" % img error.context("Checking image '%s' by command '%s'" % (img, cmd), logging.info) try: output = utils.system_output(cmd, verbose=False) except error.CmdError, err: if "does not support checks" in str(err): return (True, "") else: return (False, str(err)) return (True, output)
def run(test, params, env): """ block_stream_without_backingfile test: 1). bootup guest 2). create snapshots chian(base->sn1->sn2), verify backingfile should sn1 3). merge sn1 to sn2 (sn1->sn2) aka block stream with special base, after job done, then check backingfile is base and sn1 not opening by qemu 4). merge base to sn2(base->sn2) after this step sn2 should no backingfile and sn1 and base should not opening by qemu 5). reboot guest vierfy it works correctly 6). verify not backingfile with qemu-img command too; :param test: Qemu test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) alive_check_cmd = params.get("alive_check_cmd", "dir") image_file = storage.get_image_filename(params, data_dir.get_data_dir()) image_dir = os.path.dirname(image_file) qemu_img = utils_misc.get_qemu_img_binary(params) speed = int(params.get("limited_speed", 0)) wait_timeout = int(params.get("wait_timeout", 3600)) def wait_job_done(timeout=3600): """ Wait for job on the device done, raise TestFail exception if timeout; """ if utils_misc.wait_for(lambda: not vm.monitor.query_block_job(device_id), timeout, first=0.2, step=2.0, text="Wait for canceling block job") is None: raise error.TestFail("Wait job finish timeout in %ss" % timeout) def verify_backingfile(expect_backingfile): """ Got backingfile from monitor then verfiy it expect_backingfile, if not raise TestFail exception; """ backing_file = vm.monitor.get_backingfile(device_id) if backing_file != expect_backingfile: raise error.TestFail("Unexpect backingfile(%s)" % backing_file) def get_openingfiles(): """ Return files which opening by qemu process; """ pid = vm.get_pid() cmd = params.get("snapshot_check_cmd") % pid return set(utils.system_output(cmd, ignore_status=True).splitlines()) snapshots = map(lambda x: os.path.join(image_dir, x), ["sn1", "sn2"]) try: error.context("Create snapshots-chain(base->sn1->sn2)", logging.info) for index, snapshot in enumerate(snapshots): base_file = index and snapshots[index - 1] or image_file device_id = vm.live_snapshot(base_file, snapshot) if not device_id: raise error.TestFail("Fail to create %s" % snapshot) error.context("Check backing-file of sn2", logging.info) verify_backingfile(snapshots[0]) error.context("Merge sn1 to sn2", logging.info) vm.monitor.block_stream(device_id, base=image_file, speed=speed) wait_job_done(wait_timeout) error.context("Check backing-file of sn2", logging.info) verify_backingfile(image_file) error.context("Check sn1 is not opening by qemu process", logging.info) if snapshots[0] in get_openingfiles(): raise error.TestFail("sn1 (%s) is opening by qemu" % snapshots[0]) error.context("Merge base to sn2", logging.info) vm.monitor.block_stream(device_id) wait_job_done(wait_timeout) error.context("Check backing-file of sn2", logging.info) verify_backingfile(None) error.context("check sn1 and base are not opening by qemu process", logging.info) if set([snapshots[0], image_file]).issubset(get_openingfiles()): raise error.TestFail("%s is opening by qemu" % set([snapshots[0], image_file])) error.context("Check backing-file of sn2 by qemu-img", logging.info) cmd = "%s info %s" % (qemu_img, snapshots[1]) if re.search("backing file", utils.system_output(cmd, ignore_status=True)): raise error.TestFail("should no backing-file in this step") error.context("Reboot VM to check it works fine", logging.info) session = vm.reboot(session=session, timeout=timeout) session.cmd(alive_check_cmd) finally: map(lambda x: utils.system("rm -rf %s" % x), snapshots)
def add_persistent_bitmap_to_image(image, bitmap): """Add persistent bitmap to image""" qemu_img = utils_misc.get_qemu_img_binary(params) add_bitmap_cmd = "%s bitmap %s --add %s" % (qemu_img, image, bitmap) process.run(add_bitmap_cmd, ignore_status=False, shell=True)
def run_boot_savevm(test, params, env): """ libvirt boot savevm test: 1) Start guest booting 2) Record origin informations of snapshot list for floppy(optional). 3) Periodically savevm/loadvm while guest booting 4) Stop test when able to login, or fail after timeout seconds. 5) Check snapshot list for floppy and compare with the origin one(optional). @param test: test object @param params: Dictionary with the test parameters @param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) if params.get("with_floppy") == "yes": floppy_name = params.get("floppies", "fl") floppy_params = { "image_format": params.get("floppy_format", "qcow2"), "image_size": params.get("floppy_size", "1.4M"), "image_name": params.get("%s_name" % floppy_name, "images/test"), "vm_type": params.get("vm_type"), "qemu_img_binary": utils_misc.get_qemu_img_binary(params) } floppy = qemu_storage.QemuImg(floppy_params, data_dir.get_data_dir(), floppy_name) floppy.create(floppy_params) floppy_orig_info = floppy.snapshot_list() vm.create(params=params) vm.verify_alive() # This shouldn't require logging in to guest savevm_delay = float(params["savevm_delay"]) savevm_login_delay = float(params["savevm_login_delay"]) savevm_login_timeout = float(params["savevm_timeout"]) savevm_statedir = params.get("savevm_statedir", tempfile.gettempdir()) fd, savevm_statefile = tempfile.mkstemp(suffix='.img', prefix=vm.name + '-', dir=savevm_statedir) os.close(fd) # save_to_file doesn't need the file open start_time = time.time() cycles = 0 successful_login = False while (time.time() - start_time) < savevm_login_timeout: logging.info("Save/Restore cycle %d", cycles + 1) time.sleep(savevm_delay) vm.pause() if params['save_method'] == 'save_to_file': vm.save_to_file(savevm_statefile) # Re-use same filename vm.restore_from_file(savevm_statefile) else: vm.savevm("1") vm.loadvm("1") vm.resume() # doesn't matter if already running or not vm.verify_kernel_crash() # just in case try: vm.wait_for_login(timeout=savevm_login_delay) successful_login = True # not set if timeout expires os.unlink(savevm_statefile) # don't let these clutter disk break except: pass # loop until successful login or time runs out cycles += 1 time_elapsed = int(time.time() - start_time) info = "after %s s, %d load/save cycles" % (time_elapsed, cycles + 1) if not successful_login: raise error.TestFail("Can't log on '%s' %s" % (vm.name, info)) else: logging.info("Test ended %s", info) if params.get("with_floppy") == "yes": vm.destroy() floppy_info = floppy.snapshot_list() if floppy_info == floppy_orig_info: raise error.TestFail("savevm didn't create snapshot in floppy." " original snapshot list is: %s" " now snapshot list is: %s" % (floppy_orig_info, floppy_info))
def run(test, params, env): """ 'qemu-img' functions test: 1) Judge what subcommand is going to be tested 2) Run subcommand test :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ qemu_img_binary = utils_misc.get_qemu_img_binary(params) cmd = qemu_img_binary if not os.path.exists(cmd): raise error.TestError("Binary of 'qemu-img' not found") image_format = params["image_format"] image_size = params.get("image_size", "10G") enable_gluster = params.get("enable_gluster", "no") == "yes" image_name = storage.get_image_filename(params, data_dir.get_data_dir()) def remove(path): try: os.remove(path) except OSError: pass def _get_image_filename(img_name, enable_gluster=False, img_fmt=None): """ Generate an image path. :param image_name: Force name of image. :param enable_gluster: Enable gluster or not. :param image_format: Format for image. """ if enable_gluster: gluster_uri = gluster.create_gluster_uri(params) image_filename = "%s%s" % (gluster_uri, img_name) if img_fmt: image_filename += ".%s" % img_fmt else: if img_fmt: img_name = "%s.%s" % (img_name, img_fmt) image_filename = utils_misc.get_path(data_dir.get_data_dir(), img_name) return image_filename def _check(cmd, img): """ Simple 'qemu-img check' function implementation. :param cmd: qemu-img base command. :param img: image to be checked """ cmd += " check %s" % img error.context("Checking image '%s' by command '%s'" % (img, cmd), logging.info) try: output = utils.system_output(cmd, verbose=False) except error.CmdError, err: if "does not support checks" in str(err): return (True, "") else: return (False, str(err)) return (True, output)
def __init__(self, test, params, vm): """ Sets class attributes from test parameters. :param test: QEMU test object. :param params: Dictionary with test parameters. """ root_dir = data_dir.get_data_dir() self.deps_dir = os.path.join(test.virtdir, 'deps') self.unattended_dir = os.path.join(test.virtdir, 'unattended') self.results_dir = test.debugdir self.params = params self.attributes = ['kernel_args', 'finish_program', 'cdrom_cd1', 'unattended_file', 'medium', 'url', 'kernel', 'initrd', 'nfs_server', 'nfs_dir', 'install_virtio', 'floppy_name', 'cdrom_unattended', 'boot_path', 'kernel_params', 'extra_params', 'qemu_img_binary', 'cdkey', 'finish_program', 'vm_type', 'process_check', 'vfd_size', 'cdrom_mount_point', 'floppy_mount_point', 'cdrom_virtio', 'virtio_floppy', 're_driver_match', 're_hardware_id', 'driver_in_floppy'] for a in self.attributes: setattr(self, a, params.get(a, '')) # Will setup the virtio attributes v_attributes = ['virtio_floppy', 'virtio_scsi_path', 'virtio_storage_path', 'virtio_network_path', 'virtio_oemsetup_id', 'virtio_network_installer_path', 'virtio_balloon_installer_path', 'virtio_qxl_installer_path'] for va in v_attributes: setattr(self, va, params.get(va, '')) self.tmpdir = test.tmpdir self.qemu_img_binary = utils_misc.get_qemu_img_binary(params) if getattr(self, 'unattended_file'): self.unattended_file = os.path.join(test.virtdir, self.unattended_file) if getattr(self, 'finish_program'): self.finish_program = os.path.join(test.virtdir, self.finish_program) 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 getattr(self, 'cdrom_unattended'): self.cdrom_unattended = os.path.join(root_dir, self.cdrom_unattended) if getattr(self, 'virtio_floppy'): self.virtio_floppy = os.path.join(root_dir, self.virtio_floppy) if getattr(self, 'cdrom_virtio'): self.cdrom_virtio = os.path.join(root_dir, self.cdrom_virtio) if getattr(self, 'kernel'): self.kernel = os.path.join(root_dir, self.kernel) if getattr(self, 'initrd'): self.initrd = os.path.join(root_dir, self.initrd) if self.medium == 'nfs': self.nfs_mount = tempfile.mkdtemp(prefix='nfs_', dir=self.tmpdir) setattr(self, 'floppy', self.floppy_name) 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) # Content server params # lookup host ip address for first nic by interface name try: auto_ip = utils_net.get_ip_address_by_interface( vm.virtnet[0].netdst) except utils_net.NetError: auto_ip = None self.url_auto_content_ip = params.get('url_auto_ip', auto_ip) self.url_auto_content_port = None # Kickstart server params # use the same IP as url_auto_content_ip, but a different port self.unattended_server_port = None # Embedded Syslog Server self.syslog_server_enabled = params.get('syslog_server_enabled', 'no') self.syslog_server_ip = params.get('syslog_server_ip', auto_ip) self.syslog_server_port = int(params.get('syslog_server_port', 5140)) self.syslog_server_tcp = params.get('syslog_server_proto', 'tcp') == 'tcp' self.vm = vm
def run(test, params, env): """ block_stream_without_backingfile test: 1). bootup guest 2). create snapshots chian(base->sn1->sn2), verify backingfile should sn1 3). merge sn1 to sn2 (sn1->sn2) aka block stream with special base, after job done, then check backingfile is base and sn1 not opening by qemu 4). merge base to sn2(base->sn2) after this step sn2 should no backingfile and sn1 and base should not opening by qemu 5). reboot guest vierfy it works correctly 6). verify not backingfile with qemu-img command too; :param test: Qemu test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) alive_check_cmd = params.get("alive_check_cmd", "dir") image_file = storage.get_image_filename(params, data_dir.get_data_dir()) image_dir = os.path.dirname(image_file) qemu_img = utils_misc.get_qemu_img_binary(params) speed = int(params.get("limited_speed", 0)) wait_timeout = int(params.get("wait_timeout", 3600)) def wait_job_done(timeout=3600): """ Wait for job on the device done, raise TestFail exception if timeout; """ if utils_misc.wait_for(lambda: not vm.monitor.query_block_job(device_id), timeout, first=0.2, step=2.0, text="Wait for canceling block job") is None: raise error.TestFail("Wait job finish timeout in %ss" % timeout) def verify_backingfile(expect_backingfile): """ Got backingfile from monitor then verify it with expect_backingfile, if not raise TestFail exception; """ backing_file = vm.monitor.get_backingfile(device_id) if backing_file != expect_backingfile: raise error.TestFail("Unexpect backingfile(%s)" % backing_file) def get_openingfiles(): """ Return files which opening by qemu process; """ pid = vm.get_pid() cmd = params.get("snapshot_check_cmd") % pid return set(utils.system_output(cmd, ignore_status=True).splitlines()) snapshots = map(lambda x: os.path.join(image_dir, x), ["sn1", "sn2"]) try: error.context("Create snapshots-chain(base->sn1->sn2)", logging.info) for index, snapshot in enumerate(snapshots): base_file = index and snapshots[index - 1] or image_file device_id = vm.live_snapshot(base_file, snapshot) if not device_id: raise error.TestFail("Fail to create %s" % snapshot) error.context("Check backing-file of sn2", logging.info) verify_backingfile(snapshots[0]) error.context("Merge sn1 to sn2", logging.info) vm.monitor.block_stream(device_id, base=image_file, speed=speed) wait_job_done(wait_timeout) error.context("Check backing-file of sn2", logging.info) verify_backingfile(image_file) error.context("Check sn1 is not opening by qemu process", logging.info) if snapshots[0] in get_openingfiles(): raise error.TestFail("sn1 (%s) is opening by qemu" % snapshots[0]) error.context("Merge base to sn2", logging.info) vm.monitor.block_stream(device_id) wait_job_done(wait_timeout) error.context("Check backing-file of sn2", logging.info) verify_backingfile(None) error.context("check sn1 and base are not opening by qemu process", logging.info) if set([snapshots[0], image_file]).issubset(get_openingfiles()): raise error.TestFail("%s is opening by qemu" % set([snapshots[0], image_file])) error.context("Check backing-file of sn2 by qemu-img", logging.info) cmd = "%s info %s" % (qemu_img, snapshots[1]) if re.search("backing file", utils.system_output(cmd, ignore_status=True)): raise error.TestFail("should no backing-file in this step") error.context("Reboot VM to check it works fine", logging.info) session = vm.reboot(session=session, timeout=timeout) session.cmd(alive_check_cmd) finally: map(lambda x: utils.system("rm -rf %s" % x), snapshots)
def run(test, params, env): """ 'qemu-img' functions test: 1) Judge what subcommand is going to be tested 2) Run subcommand test :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ qemu_img_binary = utils_misc.get_qemu_img_binary(params) cmd = qemu_img_binary if not os.path.exists(cmd): test.error("Binary of 'qemu-img' not found") image_format = params["image_format"] image_size = params.get("image_size", "10G") enable_gluster = params.get("enable_gluster", "no") == "yes" image_name = storage.get_image_filename(params, data_dir.get_data_dir()) def remove(path): try: os.remove(path) except OSError: pass def _get_image_filename(img_name, enable_gluster=False, img_fmt=None): """ Generate an image path. :param image_name: Force name of image. :param enable_gluster: Enable gluster or not. :param image_format: Format for image. """ if enable_gluster: gluster_uri = gluster.create_gluster_uri(params) image_filename = "%s%s" % (gluster_uri, img_name) if img_fmt: image_filename += ".%s" % img_fmt else: if img_fmt: img_name = "%s.%s" % (img_name, img_fmt) image_filename = utils_misc.get_path(data_dir.get_data_dir(), img_name) return image_filename def _check(cmd, img): """ Simple 'qemu-img check' function implementation. :param cmd: qemu-img base command. :param img: image to be checked """ cmd += " check %s" % img error_context.context("Checking image '%s' by command '%s'" % (img, cmd), logging.info) try: output = process.system_output(cmd, verbose=False).decode() except process.CmdError as err: result_stderr = err.result.stderr.decode() if "does not support checks" in result_stderr: return (True, "") else: return (False, result_stderr) return (True, output) def check_test(cmd): """ Subcommand 'qemu-img check' test. This tests will 'dd' to create a specified size file, and check it. Then convert it to supported image_format in each loop and check again. :param cmd: qemu-img base command. """ test_image = _get_image_filename(params["image_name_dd"], enable_gluster) create_image_cmd = params["create_image_cmd"] create_image_cmd = create_image_cmd % test_image msg = " Create image %s by command %s" % (test_image, create_image_cmd) error_context.context(msg, logging.info) process.system(create_image_cmd, verbose=False, shell=True) status, output = _check(cmd, test_image) if not status: test.fail("Check image '%s' failed with error: %s" % (test_image, output)) for fmt in params["supported_image_formats"].split(): output_image = test_image + ".%s" % fmt _convert(cmd, fmt, test_image, output_image) status, output = _check(cmd, output_image) if not status: test.fail("Check image '%s' got error: %s" % (output_image, output)) remove(output_image) remove(test_image) def _create(cmd, img_name, fmt, img_size=None, base_img=None, base_img_fmt=None, encrypted="no", preallocated="off", cluster_size=None): """ Simple wrapper of 'qemu-img create' :param cmd: qemu-img base command. :param img_name: name of the image file :param fmt: image format :param img_size: image size :param base_img: base image if create a snapshot image :param base_img_fmt: base image format if create a snapshot image :param encrypted: indicates whether the created image is encrypted :param preallocated: if preallocation when create image, allowed values: off, metadata. Default is "off" :param cluster_size: the cluster size for the image """ cmd += " create" if encrypted == "yes": cmd += " -e" if base_img: cmd += " -b %s" % base_img if base_img_fmt: cmd += " -F %s" % base_img_fmt cmd += " -f %s" % fmt options = [] if preallocated != "off": options.append("preallocation=%s" % preallocated) if cluster_size is not None: options.append("cluster_size=%s" % cluster_size) if options: cmd += " -o %s" % ",".join(options) cmd += " %s" % img_name if img_size: cmd += " %s" % img_size msg = "Creating image %s by command %s" % (img_name, cmd) error_context.context(msg, logging.info) process.system(cmd, verbose=False) status, out = _check(qemu_img_binary, img_name) if not status: test.fail("Check image '%s' got error: %s" % (img_name, out)) def create_test(cmd): """ Subcommand 'qemu-img create' test. :param cmd: qemu-img base command. """ image_large = params["image_name_large"] device = params.get("device") if not device: img = _get_image_filename(image_large, enable_gluster, image_format) else: img = device _create(cmd, img_name=img, fmt=image_format, img_size=params["image_size_large"], preallocated=params.get("preallocated", "off"), cluster_size=params.get("image_cluster_size")) remove(img) def send_signal(timeout=360): """ send signal "SIGUSR1" to qemu-img without the option -p to report progress """ logging.info("Send signal to qemu-img") end_time = time.time() + timeout while time.time() < end_time: time.sleep(1) pid = process.system_output("pidof qemu-img", ignore_status=True, verbose=False).decode().strip() if bool(pid): break try: os.kill(int(pid), signal.SIGUSR1) except Exception as error: logging.info("Failed to send signal to qemu-img") test.error(str(error)) def check_command_output(CmdResult): """ Check standard error or standard output of command : param CmdResult: a list of CmdResult objects """ logging.info("Check result of command") check_output = params.get("check_output", "exit_status") if not hasattr(CmdResult, check_output): test.error("Unknown check output '%s'" % check_output) output = getattr(CmdResult, check_output) if check_output == "exit_status" and output == 0: return None if check_output == "exit_status" and output != 0: err_msg = "Get nonzero exit status(%d) '%s'" test.fail(err_msg % (output, CmdResult.command)) pattern = params.get("command_result_pattern") if not re.findall(pattern, output.decode()): err_msg = "Fail to get expected result!" err_msg += "Output: %s, expected pattern: %s" % (output, pattern) test.fail(err_msg) def _convert(cmd, output_fmt, img_name, output_filename, fmt=None, compressed="no", encrypted="no"): """ Simple wrapper of 'qemu-img convert' function. :param cmd: qemu-img base command. :param output_fmt: the output format of converted image :param img_name: image name that to be converted :param output_filename: output image name that converted :param fmt: output image format :param compressed: whether output image is compressed :param encrypted: whether output image is encrypted """ cmd += " convert" if compressed == "yes": cmd += " -c" if encrypted == "yes": cmd += " -e" show_progress = params.get("show_progress", "") if show_progress == "on": cmd += " -p" if fmt: cmd += " -f %s" % fmt cmd += " -O %s" % output_fmt options = params.get("qemu_img_options") if options: options = options.split() cmd += " -o " for option in options: value = params.get(option) cmd += "%s=%s," % (option, value) cmd = cmd.rstrip(",") cmd += " %s %s" % (img_name, output_filename) msg = "Converting '%s' from format '%s'" % (img_name, fmt) msg += " to '%s'" % output_fmt error_context.context(msg, logging.info) if show_progress == "off": bg = utils_misc.InterruptedThread(send_signal) bg.start() check_command_output(process.run(cmd, ignore_status=True)) def convert_test(cmd): """ Subcommand 'qemu-img convert' test. :param cmd: qemu-img base command. """ dest_img_fmt = params["dest_image_format"] output_filename = "%s.converted_%s.%s" % (image_name, dest_img_fmt, dest_img_fmt) _convert(cmd, dest_img_fmt, image_name, output_filename, image_format, params["compressed"], params["encrypted"]) orig_img_name = params.get("image_name") img_name = "%s.%s.converted_%s" % (orig_img_name, image_format, dest_img_fmt) _boot(img_name, dest_img_fmt) if dest_img_fmt == "qcow2": status, output = _check(cmd, output_filename) if status: remove(output_filename) else: test.fail("Check image '%s' failed with error: %s" % (output_filename, output)) else: remove(output_filename) def _info(cmd, img, sub_info=None, fmt=None): """ Simple wrapper of 'qemu-img info'. :param cmd: qemu-img base command. :param img: image file :param sub_info: sub info, say 'backing file' :param fmt: image format """ cmd += " info" if fmt: cmd += " -f %s" % fmt cmd += " %s" % img try: output = process.system_output(cmd).decode() except process.CmdError as err: logging.error("Get info of image '%s' failed: %s", img, err.result.stderr.decode()) return None if not sub_info: return output sub_info += ": (.*)" matches = re.findall(sub_info, output) if "virtual size" in sub_info: p = re.compile(r'\.0*(G|K)$') return p.sub(r'\1', matches[0].split()[0]) if matches: return matches[0] return None def info_test(cmd): """ Subcommand 'qemu-img info' test. :param cmd: qemu-img base command. """ img_info = _info(cmd, image_name) logging.info("Info of image '%s':\n%s", image_name, img_info) if image_format not in img_info: test.fail("Got unexpected format of image '%s'" " in info test" % image_name) if not re.search(r'%s\s+bytes' % normalize_data_size( image_size, "B"), img_info): test.fail("Got unexpected size of image '%s'" " in info test" % image_name) def snapshot_test(cmd): """ Subcommand 'qemu-img snapshot' test. :param cmd: qemu-img base command. """ cmd += " snapshot" for i in range(2): crtcmd = cmd sn_name = "snapshot%d" % i crtcmd += " -c %s %s" % (sn_name, image_name) msg = "Created snapshot '%s' in '%s' by command %s" % (sn_name, image_name, crtcmd) error_context.context(msg, logging.info) cmd_result = process.run(crtcmd, verbose=False, ignore_status=True) status, output = cmd_result.exit_status, cmd_result.stdout.decode() if status != 0: test.fail("Create snapshot failed via command: %s;" "Output is: %s" % (crtcmd, output)) listcmd = cmd listcmd += " -l %s" % image_name cmd_result = process.run(listcmd, verbose=False, ignore_status=True) status, out = cmd_result.exit_status, cmd_result.stdout.decode() if not ("snapshot0" in out and "snapshot1" in out and status == 0): test.fail("Snapshot created failed or missed;" "snapshot list is: \n%s" % out) for i in range(2): sn_name = "snapshot%d" % i delcmd = cmd delcmd += " -d %s %s" % (sn_name, image_name) msg = "Delete snapshot '%s' by command %s" % (sn_name, delcmd) error_context.context(msg, logging.info) cmd_result = process.run(delcmd, verbose=False, ignore_status=True) status, output = cmd_result.exit_status, cmd_result.stdout.decode() if status != 0: test.fail("Delete snapshot '%s' failed: %s" % (sn_name, output)) def commit_test(cmd): """ Subcommand 'qemu-img commit' test. 1) Create a overlay file of the qemu harddisk specified by image_name. 2) Start a VM using the overlay file as its harddisk. 3) Touch a file "commit_testfile" in the overlay file, and shutdown the VM. 4) Commit the change to the backing harddisk by executing "qemu-img commit" command. 5) Start the VM using the backing harddisk. 6) Check if the file "commit_testfile" exists. :param cmd: qemu-img base command. """ logging.info("Commit testing started!") image_name = storage.get_image_filename(params, data_dir.get_data_dir()) pre_name = '.'.join(image_name.split('.')[:-1]) image_format = params.get("image_format", "qcow2") overlay_file_name = "%s_overlay.%s" % (pre_name, image_format) file_create_cmd = params.get("file_create_cmd", "touch /commit_testfile") file_info_cmd = params.get("file_info_cmd", "ls / | grep commit_testfile") file_exist_chk_cmd = params.get("file_exist_chk_cmd", "[ -e /commit_testfile ] && echo $?") file_del_cmd = params.get("file_del_cmd", "rm -f /commit_testfile") try: # Remove the existing overlay file if os.path.isfile(overlay_file_name): remove(overlay_file_name) # Create the new overlay file create_cmd = "%s create -b %s -f %s %s" % (cmd, image_name, image_format, overlay_file_name) msg = "Create overlay file by command: %s" % create_cmd error_context.context(msg, logging.info) try: process.system(create_cmd, verbose=False) except process.CmdError: test.fail("Could not create a overlay file!") logging.info("overlay file (%s) created!" % overlay_file_name) # Set the qemu harddisk to the overlay file logging.info( "Original image_name is: %s", params.get('image_name')) params['image_name'] = '.'.join(overlay_file_name.split('.')[:-1]) logging.info("Param image_name changed to: %s", params.get('image_name')) msg = "Start a new VM, using overlay file as its harddisk" error_context.context(msg, logging.info) vm_name = params['main_vm'] env_process.preprocess_vm(test, params, env, vm_name) vm = env.get_vm(vm_name) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) # Do some changes to the overlay_file harddisk try: output = session.cmd(file_create_cmd) logging.info("Output of %s: %s", file_create_cmd, output) output = session.cmd(file_info_cmd) logging.info("Output of %s: %s", file_info_cmd, output) except Exception as err: test.fail("Could not create commit_testfile in the " "overlay file %s" % err) vm.destroy() # Execute the commit command cmitcmd = "%s commit -f %s %s" % (cmd, image_format, overlay_file_name) error_context.context("Committing image by command %s" % cmitcmd, logging.info) try: process.system(cmitcmd, verbose=False) except process.CmdError: test.fail("Could not commit the overlay file") logging.info("overlay file (%s) committed!" % overlay_file_name) msg = "Start a new VM, using image_name as its harddisk" error_context.context(msg, logging.info) params['image_name'] = pre_name vm_name = params['main_vm'] env_process.preprocess_vm(test, params, env, vm_name) vm = env.get_vm(vm_name) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) try: output = session.cmd(file_exist_chk_cmd) logging.info("Output of %s: %s", file_exist_chk_cmd, output) session.cmd(file_del_cmd) except Exception: test.fail("Could not find commit_testfile after a commit") vm.destroy() finally: # Remove the overlay file if os.path.isfile(overlay_file_name): remove(overlay_file_name) def _rebase(cmd, img_name, base_img, backing_fmt, mode="unsafe"): """ Simple wrapper of 'qemu-img rebase'. :param cmd: qemu-img base command. :param img_name: image name to be rebased :param base_img: indicates the base image :param backing_fmt: the format of base image :param mode: rebase mode: safe mode, unsafe mode """ cmd += " rebase" show_progress = params.get("show_progress", "") if mode == "unsafe": cmd += " -u" if show_progress == "on": cmd += " -p" cmd += " -b %s -F %s %s" % (base_img, backing_fmt, img_name) msg = "Trying to rebase '%s' to '%s' by command %s" % (img_name, base_img, cmd) error_context.context(msg, logging.info) if show_progress == "off": bg = utils_misc.InterruptedThread(send_signal) bg.start() check_command_output(process.run(cmd)) def rebase_test(cmd): """ Subcommand 'qemu-img rebase' test Change the backing file of a snapshot image in "unsafe mode": Assume the previous backing file had missed and we just have to change reference of snapshot to new one. After change the backing file of a snapshot image in unsafe mode, the snapshot should work still. :param cmd: qemu-img base command. """ if 'rebase' not in process.system_output(cmd + ' --help', ignore_status=True).decode(): test.cancel("Current kvm user space version does not" " support 'rebase' subcommand") sn_fmt = params.get("snapshot_format", "qcow2") sn1 = params["image_name_snapshot1"] sn1 = _get_image_filename(sn1, enable_gluster, sn_fmt) base_img = storage.get_image_filename(params, data_dir.get_data_dir()) _create(cmd, sn1, sn_fmt, base_img=base_img, base_img_fmt=image_format) # Create snapshot2 based on snapshot1 sn2 = params["image_name_snapshot2"] sn2 = _get_image_filename(sn2, enable_gluster, sn_fmt) _create(cmd, sn2, sn_fmt, base_img=sn1, base_img_fmt=sn_fmt) rebase_mode = params.get("rebase_mode", "safe") if rebase_mode == "unsafe": remove(sn1) _rebase(cmd, sn2, base_img, image_format, mode=rebase_mode) # Boot snapshot image after rebase img_format = sn2.split('.')[-1] img_name = ".".join(sn2.split('.')[:-1]) _boot(img_name, img_format) # Check sn2's format and backing_file actual_base_img = _info(cmd, sn2, "backing file") base_img_name = os.path.basename(base_img) if base_img_name not in actual_base_img: test.fail("After rebase the backing_file of 'sn2' is " "'%s' which is not expected as '%s'" % (actual_base_img, base_img_name)) status, output = _check(cmd, sn2) if not status: test.fail("Check image '%s' failed after rebase;" "got error: %s" % (sn2, output)) remove(sn2) remove(sn1) def _amend(cmd, img_name, img_fmt, options): """ Simple wrapper of 'qemu-img amend'. :param cmd: qemu-img base command :param img_name: image name that should be amended :param img_fmt: image format :param options: a comma separated list of format specific options """ msg = "Amend '%s' with options '%s'" % (img_name, options) cmd += " amend" if img_fmt: cmd += " -f %s" % img_fmt cache = params.get("cache_mode", '') if cache: cmd += " -t %s" % cache if options: cmd += " -o " for option in options: cmd += "%s=%s," % (option, params.get(option)) cmd = cmd.rstrip(',') cmd += " %s" % img_name error_context.context(msg, logging.info) check_command_output(process.run(cmd, ignore_status=True)) def amend_test(cmd): """ Subcommand 'qemu-img amend' test Amend the image format specific options for the image file :param cmd: qemu-img base command. """ img_name = params.get("image_name_stg") img_fmt = params.get("image_format_stg", "qcow2") options = params.get("qemu_img_options", "").split() check_output = params.get("check_output", "exit_status") img = _get_image_filename(img_name, img_fmt=img_fmt) _amend(cmd, img, img_fmt, options) if check_output == "exit_status": for option in options: expect = params.get(option) if option == "size": option = "virtual size" actual = _info(cmd, img, option) if actual is not None and actual != expect: msg = "Get wrong %s from image %s!" % (option, img_name) msg += "Expect: %s, actual: %s" % (expect, actual) test.fail(msg) status, output = _check(cmd, img) if not status: test.fail("Check image '%s' failed after rebase;" "got error: %s" % (img, output)) def _boot(img_name, img_fmt): """ Boot test: 1) Login guest 2) Run dd in rhel guest 3) Shutdown guest :param img_name: image name :param img_fmt: image format """ params['image_name'] = img_name params['image_format'] = img_fmt image_name = "%s.%s" % (img_name, img_fmt) msg = "Try to boot vm with image %s" % image_name error_context.context(msg, logging.info) vm_name = params.get("main_vm") dd_timeout = int(params.get("dd_timeout", 60)) params['vms'] = vm_name env_process.preprocess_vm(test, params, env, vm_name) vm = env.get_vm(params.get("main_vm")) vm.verify_alive() login_timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) # Run dd in linux guest if params.get("os_type") == 'linux': cmd = "dd if=/dev/zero of=/mnt/test bs=1000 count=1000" status = session.cmd_status(cmd, timeout=dd_timeout) if status != 0: test.error("dd failed") error_context.context("Shutdown guest", logging.info) try: vm.graceful_shutdown(timeout=login_timeout) except Exception: image_filename = _get_image_filename(img_name, enable_gluster, img_fmt) backup_img_chain(image_filename) raise finally: vm.destroy(gracefully=True) process.system("sync") def backup_img_chain(image_file): """ Backup whole image in a image chain; """ mount_point = tempfile.mkdtemp(dir=test.resultsdir) qemu_img = utils_misc.get_qemu_img_binary(params) if enable_gluster: g_uri = gluster.create_gluster_uri(params) gluster.glusterfs_mount(g_uri, mount_point) image_name = os.path.basename(image_file) image_file = os.path.join(mount_point, image_name) logging.warn("backup %s to %s" % (image_file, test.resultsdir)) shutil.copy(image_file, test.resultsdir) backing_file = _info(qemu_img, image_file, "backing file", None) if backing_file: backup_img_chain(backing_file) elif enable_gluster: utils_misc.umount(g_uri, mount_point, "glusterfs", False, "fuse.glusterfs") shutil.rmtree(mount_point) return None # Here starts test subcommand = params["subcommand"] error_context.context("Running %s_test(cmd)" % subcommand, logging.info) eval("%s_test(cmd)" % subcommand)
def run_boot_savevm(test, params, env): """ libvirt boot savevm test: 1) Start guest booting 2) Record origin informations of snapshot list for floppy(optional). 3) Periodically savevm/loadvm while guest booting 4) Stop test when able to login, or fail after timeout seconds. 5) Check snapshot list for floppy and compare with the origin one(optional). @param test: test object @param params: Dictionary with the test parameters @param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) if params.get("with_floppy") == "yes": floppy_name = params.get("floppies", "fl") floppy_params = {"image_format": params.get("floppy_format", "qcow2"), "image_size": params.get("floppy_size", "1.4M"), "image_name": params.get("%s_name" % floppy_name, "images/test"), "vm_type": params.get("vm_type"), "qemu_img_binary": utils_misc.get_qemu_img_binary(params)} floppy = qemu_storage.QemuImg(floppy_params, data_dir.get_data_dir(), floppy_name) floppy.create(floppy_params) floppy_orig_info = floppy.snapshot_list() vm.create(params=params) vm.verify_alive() # This shouldn't require logging in to guest savevm_delay = float(params["savevm_delay"]) savevm_login_delay = float(params["savevm_login_delay"]) savevm_login_timeout = float(params["savevm_timeout"]) savevm_statedir = params.get("savevm_statedir", tempfile.gettempdir()) fd, savevm_statefile = tempfile.mkstemp(suffix='.img', prefix=vm.name+'-', dir=savevm_statedir) os.close(fd) # save_to_file doesn't need the file open start_time = time.time() cycles = 0 successful_login = False while (time.time() - start_time) < savevm_login_timeout: logging.info("Save/Restore cycle %d", cycles + 1) time.sleep(savevm_delay) vm.pause() if params['save_method'] == 'save_to_file': vm.save_to_file(savevm_statefile) # Re-use same filename vm.restore_from_file(savevm_statefile) else: vm.savevm("1") vm.loadvm("1") vm.resume() # doesn't matter if already running or not vm.verify_kernel_crash() # just in case try: vm.wait_for_login(timeout=savevm_login_delay) successful_login = True # not set if timeout expires os.unlink(savevm_statefile) # don't let these clutter disk break except: pass # loop until successful login or time runs out cycles += 1 time_elapsed = int(time.time() - start_time) info = "after %s s, %d load/save cycles" % (time_elapsed, cycles + 1) if not successful_login: raise error.TestFail("Can't log on '%s' %s" % (vm.name, info)) else: logging.info("Test ended %s", info) if params.get("with_floppy") == "yes": vm.destroy() floppy_info = floppy.snapshot_list() if floppy_info == floppy_orig_info: raise error.TestFail("savevm didn't create snapshot in floppy." " original snapshot list is: %s" " now snapshot list is: %s" % (floppy_orig_info, floppy_info))
def __init__(self, test, params, vm): """ Sets class attributes from test parameters. :param test: QEMU test object. :param params: Dictionary with test parameters. """ root_dir = data_dir.get_data_dir() self.deps_dir = os.path.join(test.virtdir, 'deps') self.unattended_dir = os.path.join(test.virtdir, 'unattended') self.results_dir = test.debugdir self.params = params self.attributes = [ 'kernel_args', 'finish_program', 'cdrom_cd1', 'unattended_file', 'medium', 'url', 'kernel', 'initrd', 'nfs_server', 'nfs_dir', 'install_virtio', 'floppy_name', 'cdrom_unattended', 'boot_path', 'kernel_params', 'extra_params', 'qemu_img_binary', 'cdkey', 'finish_program', 'vm_type', 'process_check', 'vfd_size', 'cdrom_mount_point', 'floppy_mount_point', 'cdrom_virtio', 'virtio_floppy', 're_driver_match', 're_hardware_id', 'driver_in_floppy', 'vga' ] for a in self.attributes: setattr(self, a, params.get(a, '')) # Will setup the virtio attributes v_attributes = [ 'virtio_floppy', 'virtio_scsi_path', 'virtio_storage_path', 'virtio_network_path', 'virtio_oemsetup_id', 'virtio_network_installer_path', 'virtio_balloon_installer_path', 'virtio_qxl_installer_path' ] for va in v_attributes: setattr(self, va, params.get(va, '')) self.tmpdir = test.tmpdir self.qemu_img_binary = utils_misc.get_qemu_img_binary(params) if getattr(self, 'unattended_file'): self.unattended_file = os.path.join(test.virtdir, self.unattended_file) if params.get('use_ovmf_autounattend'): self.unattended_file = re.sub("\.", "_ovmf.", self.unattended_file) if getattr(self, 'finish_program'): self.finish_program = os.path.join(test.virtdir, self.finish_program) 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 getattr(self, 'cdrom_unattended'): self.cdrom_unattended = os.path.join(root_dir, self.cdrom_unattended) if getattr(self, 'virtio_floppy'): self.virtio_floppy = os.path.join(root_dir, self.virtio_floppy) if getattr(self, 'cdrom_virtio'): self.cdrom_virtio = os.path.join(root_dir, self.cdrom_virtio) if getattr(self, 'kernel'): self.kernel = os.path.join(root_dir, self.kernel) if getattr(self, 'initrd'): self.initrd = os.path.join(root_dir, self.initrd) if self.medium == 'nfs': self.nfs_mount = tempfile.mkdtemp(prefix='nfs_', dir=self.tmpdir) setattr(self, 'floppy', self.floppy_name) 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) # Content server params # lookup host ip address for first nic by interface name try: auto_ip = utils_net.get_ip_address_by_interface( vm.virtnet[0].netdst) except utils_net.NetError: auto_ip = None self.url_auto_content_ip = params.get('url_auto_ip', auto_ip) self.url_auto_content_port = None # Kickstart server params # use the same IP as url_auto_content_ip, but a different port self.unattended_server_port = None # Embedded Syslog Server self.syslog_server_enabled = params.get('syslog_server_enabled', 'no') self.syslog_server_ip = params.get('syslog_server_ip', auto_ip) self.syslog_server_port = int(params.get('syslog_server_port', 5140)) self.syslog_server_tcp = params.get('syslog_server_proto', 'tcp') == 'tcp' self.vm = vm