Example #1
0
    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 not 'rebase' in utils.system_output(cmd + ' --help',
                                               ignore_status=True):
            raise error.TestNAError("Current kvm user space version does not"
                                    " support 'rebase' subcommand")
        sn_fmt = params.get("snapshot_format", "qcow2")
        sn1 = params.get("image_name_snapshot1")
        sn1 = kvm_utils.get_path(test.bindir, sn1) + ".%s" % sn_fmt
        base_img = kvm_vm.get_image_filename(params, test.bindir)
        _create(cmd, sn1, sn_fmt, base_img=base_img, base_img_fmt=image_format)

        # Create snapshot2 based on snapshot1
        sn2 = params.get("image_name_snapshot2")
        sn2 = kvm_utils.get_path(test.bindir, sn2) + ".%s" % sn_fmt
        _create(cmd, sn2, sn_fmt, base_img=sn1, base_img_fmt=sn_fmt)

        rebase_mode = params.get("rebase_mode")
        if rebase_mode == "unsafe":
            os.remove(sn1)

        _rebase(cmd, sn2, base_img, image_format, mode=rebase_mode)

        # Check sn2's format and backing_file
        actual_base_img = _info(cmd, sn2, "backing file")
        base_img_name = os.path.basename(params.get("image_name"))
        if not base_img_name in actual_base_img:
            raise error.TestFail("After rebase the backing_file of 'sn2' is "
                                 "'%s' which is not expected as '%s'" %
                                 (actual_base_img, base_img_name))
        s, o = _check(cmd, sn2)
        if not s:
            raise error.TestFail("Check image '%s' failed after rebase;"
                                 "got error: %s" % (sn2, o))
        try:
            os.remove(sn2)
            os.remove(sn1)
        except:
            pass
Example #2
0
    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 not 'rebase' in utils.system_output(cmd + ' --help',
                                               ignore_status=True):
            raise error.TestNAError("Current kvm user space version does not"
                                    " support 'rebase' subcommand")
        sn_fmt = params.get("snapshot_format", "qcow2")
        sn1 = params.get("image_name_snapshot1")
        sn1 = kvm_utils.get_path(test.bindir, sn1) + ".%s" % sn_fmt
        base_img = kvm_vm.get_image_filename(params, test.bindir)
        _create(cmd, sn1, sn_fmt, base_img=base_img, base_img_fmt=image_format)

        # Create snapshot2 based on snapshot1
        sn2 = params.get("image_name_snapshot2")
        sn2 = kvm_utils.get_path(test.bindir, sn2) + ".%s" % sn_fmt
        _create(cmd, sn2, sn_fmt, base_img=sn1, base_img_fmt=sn_fmt)

        rebase_mode = params.get("rebase_mode")
        if rebase_mode == "unsafe":
            os.remove(sn1)

        _rebase(cmd, sn2, base_img, image_format, mode=rebase_mode)

        # Check sn2's format and backing_file
        actual_base_img = _info(cmd, sn2, "backing file")
        base_img_name = os.path.basename(params.get("image_name"))
        if not base_img_name in actual_base_img:
            raise error.TestFail("After rebase the backing_file of 'sn2' is "
                                 "'%s' which is not expected as '%s'"
                                 % (actual_base_img, base_img_name))
        s, o = _check(cmd, sn2)
        if not s:
            raise error.TestFail("Check image '%s' failed after rebase;"
                                 "got error: %s" % (sn2, o))
        try:
            os.remove(sn2)
            os.remove(sn1)
        except:
            pass
Example #3
0
    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 = kvm_utils.get_path(test.bindir,
                                        params.get("image_name_dd"))
        print "test_image = %s" % test_image
        create_image_cmd = params.get("create_image_cmd")
        create_image_cmd = create_image_cmd % test_image
        print "create_image_cmd = %s" % create_image_cmd
        utils.system(create_image_cmd)
        s, o = _check(cmd, test_image)
        if not s:
            raise error.TestFail("Check image '%s' failed with error: %s" %
                                 (test_image, o))
        for fmt in params.get("supported_image_formats").split():
            output_image = test_image + ".%s" % fmt
            _convert(cmd, fmt, test_image, output_image)
            s, o = _check(cmd, output_image)
            if not s:
                raise error.TestFail("Check image '%s' got error: %s" %
                                     (output_image, o))
            os.remove(output_image)
        os.remove(test_image)
Example #4
0
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: kvm test object
    @param params: Dictionary with the test parameters
    @param env: Dictionary with test environment.
    """
    cmd = kvm_utils.get_path(test.bindir, params.get("qemu_img_binary"))
    if not os.path.exists(cmd):
        raise error.TestError("Binary of 'qemu-img' not found")
    image_format = params.get("image_format")
    image_size = params.get("image_size", "10G")
    image_name = kvm_vm.get_image_filename(params, test.bindir)

    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
        logging.info("Checking image '%s'...", img)
        try:
            output = utils.system_output(cmd)
        except error.CmdError, e:
            if "does not support checks" in str(e):
                return (True, "")
            else:
                return (False, str(e))
        return (True, output)
Example #5
0
    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 = kvm_utils.get_path(test.bindir,
                                        params.get("image_name_dd"))
        print "test_image = %s" % test_image
        create_image_cmd = params.get("create_image_cmd")
        create_image_cmd = create_image_cmd % test_image
        print "create_image_cmd = %s" % create_image_cmd
        utils.system(create_image_cmd)
        s, o = _check(cmd, test_image)
        if not s:
            raise error.TestFail("Check image '%s' failed with error: %s" %
                                                           (test_image, o))
        for fmt in params.get("supported_image_formats").split():
            output_image = test_image + ".%s" % fmt
            _convert(cmd, fmt, test_image, output_image)
            s, o = _check(cmd, output_image)
            if not s:
                raise error.TestFail("Check image '%s' got error: %s" %
                                                     (output_image, o))
            os.remove(output_image)
        os.remove(test_image)
Example #6
0
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: kvm test object
    @param params: Dictionary with the test parameters
    @param env: Dictionary with test environment.
    """
    cmd = kvm_utils.get_path(test.bindir, params.get("qemu_img_binary"))
    if not os.path.exists(cmd):
        raise error.TestError("Binary of 'qemu-img' not found")
    image_format = params.get("image_format")
    image_size = params.get("image_size", "10G")
    image_name = kvm_vm.get_image_filename(params, test.bindir)


    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
        logging.info("Checking image '%s'...", img)
        try:
            output = utils.system_output(cmd)
        except error.CmdError, e:
            if "does not support checks" in str(e):
                return (True, "")
            else:
                return (False, str(e))
        return (True, output)
Example #7
0
def create_image(params, root_dir):
    """
    Create an image using qemu_image.

    @param params: Dictionary containing the test parameters.
    @param root_dir: Base directory for relative filenames.

    @note: params should contain:
           image_name -- the name of the image file, without extension
           image_format -- the format of the image (qcow2, raw etc)
           image_size -- the requested size of the image (a string
           qemu-img can understand, such as '10G')
    """
    qemu_img_cmd = kvm_utils.get_path(root_dir, params.get("qemu_img_binary",
                                                           "qemu-img"))
    qemu_img_cmd += " create"

    format = params.get("image_format", "qcow2")
    qemu_img_cmd += " -f %s" % format

    image_filename = get_image_filename(params, root_dir)
    qemu_img_cmd += " %s" % image_filename

    size = params.get("image_size", "10G")
    qemu_img_cmd += " %s" % size

    try:
        utils.system(qemu_img_cmd)
    except error.CmdError, e:
        logging.error("Could not create image; qemu-img command failed:\n%s",
                      str(e))
        return None
def _take_screendumps(test, params, env):
    global _screendump_thread_termination_event
    temp_dir = test.debugdir
    if params.get("screendump_temp_dir"):
        temp_dir = kvm_utils.get_path(test.bindir,
                                      params.get("screendump_temp_dir"))
        try:
            os.makedirs(temp_dir)
        except OSError:
            pass
    temp_filename = os.path.join(temp_dir, "scrdump-%s.ppm" %
                                 kvm_utils.generate_random_string(6))
    delay = float(params.get("screendump_delay", 5))
    quality = int(params.get("screendump_quality", 30))

    cache = {}

    while True:
        for vm in env.get_all_vms():
            if not vm.is_alive():
                continue
            try:
                vm.monitor.screendump(temp_filename)
            except kvm_monitor.MonitorError, e:
                logging.warn(e)
                continue
            if not os.path.exists(temp_filename):
                logging.warn("VM '%s' failed to produce a screendump", vm.name)
                continue
            if not ppm_utils.image_verify_ppm_file(temp_filename):
                logging.warn("VM '%s' produced an invalid screendump", vm.name)
                os.unlink(temp_filename)
                continue
            screendump_dir = os.path.join(test.debugdir,
                                          "screendumps_%s" % vm.name)
            try:
                os.makedirs(screendump_dir)
            except OSError:
                pass
            screendump_filename = os.path.join(screendump_dir,
                    "%s_%s.jpg" % (vm.name,
                                   time.strftime("%Y-%m-%d_%H-%M-%S")))
            hash = utils.hash_file(temp_filename)
            if hash in cache:
                try:
                    os.link(cache[hash], screendump_filename)
                except OSError:
                    pass
            else:
                try:
                    image = PIL.Image.open(temp_filename)
                    image.save(screendump_filename, format="JPEG", quality=quality)
                    cache[hash] = screendump_filename
                except NameError:
                    pass
            os.unlink(temp_filename)
        if _screendump_thread_termination_event.isSet():
            _screendump_thread_termination_event = None
            break
        _screendump_thread_termination_event.wait(delay)
Example #9
0
def run_autoit(test, params, env):
    """
    A wrapper for AutoIt scripts.

    1) Log into a guest.
    2) Run AutoIt script.
    3) Wait for script execution to complete.
    4) Pass/fail according to exit status of script.

    @param test: KVM test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
    session = kvm_test_utils.wait_for_login(vm)

    try:
        logging.info("Starting script...")

        # Collect test parameters
        binary = params.get("autoit_binary")
        script = params.get("autoit_script")
        script_params = params.get("autoit_script_params", "")
        timeout = float(params.get("autoit_script_timeout", 600))

        # Send AutoIt script to guest (this code will be replaced once we
        # support sending files to Windows guests)
        session.sendline("del script.au3")
        file = open(kvm_utils.get_path(test.bindir, script))
        for line in file.readlines():
            # Insert a '^' before each character
            line = "".join("^" + c for c in line.rstrip())
            if line:
                # Append line to the file
                session.sendline("echo %s>>script.au3" % line)
        file.close()

        session.read_up_to_prompt()

        command = "cmd /c %s script.au3 %s" % (binary, script_params)

        logging.info("---------------- Script output ----------------")
        status = session.get_command_status(command,
                                            print_func=logging.info,
                                            timeout=timeout)
        logging.info("---------------- End of script output ----------------")

        if status is None:
            raise error.TestFail("Timeout expired before script execution "
                                 "completed (or something weird happened)")
        if status != 0:
            raise error.TestFail("Script execution failed")

    finally:
        session.close()
Example #10
0
    def create_test(cmd):
        """
        Subcommand 'qemu-img create' test.

        @param cmd: qemu-img base command.
        """
        image_large = params.get("image_name_large")
        img = kvm_utils.get_path(test.bindir, image_large)
        img += '.' + image_format
        _create(cmd, img_name=img, fmt=image_format,
               img_size=params.get("image_size_large"))
        os.remove(img)
Example #11
0
def run_nic_bonding(test, params, env):
    """
    Nic bonding test in guest.

    1) Start guest with four nic models.
    2) Setup bond0 in guest by script nic_bonding_guest.py.
    3) Execute file transfer test between guest and host.
    4) Repeatedly put down/up interfaces by set_link
    5) Execute file transfer test between guest and host.

    @param test: Kvm test object.
    @param params: Dictionary with the test parameters.
    @param env: Dictionary with test environment.
    """
    def control_link_loop(vm, termination_event):
        logging.info("Repeatedly put down/up interfaces by set_link")
        while True:
            for i in range(len(params.get("nics").split())):
                linkname = "%s.%s" % (params.get("nic_model"), i)
                cmd = "set_link %s down" % linkname
                vm.monitor.cmd(cmd)
                time.sleep(1)
                cmd = "set_link %s up" % linkname
                vm.monitor.cmd(cmd)
            if termination_event.isSet():
                break

    timeout = int(params.get("login_timeout", 1200))
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session_serial = vm.wait_for_serial_login(timeout=timeout)
    script_path = kvm_utils.get_path(test.bindir,
                                     "scripts/nic_bonding_guest.py")
    vm.copy_files_to(script_path, "/tmp/nic_bonding_guest.py")
    cmd = "python /tmp/nic_bonding_guest.py %s" % vm.get_mac_address()
    session_serial.cmd(cmd)

    termination_event = threading.Event()
    t = threading.Thread(target=control_link_loop,
                         args=(vm, termination_event))
    try:
        logging.info("Do some basic test before testing high availability")
        file_transfer.run_file_transfer(test, params, env)
        t.start()
        logging.info("Do file transfer testing")
        file_transfer.run_file_transfer(test, params, env)
    finally:
        termination_event.set()
        t.join(10)
        session_serial.close()
Example #12
0
    def create_test(cmd):
        """
        Subcommand 'qemu-img create' test.

        @param cmd: qemu-img base command.
        """
        image_large = params.get("image_name_large")
        img = kvm_utils.get_path(test.bindir, image_large)
        img += '.' + image_format
        _create(cmd,
                img_name=img,
                fmt=image_format,
                img_size=params.get("image_size_large"))
        os.remove(img)
Example #13
0
def run_nic_bonding(test, params, env):
    """
    Nic bonding test in guest.

    1) Start guest with four nic models.
    2) Setup bond0 in guest by script nic_bonding_guest.py.
    3) Execute file transfer test between guest and host.
    4) Repeatedly put down/up interfaces by set_link
    5) Execute file transfer test between guest and host.

    @param test: Kvm test object.
    @param params: Dictionary with the test parameters.
    @param env: Dictionary with test environment.
    """

    def control_link_loop(vm, termination_event):
        logging.info("Repeatedly put down/up interfaces by set_link")
        while True:
            for i in range(len(params.get("nics").split())):
                linkname = "%s.%s" % (params.get("nic_model"), i)
                cmd = "set_link %s down" % linkname
                vm.monitor.cmd(cmd)
                time.sleep(1)
                cmd = "set_link %s up" % linkname
                vm.monitor.cmd(cmd)
            if termination_event.isSet():
                break

    timeout = int(params.get("login_timeout", 1200))
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session_serial = vm.wait_for_serial_login(timeout=timeout)
    script_path = kvm_utils.get_path(test.bindir, "scripts/nic_bonding_guest.py")
    vm.copy_files_to(script_path, "/tmp/nic_bonding_guest.py")
    cmd = "python /tmp/nic_bonding_guest.py %s" % vm.get_mac_address()
    session_serial.cmd(cmd)

    termination_event = threading.Event()
    t = threading.Thread(target=control_link_loop, args=(vm, termination_event))
    try:
        logging.info("Do some basic test before testing high availability")
        file_transfer.run_file_transfer(test, params, env)
        t.start()
        logging.info("Do file transfer testing")
        file_transfer.run_file_transfer(test, params, env)
    finally:
        termination_event.set()
        t.join(10)
        session_serial.close()
Example #14
0
def get_image_filename(params, root_dir):
    """
    Generate an image path from params and root_dir.

    @param params: Dictionary containing the test parameters.
    @param root_dir: Base directory for relative filenames.

    @note: params should contain:
           image_name -- the name of the image file, without extension
           image_format -- the format of the image (qcow2, raw etc)
    """
    image_name = params.get("image_name", "image")
    image_format = params.get("image_format", "qcow2")
    image_filename = "%s.%s" % (image_name, image_format)
    image_filename = kvm_utils.get_path(root_dir, image_filename)
    return image_filename
Example #15
0
    def netdev_add(vm):
        netdev_id = kvm_utils.generate_random_id()
        attach_cmd = ("netdev_add tap,id=%s,script=%s" %
                      (netdev_id, kvm_utils.get_path(vm.root_dir,
                                                     params.get("nic_script"))))
        netdev_extra_params = params.get("netdev_extra_params")
        if netdev_extra_params:
            attach_cmd += ",%s" % netdev_extra_params
        logging.info("Adding netdev through %s", attach_cmd)
        vm.monitor.cmd(attach_cmd)

        network = vm.monitor.info("network")
        if netdev_id not in network:
            logging.error(network)
            raise error.TestError("Fail to add netdev: %s" % netdev_id)
        else:
            return netdev_id
Example #16
0
def run_stepmaker(test, params, env):
    vm = env.get_vm(params.get("main_vm"))
    if not vm:
        raise error.TestError("VM object not found in environment")
    if not vm.is_alive():
        raise error.TestError("VM seems to be dead; Step Maker requires a"
                              " living VM")

    steps_filename = params.get("steps")
    if not steps_filename:
        raise error.TestError("Steps filename not specified")
    steps_filename = kvm_utils.get_path(test.bindir, steps_filename)
    if os.path.exists(steps_filename):
        raise error.TestError("Steps file %s already exists" % steps_filename)

    StepMaker(vm, steps_filename, test.debugdir, params)
    gtk.main()
Example #17
0
def run_stepmaker(test, params, env):
    vm = env.get_vm(params.get("main_vm"))
    if not vm:
        raise error.TestError("VM object not found in environment")
    if not vm.is_alive():
        raise error.TestError("VM seems to be dead; Step Maker requires a"
                              " living VM")

    steps_filename = params.get("steps")
    if not steps_filename:
        raise error.TestError("Steps filename not specified")
    steps_filename = kvm_utils.get_path(test.bindir, steps_filename)
    if os.path.exists(steps_filename):
        raise error.TestError("Steps file %s already exists" % steps_filename)

    StepMaker(vm, steps_filename, test.debugdir, params)
    gtk.main()
Example #18
0
def create_image(params, root_dir):
    """
    Create an image using qemu_image.

    @param params: Dictionary containing the test parameters.
    @param root_dir: Base directory for relative filenames.

    @note: params should contain:
           image_name -- the name of the image file, without extension
           image_format -- the format of the image (qcow2, raw etc)
           image_size -- the requested size of the image (a string
           qemu-img can understand, such as '10G')
    """
    qemu_img_cmd = kvm_utils.get_path(root_dir, params.get("qemu_img_binary", "qemu-img"))
    qemu_img_cmd += " create"

    format = params.get("image_format", "qcow2")
    qemu_img_cmd += " -f %s" % format

    image_filename = get_image_filename(params, root_dir)
    qemu_img_cmd += " %s" % image_filename

    size = params.get("image_size", "10G")
    qemu_img_cmd += " %s" % size

    logging.debug("Running qemu-img command:\n%s" % qemu_img_cmd)
    (status, output) = kvm_subprocess.run_fg(qemu_img_cmd, logging.debug, "(qemu-img) ", timeout=30)

    if status is None:
        logging.error("Timeout elapsed while waiting for qemu-img command " "to complete:\n%s" % qemu_img_cmd)
        return None
    elif status != 0:
        logging.error("Could not create image; " "qemu-img command failed:\n%s" % qemu_img_cmd)
        logging.error("Status: %s" % status)
        logging.error("Output:" + kvm_utils.format_str_for_message(output))
        return None
    if not os.path.exists(image_filename):
        logging.error("Image could not be created for some reason; " "qemu-img command:\n%s" % qemu_img_cmd)
        return None

    logging.info("Image created in %s" % image_filename)
    return image_filename
Example #19
0
    def create(self, name=None, params=None, root_dir=None, for_migration=False, timeout=5.0):
        """
        Start the VM by running a qemu command.
        All parameters are optional. The following applies to all parameters
        but for_migration: If a parameter is not supplied, the corresponding
        value stored in the class attributes is used, and if it is supplied,
        it is stored for later use.

        @param name: The name of the object
        @param params: A dict containing VM params
        @param root_dir: Base directory for relative filenames
        @param for_migration: If True, start the VM with the -incoming
        option
        """
        self.destroy()

        if name != None:
            self.name = name
        if params != None:
            self.params = params
        if root_dir != None:
            self.root_dir = root_dir
        name = self.name
        params = self.params
        root_dir = self.root_dir

        # Verify the md5sum of the ISO image
        iso = params.get("cdrom")
        if iso:
            iso = kvm_utils.get_path(root_dir, iso)
            if not os.path.exists(iso):
                logging.error("ISO file not found: %s" % iso)
                return False
            compare = False
            if params.get("md5sum_1m"):
                logging.debug("Comparing expected MD5 sum with MD5 sum of " "first MB of ISO file...")
                actual_md5sum = kvm_utils.md5sum_file(iso, 1048576)
                expected_md5sum = params.get("md5sum_1m")
                compare = True
            elif params.get("md5sum"):
                logging.debug("Comparing expected MD5 sum with MD5 sum of ISO " "file...")
                actual_md5sum = kvm_utils.md5sum_file(iso)
                expected_md5sum = params.get("md5sum")
                compare = True
            if compare:
                if actual_md5sum == expected_md5sum:
                    logging.debug("MD5 sums match")
                else:
                    logging.error("Actual MD5 sum differs from expected one")
                    return False

        # Make sure the following code is not executed by more than one thread
        # at the same time
        lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
        fcntl.lockf(lockfile, fcntl.LOCK_EX)

        try:
            # Handle port redirections
            redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
            host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
            self.redirs = {}
            for i in range(len(redir_names)):
                redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
                guest_port = int(redir_params.get("guest_port"))
                self.redirs[guest_port] = host_ports[i]

            # Find available VNC port, if needed
            if params.get("display") == "vnc":
                self.vnc_port = kvm_utils.find_free_port(5900, 6000)

            # Find random UUID if specified 'uuid = random' in config file
            if params.get("uuid") == "random":
                f = open("/proc/sys/kernel/random/uuid")
                self.uuid = f.read().strip()
                f.close()

            # Make qemu command
            qemu_command = self.make_qemu_command()

            # Is this VM supposed to accept incoming migrations?
            if for_migration:
                # Find available migration port
                self.migration_port = kvm_utils.find_free_port(5200, 6000)
                # Add -incoming option to the qemu command
                qemu_command += " -incoming tcp:0:%d" % self.migration_port

            logging.debug("Running qemu command:\n%s", qemu_command)
            self.process = kvm_subprocess.run_bg(qemu_command, None, logging.debug, "(qemu) ")

            if not self.process.is_alive():
                logging.error("VM could not be created; " "qemu command failed:\n%s" % qemu_command)
                logging.error("Status: %s" % self.process.get_status())
                logging.error("Output:" + kvm_utils.format_str_for_message(self.process.get_output()))
                self.destroy()
                return False

            if not kvm_utils.wait_for(self.is_alive, timeout, 0, 1):
                logging.error("VM is not alive for some reason; " "qemu command:\n%s" % qemu_command)
                self.destroy()
                return False

            # Get the output so far, to see if we have any problems with
            # hugepage setup.
            output = self.process.get_output()

            if "alloc_mem_area" in output:
                logging.error("Could not allocate hugepage memory; " "qemu command:\n%s" % qemu_command)
                logging.error("Output:" + kvm_utils.format_str_for_message(self.process.get_output()))
                return False

            logging.debug("VM appears to be alive with PID %d", self.process.get_pid())
            return True

        finally:
            fcntl.lockf(lockfile, fcntl.LOCK_UN)
            lockfile.close()
Example #20
0
    def make_qemu_command(self, name=None, params=None, root_dir=None):
        """
        Generate a qemu command line. All parameters are optional. If a
        parameter is not supplied, the corresponding value stored in the
        class attributes is used.

        @param name: The name of the object
        @param params: A dict containing VM params
        @param root_dir: Base directory for relative filenames

        @note: The params dict should contain:
               mem -- memory size in MBs
               cdrom -- ISO filename to use with the qemu -cdrom parameter
               extra_params -- a string to append to the qemu command
               shell_port -- port of the remote shell daemon on the guest
               (SSH, Telnet or the home-made Remote Shell Server)
               shell_client -- client program to use for connecting to the
               remote shell daemon on the guest (ssh, telnet or nc)
               x11_display -- if specified, the DISPLAY environment variable
               will be be set to this value for the qemu process (useful for
               SDL rendering)
               images -- a list of image object names, separated by spaces
               nics -- a list of NIC object names, separated by spaces

               For each image in images:
               drive_format -- string to pass as 'if' parameter for this
               image (e.g. ide, scsi)
               image_snapshot -- if yes, pass 'snapshot=on' to qemu for
               this image
               image_boot -- if yes, pass 'boot=on' to qemu for this image
               In addition, all parameters required by get_image_filename.

               For each NIC in nics:
               nic_model -- string to pass as 'model' parameter for this
               NIC (e.g. e1000)
        """
        if name == None:
            name = self.name
        if params == None:
            params = self.params
        if root_dir == None:
            root_dir = self.root_dir

        # Start constructing the qemu command
        qemu_cmd = ""
        # Set the X11 display parameter if requested
        if params.get("x11_display"):
            qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
        # Add the qemu binary
        qemu_cmd += kvm_utils.get_path(root_dir, params.get("qemu_binary", "qemu"))
        # Add the VM's name
        qemu_cmd += " -name '%s'" % name
        # Add the monitor socket parameter
        qemu_cmd += " -monitor unix:%s,server,nowait" % self.monitor_file_name

        for image_name in kvm_utils.get_sub_dict_names(params, "images"):
            image_params = kvm_utils.get_sub_dict(params, image_name)
            if image_params.get("boot_drive") == "no":
                continue
            qemu_cmd += " -drive file=%s" % get_image_filename(image_params, root_dir)
            if image_params.get("drive_format"):
                qemu_cmd += ",if=%s" % image_params.get("drive_format")
            if image_params.get("drive_cache"):
                qemu_cmd += ",cache=%s" % image_params.get("drive_cache")
            if image_params.get("drive_serial"):
                qemu_cmd += ",serial=%s" % image_params.get("drive_serial")
            if image_params.get("image_snapshot") == "yes":
                qemu_cmd += ",snapshot=on"
            if image_params.get("image_boot") == "yes":
                qemu_cmd += ",boot=on"

        vlan = 0
        for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
            nic_params = kvm_utils.get_sub_dict(params, nic_name)
            # Handle the '-net nic' part
            qemu_cmd += " -net nic,vlan=%d" % vlan
            if nic_params.get("nic_model"):
                qemu_cmd += ",model=%s" % nic_params.get("nic_model")
            if nic_params.has_key("address_index"):
                mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
                if mac:
                    qemu_cmd += ",macaddr=%s" % mac
            # Handle the '-net tap' or '-net user' part
            mode = nic_params.get("nic_mode", "user")
            qemu_cmd += " -net %s,vlan=%d" % (mode, vlan)
            if mode == "tap":
                if nic_params.get("nic_ifname"):
                    qemu_cmd += ",ifname=%s" % nic_params.get("nic_ifname")
                script_path = nic_params.get("nic_script")
                if script_path:
                    script_path = kvm_utils.get_path(root_dir, script_path)
                    qemu_cmd += ",script=%s" % script_path
                script_path = nic_params.get("nic_downscript")
                if script_path:
                    script_path = kvm_utils.get_path(root_dir, script_path)
                    qemu_cmd += ",downscript=%s" % script_path
            # Proceed to next NIC
            vlan += 1

        mem = params.get("mem")
        if mem:
            qemu_cmd += " -m %s" % mem

        iso = params.get("cdrom")
        if iso:
            iso = kvm_utils.get_path(root_dir, iso)
            qemu_cmd += " -cdrom %s" % iso

        extra_params = params.get("extra_params")
        if extra_params:
            qemu_cmd += " %s" % extra_params

        for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
            redir_params = kvm_utils.get_sub_dict(params, redir_name)
            guest_port = int(redir_params.get("guest_port"))
            host_port = self.redirs.get(guest_port)
            qemu_cmd += " -redir tcp:%s::%s" % (host_port, guest_port)

        if params.get("display") == "vnc":
            qemu_cmd += " -vnc :%d" % (self.vnc_port - 5900)
        elif params.get("display") == "sdl":
            qemu_cmd += " -sdl"
        elif params.get("display") == "nographic":
            qemu_cmd += " -nographic"

        if params.get("uuid") == "random":
            qemu_cmd += " -uuid %s" % self.uuid
        elif params.get("uuid"):
            qemu_cmd += " -uuid %s" % params.get("uuid")

        return qemu_cmd
Example #21
0
    def create(self, name=None, params=None, root_dir=None, timeout=5.0,
               migration_mode=None, mac_source=None):
        """
        Start the VM by running a qemu command.
        All parameters are optional. If name, params or root_dir are not
        supplied, the respective values stored as class attributes are used.

        @param name: The name of the object
        @param params: A dict containing VM params
        @param root_dir: Base directory for relative filenames
        @param migration_mode: If supplied, start VM for incoming migration
                using this protocol (either 'tcp', 'unix' or 'exec')
        @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."'
                (e.g. 'gzip -c -d filename') if migration_mode is 'exec'
        @param mac_source: A VM object from which to copy MAC addresses. If not
                specified, new addresses will be generated.
        """
        self.destroy()

        if name is not None:
            self.name = name
        if params is not None:
            self.params = params
        if root_dir is not None:
            self.root_dir = root_dir
        name = self.name
        params = self.params
        root_dir = self.root_dir

        # Verify the md5sum of the ISO image
        iso = params.get("cdrom")
        if iso:
            iso = kvm_utils.get_path(root_dir, iso)
            if not os.path.exists(iso):
                logging.error("ISO file not found: %s" % iso)
                return False
            compare = False
            if params.get("md5sum_1m"):
                logging.debug("Comparing expected MD5 sum with MD5 sum of "
                              "first MB of ISO file...")
                actual_hash = utils.hash_file(iso, 1048576, method="md5")
                expected_hash = params.get("md5sum_1m")
                compare = True
            elif params.get("md5sum"):
                logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
                              "file...")
                actual_hash = utils.hash_file(iso, method="md5")
                expected_hash = params.get("md5sum")
                compare = True
            elif params.get("sha1sum"):
                logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
                              "ISO file...")
                actual_hash = utils.hash_file(iso, method="sha1")
                expected_hash = params.get("sha1sum")
                compare = True
            if compare:
                if actual_hash == expected_hash:
                    logging.debug("Hashes match")
                else:
                    logging.error("Actual hash differs from expected one")
                    return False

        # Make sure the following code is not executed by more than one thread
        # at the same time
        lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
        fcntl.lockf(lockfile, fcntl.LOCK_EX)

        try:
            # Handle port redirections
            redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
            host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
            self.redirs = {}
            for i in range(len(redir_names)):
                redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
                guest_port = int(redir_params.get("guest_port"))
                self.redirs[guest_port] = host_ports[i]

            # Generate netdev IDs for all NICs
            self.netdev_id = []
            for nic in kvm_utils.get_sub_dict_names(params, "nics"):
                self.netdev_id.append(kvm_utils.generate_random_id())

            # Find available VNC port, if needed
            if params.get("display") == "vnc":
                self.vnc_port = kvm_utils.find_free_port(5900, 6100)

            # Find random UUID if specified 'uuid = random' in config file
            if params.get("uuid") == "random":
                f = open("/proc/sys/kernel/random/uuid")
                self.uuid = f.read().strip()
                f.close()

            # Generate or copy MAC addresses for all NICs
            num_nics = len(kvm_utils.get_sub_dict_names(params, "nics"))
            for vlan in range(num_nics):
                nic_name = kvm_utils.get_sub_dict_names(params, "nics")[vlan]
                nic_params = kvm_utils.get_sub_dict(params, nic_name)
                if nic_params.get("nic_mac", None):
                    mac = nic_params.get("nic_mac")
                    kvm_utils.set_mac_address(self.instance, vlan, mac)
                else:
                    mac = mac_source and mac_source.get_mac_address(vlan)
                    if mac:
                        kvm_utils.set_mac_address(self.instance, vlan, mac)
                    else:
                        kvm_utils.generate_mac_address(self.instance, vlan)

            # Assign a PCI assignable device
            self.pci_assignable = None
            pa_type = params.get("pci_assignable")
            if pa_type in ["vf", "pf", "mixed"]:
                pa_devices_requested = params.get("devices_requested")

                # Virtual Functions (VF) assignable devices
                if pa_type == "vf":
                    self.pci_assignable = kvm_utils.PciAssignable(
                        type=pa_type,
                        driver=params.get("driver"),
                        driver_option=params.get("driver_option"),
                        devices_requested=pa_devices_requested)
                # Physical NIC (PF) assignable devices
                elif pa_type == "pf":
                    self.pci_assignable = kvm_utils.PciAssignable(
                        type=pa_type,
                        names=params.get("device_names"),
                        devices_requested=pa_devices_requested)
                # Working with both VF and PF
                elif pa_type == "mixed":
                    self.pci_assignable = kvm_utils.PciAssignable(
                        type=pa_type,
                        driver=params.get("driver"),
                        driver_option=params.get("driver_option"),
                        names=params.get("device_names"),
                        devices_requested=pa_devices_requested)

                self.pa_pci_ids = self.pci_assignable.request_devs()

                if self.pa_pci_ids:
                    logging.debug("Successfuly assigned devices: %s",
                                  self.pa_pci_ids)
                else:
                    logging.error("No PCI assignable devices were assigned "
                                  "and 'pci_assignable' is defined to %s "
                                  "on your config file. Aborting VM creation.",
                                  pa_type)
                    return False

            elif pa_type and pa_type != "no":
                logging.warn("Unsupported pci_assignable type: %s", pa_type)

            # Make qemu command
            qemu_command = self.make_qemu_command()

            # Add migration parameters if required
            if migration_mode == "tcp":
                self.migration_port = kvm_utils.find_free_port(5200, 6000)
                qemu_command += " -incoming tcp:0:%d" % self.migration_port
            elif migration_mode == "unix":
                self.migration_file = "/tmp/migration-unix-%s" % self.instance
                qemu_command += " -incoming unix:%s" % self.migration_file
            elif migration_mode == "exec":
                self.migration_port = kvm_utils.find_free_port(5200, 6000)
                qemu_command += (' -incoming "exec:nc -l %s"' %
                                 self.migration_port)

            logging.debug("Running qemu command:\n%s", qemu_command)
            self.process = kvm_subprocess.run_bg(qemu_command, None,
                                                 logging.debug, "(qemu) ")

            # Make sure the process was started successfully
            if not self.process.is_alive():
                logging.error("VM could not be created; "
                              "qemu command failed:\n%s" % qemu_command)
                logging.error("Status: %s" % self.process.get_status())
                logging.error("Output:" + kvm_utils.format_str_for_message(
                    self.process.get_output()))
                self.destroy()
                return False

            # Establish monitor connections
            self.monitors = []
            for monitor_name in kvm_utils.get_sub_dict_names(params,
                                                             "monitors"):
                monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
                # Wait for monitor connection to succeed
                end_time = time.time() + timeout
                while time.time() < end_time:
                    try:
                        if monitor_params.get("monitor_type") == "qmp":
                            # Add a QMP monitor
                            monitor = kvm_monitor.QMPMonitor(
                                monitor_name,
                                self.get_monitor_filename(monitor_name))
                        else:
                            # Add a "human" monitor
                            monitor = kvm_monitor.HumanMonitor(
                                monitor_name,
                                self.get_monitor_filename(monitor_name))
                    except kvm_monitor.MonitorError, e:
                        logging.warn(e)
                    else:
                        if monitor.is_responsive():
                            break
                    time.sleep(1)
                else:
                    logging.error("Could not connect to monitor '%s'" %
                                  monitor_name)
                    self.destroy()
                    return False
                # Add this monitor to the list
                self.monitors += [monitor]

            # Get the output so far, to see if we have any problems with
            # KVM modules or with hugepage setup.
            output = self.process.get_output()

            if re.search("Could not initialize KVM", output, re.IGNORECASE):
                logging.error("Could not initialize KVM; "
                              "qemu command:\n%s" % qemu_command)
                logging.error("Output:" + kvm_utils.format_str_for_message(
                              self.process.get_output()))
                self.destroy()
                return False

            if "alloc_mem_area" in output:
                logging.error("Could not allocate hugepage memory; "
                              "qemu command:\n%s" % qemu_command)
                logging.error("Output:" + kvm_utils.format_str_for_message(
                              self.process.get_output()))
                self.destroy()
                return False

            logging.debug("VM appears to be alive with PID %s", self.get_pid())

            # Establish a session with the serial console -- requires a version
            # of netcat that supports -U
            self.serial_console = kvm_subprocess.ShellSession(
                "nc -U %s" % self.get_serial_console_filename(),
                auto_close=False,
                output_func=kvm_utils.log_line,
                output_params=("serial-%s.log" % name,))

            return True
Example #22
0
def run_guest_test(test, params, env):
    """
    A wrapper for running customized tests in guests.

    1) Log into a guest.
    2) Run script.
    3) Wait for script execution to complete.
    4) Pass/fail according to exit status of script.

    @param test: KVM test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    login_timeout = int(params.get("login_timeout", 360))
    reboot = params.get("reboot", "no")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    if params.get("serial_login") == "yes":
        session = vm.wait_for_serial_login(timeout=login_timeout)
    else:
        session = vm.wait_for_login(timeout=login_timeout)

    if reboot == "yes":
        logging.debug("Rebooting guest before test ...")
        session = vm.reboot(session, timeout=login_timeout)

    try:
        logging.info("Starting script...")

        # Collect test parameters
        interpreter = params.get("interpreter")
        script = params.get("guest_script")
        dst_rsc_path = params.get("dst_rsc_path", "script.au3")
        script_params = params.get("script_params", "")
        test_timeout = float(params.get("test_timeout", 600))

        logging.debug("Starting preparing resouce files...")
        # Download the script resource from a remote server, or
        # prepare the script using rss?
        if params.get("download") == "yes":
            download_cmd = params.get("download_cmd")
            rsc_server = params.get("rsc_server")
            rsc_dir = os.path.basename(rsc_server)
            dst_rsc_dir = params.get("dst_rsc_dir")

            # Change dir to dst_rsc_dir, and remove the guest script dir there
            rm_cmd = "cd %s && (rmdir /s /q %s || del /s /q %s)" % \
                     (dst_rsc_dir, rsc_dir, rsc_dir)
            session.cmd(rm_cmd, timeout=test_timeout)
            logging.debug("Clean directory succeeded.")

            # then download the resource.
            rsc_cmd = "cd %s && %s %s" % (dst_rsc_dir, download_cmd, rsc_server)
            session.cmd(rsc_cmd, timeout=test_timeout)
            logging.info("Download resource finished.")
        else:
            session.cmd_output("del %s" % dst_rsc_path, internal_timeout=0)
            script_path = kvm_utils.get_path(test.bindir, script)
            vm.copy_files_to(script_path, dst_rsc_path, timeout=60)

        cmd = "%s %s %s" % (interpreter, dst_rsc_path, script_params)

        try:
            logging.info("------------ Script output ------------")
            session.cmd(cmd, print_func=logging.info, timeout=test_timeout)
        finally:
            logging.info("------------ End of script output ------------")

        if reboot == "yes":
            logging.debug("Rebooting guest after test ...")
            session = vm.reboot(session, timeout=login_timeout)

        logging.debug("guest test PASSED.")
    finally:
        session.close()
Example #23
0
def preprocess(test, params, env):
    """
    Preprocess all VMs and images according to the instructions in params.
    Also, collect some host information, such as the KVM version.

    @param test: An Autotest test object.
    @param params: A dict containing all VM and image parameters.
    @param env: The environment (a dict-like object).
    """
    error.context("preprocessing")

    # Start tcpdump if it isn't already running
    if "address_cache" not in env:
        env["address_cache"] = {}
    if "tcpdump" in env and not env["tcpdump"].is_alive():
        env["tcpdump"].close()
        del env["tcpdump"]
    if "tcpdump" not in env and params.get("run_tcpdump", "yes") == "yes":
        cmd = "%s -npvi any 'dst port 68'" % kvm_utils.find_command("tcpdump")
        logging.debug("Starting tcpdump (%s)...", cmd)
        env["tcpdump"] = kvm_subprocess.Tail(
            command=cmd,
            output_func=_update_address_cache,
            output_params=(env["address_cache"], ))
        if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(), 0.1, 0.1,
                              1.0):
            logging.warn("Could not start tcpdump")
            logging.warn("Status: %s" % env["tcpdump"].get_status())
            logging.warn(
                "Output:" +
                kvm_utils.format_str_for_message(env["tcpdump"].get_output()))

    # Destroy and remove VMs that are no longer needed in the environment
    requested_vms = params.objects("vms")
    for key in env.keys():
        vm = env[key]
        if not kvm_utils.is_vm(vm):
            continue
        if not vm.name in requested_vms:
            logging.debug("VM '%s' found in environment but not required for "
                          "test; removing it..." % vm.name)
            vm.destroy()
            del env[key]

    # Get the KVM kernel module version and write it as a keyval
    logging.debug("Fetching KVM module version...")
    if os.path.exists("/dev/kvm"):
        try:
            kvm_version = open("/sys/module/kvm/version").read().strip()
        except:
            kvm_version = os.uname()[2]
    else:
        kvm_version = "Unknown"
        logging.debug("KVM module not loaded")
    logging.debug("KVM version: %s" % kvm_version)
    test.write_test_keyval({"kvm_version": kvm_version})

    # Get the KVM userspace version and write it as a keyval
    logging.debug("Fetching KVM userspace version...")
    qemu_path = kvm_utils.get_path(test.bindir,
                                   params.get("qemu_binary", "qemu"))
    version_line = commands.getoutput("%s -help | head -n 1" % qemu_path)
    matches = re.findall("[Vv]ersion .*?,", version_line)
    if matches:
        kvm_userspace_version = " ".join(matches[0].split()[1:]).strip(",")
    else:
        kvm_userspace_version = "Unknown"
        logging.debug("Could not fetch KVM userspace version")
    logging.debug("KVM userspace version: %s" % kvm_userspace_version)
    test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version})

    if params.get("setup_hugepages") == "yes":
        h = test_setup.HugePageConfig(params)
        h.setup()

    if params.get("type") == "unattended_install":
        u = test_setup.UnattendedInstallConfig(test, params)
        u.setup()

    if params.get("type") == "enospc":
        e = test_setup.EnospcConfig(test, params)
        e.setup()

    # Execute any pre_commands
    if params.get("pre_command"):
        process_command(test, params, env, params.get("pre_command"),
                        int(params.get("pre_command_timeout", "600")),
                        params.get("pre_command_noncritical") == "yes")

    # Preprocess all VMs and images
    process(test, params, env, preprocess_image, preprocess_vm)

    # Start the screendump thread
    if params.get("take_regular_screendumps") == "yes":
        logging.debug("Starting screendump thread")
        global _screendump_thread, _screendump_thread_termination_event
        _screendump_thread_termination_event = threading.Event()
        _screendump_thread = threading.Thread(target=_take_screendumps,
                                              args=(test, params, env))
        _screendump_thread.start()
Example #24
0
def _take_screendumps(test, params, env):
    global _screendump_thread_termination_event
    temp_dir = test.debugdir
    if params.get("screendump_temp_dir"):
        temp_dir = kvm_utils.get_path(test.bindir,
                                      params.get("screendump_temp_dir"))
        try:
            os.makedirs(temp_dir)
        except OSError:
            pass
    temp_filename = os.path.join(
        temp_dir, "scrdump-%s.ppm" % kvm_utils.generate_random_string(6))
    delay = float(params.get("screendump_delay", 5))
    quality = int(params.get("screendump_quality", 30))

    cache = {}

    while True:
        for vm in env.get_all_vms():
            if not vm.is_alive():
                continue
            try:
                vm.monitor.screendump(temp_filename)
            except kvm_monitor.MonitorError, e:
                logging.warn(e)
                continue
            if not os.path.exists(temp_filename):
                logging.warn("VM '%s' failed to produce a screendump", vm.name)
                continue
            if not ppm_utils.image_verify_ppm_file(temp_filename):
                logging.warn("VM '%s' produced an invalid screendump", vm.name)
                os.unlink(temp_filename)
                continue
            screendump_dir = os.path.join(test.debugdir,
                                          "screendumps_%s" % vm.name)
            try:
                os.makedirs(screendump_dir)
            except OSError:
                pass
            screendump_filename = os.path.join(
                screendump_dir,
                "%s_%s.jpg" % (vm.name, time.strftime("%Y-%m-%d_%H-%M-%S")))
            hash = utils.hash_file(temp_filename)
            if hash in cache:
                try:
                    os.link(cache[hash], screendump_filename)
                except OSError:
                    pass
            else:
                try:
                    image = PIL.Image.open(temp_filename)
                    image.save(screendump_filename,
                               format="JPEG",
                               quality=quality)
                    cache[hash] = screendump_filename
                except NameError:
                    pass
            os.unlink(temp_filename)
        if _screendump_thread_termination_event.isSet():
            _screendump_thread_termination_event = None
            break
        _screendump_thread_termination_event.wait(delay)
def run_whql_submission(test, params, env):
    """
    WHQL submission test:
    1) Log into the guest (the client machine) and into a DTM server machine
    2) Copy the automation program binary (dsso_test_binary) to the server machine
    3) Run the automation program
    4) Pass the program all relevant parameters (e.g. device_data)
    5) Wait for the program to terminate
    6) Parse and report job results
    (logs and HTML reports are placed in test.bindir)

    @param test: kvm test object
    @param params: Dictionary with the test parameters
    @param env: Dictionary with test environment.
    """
    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
    session = kvm_test_utils.wait_for_login(vm, 0, 240)

    # Collect parameters
    server_address = params.get("server_address")
    server_shell_port = int(params.get("server_shell_port"))
    server_file_transfer_port = int(params.get("server_file_transfer_port"))
    server_studio_path = params.get("server_studio_path", "%programfiles%\\ " "Microsoft Driver Test Manager\\Studio")
    dsso_test_binary = params.get("dsso_test_binary", "deps/whql_submission_15.exe")
    dsso_test_binary = kvm_utils.get_path(test.bindir, dsso_test_binary)
    test_device = params.get("test_device")
    job_filter = params.get("job_filter", ".*")
    test_timeout = float(params.get("test_timeout", 600))
    wtt_services = params.get("wtt_services")

    # Restart WTT service(s) on the client
    logging.info("Restarting WTT services on client")
    for svc in wtt_services.split():
        kvm_test_utils.stop_windows_service(session, svc)
    for svc in wtt_services.split():
        kvm_test_utils.start_windows_service(session, svc)

    # Copy dsso_test_binary to the server
    rss_file_transfer.upload(
        server_address, server_file_transfer_port, dsso_test_binary, server_studio_path, timeout=60
    )

    # Open a shell session with the server
    server_session = kvm_utils.remote_login(
        "nc", server_address, server_shell_port, "", "", session.prompt, session.linesep
    )
    server_session.set_status_test_command(session.status_test_command)

    # Get the computer names of the server and client
    cmd = "echo %computername%"
    server_name = server_session.cmd_output(cmd).strip()
    client_name = session.cmd_output(cmd).strip()
    session.close()

    # Run the automation program on the server
    server_session.cmd("cd %s" % server_studio_path)
    cmd = "%s %s %s %s %s %s" % (
        os.path.basename(dsso_test_binary),
        server_name,
        client_name,
        "%s_pool" % client_name,
        "%s_submission" % client_name,
        test_timeout,
    )
    server_session.sendline(cmd)

    # Helper function: wait for a given prompt and raise an exception if an
    # error occurs
    def find_prompt(prompt):
        m, o = server_session.read_until_last_line_matches(
            [prompt, server_session.prompt], print_func=logging.info, timeout=600
        )
        if m != 0:
            errors = re.findall("^Error:.*$", o, re.I | re.M)
            if errors:
                raise error.TestError(errors[0])
            else:
                raise error.TestError("Error running automation program: " "could not find '%s' prompt" % prompt)

    # Tell the automation program which device to test
    find_prompt("Device to test:")
    server_session.sendline(test_device)

    # Tell the automation program which jobs to run
    find_prompt("Jobs to run:")
    server_session.sendline(job_filter)

    # Give the automation program all the device data supplied by the user
    find_prompt("DeviceData name:")
    for dd in kvm_utils.get_sub_dict_names(params, "device_data"):
        dd_params = kvm_utils.get_sub_dict(params, dd)
        if dd_params.get("dd_name") and dd_params.get("dd_data"):
            server_session.sendline(dd_params.get("dd_name"))
            server_session.sendline(dd_params.get("dd_data"))
    server_session.sendline()

    # Give the automation program all the descriptor information supplied by
    # the user
    find_prompt("Descriptor path:")
    for desc in kvm_utils.get_sub_dict_names(params, "descriptors"):
        desc_params = kvm_utils.get_sub_dict(params, desc)
        if desc_params.get("desc_path"):
            server_session.sendline(desc_params.get("desc_path"))
    server_session.sendline()

    # Wait for the automation program to terminate
    try:
        o = server_session.read_up_to_prompt(print_func=logging.info, timeout=test_timeout + 300)
        # (test_timeout + 300 is used here because the automation program is
        # supposed to terminate cleanly on its own when test_timeout expires)
        done = True
    except kvm_subprocess.ExpectError, e:
        o = e.output
        done = False
def run_whql_client_install(test, params, env):
    """
    WHQL DTM client installation:
    1) Log into the guest (the client machine) and into a DTM server machine
    2) Stop the DTM client service (wttsvc) on the client machine
    3) Delete the client machine from the server's data store
    4) Rename the client machine (give it a randomly generated name)
    5) Move the client machine into the server's workgroup
    6) Reboot the client machine
    7) Install the DTM client software
    8) Setup auto logon for the user created by the installation
       (normally DTMLLUAdminUser)
    9) Reboot again

    @param test: kvm 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()
    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))

    # Collect test params
    server_address = params.get("server_address")
    server_shell_port = int(params.get("server_shell_port"))
    server_file_transfer_port = int(params.get("server_file_transfer_port"))
    server_studio_path = params.get("server_studio_path", "%programfiles%\\ "
                                    "Microsoft Driver Test Manager\\Studio")
    server_username = params.get("server_username")
    server_password = params.get("server_password")
    client_username = params.get("client_username")
    client_password = params.get("client_password")
    dsso_delete_machine_binary = params.get("dsso_delete_machine_binary",
                                            "deps/whql_delete_machine_15.exe")
    dsso_delete_machine_binary = kvm_utils.get_path(test.bindir,
                                                    dsso_delete_machine_binary)
    install_timeout = float(params.get("install_timeout", 600))
    install_cmd = params.get("install_cmd")
    wtt_services = params.get("wtt_services")

    # Stop WTT service(s) on client
    for svc in wtt_services.split():
        kvm_test_utils.stop_windows_service(session, svc)

    # Copy dsso_delete_machine_binary to server
    rss_file_transfer.upload(server_address, server_file_transfer_port,
                             dsso_delete_machine_binary, server_studio_path,
                             timeout=60)

    # Open a shell session with server
    server_session = kvm_utils.remote_login("nc", server_address,
                                            server_shell_port, "", "",
                                            session.prompt, session.linesep)
    server_session.set_status_test_command(session.status_test_command)

    # Get server and client information
    cmd = "echo %computername%"
    server_name = server_session.cmd_output(cmd).strip()
    client_name = session.cmd_output(cmd).strip()
    cmd = "wmic computersystem get domain"
    server_workgroup = server_session.cmd_output(cmd).strip()
    server_workgroup = server_workgroup.splitlines()[-1]
    regkey = r"HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
    cmd = "reg query %s /v Domain" % regkey
    o = server_session.cmd_output(cmd).strip().splitlines()[-1]
    try:
        server_dns_suffix = o.split(None, 2)[2]
    except IndexError:
        server_dns_suffix = ""

    # Delete the client machine from the server's data store (if it's there)
    server_session.cmd("cd %s" % server_studio_path)
    cmd = "%s %s %s" % (os.path.basename(dsso_delete_machine_binary),
                        server_name, client_name)
    server_session.cmd(cmd, print_func=logging.info)
    server_session.close()

    # Rename the client machine
    client_name = "autotest_%s" % kvm_utils.generate_random_string(4)
    logging.info("Renaming client machine to '%s'", client_name)
    cmd = ('wmic computersystem where name="%%computername%%" rename name="%s"'
           % client_name)
    session.cmd(cmd, timeout=600)

    # Join the server's workgroup
    logging.info("Joining workgroup '%s'", server_workgroup)
    cmd = ('wmic computersystem where name="%%computername%%" call '
           'joindomainorworkgroup name="%s"' % server_workgroup)
    session.cmd(cmd, timeout=600)

    # Set the client machine's DNS suffix
    logging.info("Setting DNS suffix to '%s'", server_dns_suffix)
    cmd = 'reg add %s /v Domain /d "%s" /f' % (regkey, server_dns_suffix)
    session.cmd(cmd, timeout=300)

    # Reboot
    session = vm.reboot(session)

    # Access shared resources on the server machine
    logging.info("Attempting to access remote share on server")
    cmd = r"net use \\%s /user:%s %s" % (server_name, server_username,
                                         server_password)
    end_time = time.time() + 120
    while time.time() < end_time:
        try:
            session.cmd(cmd)
            break
        except:
            pass
        time.sleep(5)
    else:
        raise error.TestError("Could not access server share from client "
                              "machine")

    # Install
    logging.info("Installing DTM client (timeout=%ds)", install_timeout)
    install_cmd = r"cmd /c \\%s\%s" % (server_name, install_cmd.lstrip("\\"))
    session.cmd(install_cmd, timeout=install_timeout)

    # Setup auto logon
    logging.info("Setting up auto logon for user '%s'", client_username)
    cmd = ('reg add '
           '"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon" '
           '/v "%s" /d "%s" /t REG_SZ /f')
    session.cmd(cmd % ("AutoAdminLogon", "1"))
    session.cmd(cmd % ("DefaultUserName", client_username))
    session.cmd(cmd % ("DefaultPassword", client_password))

    # Reboot one more time
    session = vm.reboot(session)
    session.close()
Example #27
0
def run_whql_submission(test, params, env):
    """
    WHQL submission test:
    1) Log into the client machines and into a DTM server machine
    2) Copy the automation program binary (dsso_test_binary) to the server machine
    3) Run the automation program
    4) Pass the program all relevant parameters (e.g. device_data)
    5) Wait for the program to terminate
    6) Parse and report job results
    (logs and HTML reports are placed in test.debugdir)

    @param test: kvm test object
    @param params: Dictionary with the test parameters
    @param env: Dictionary with test environment.
    """
    # Log into all client VMs
    login_timeout = int(params.get("login_timeout", 360))
    vms = []
    sessions = []
    for vm_name in params.objects("vms"):
        vms.append(env.get_vm(vm_name))
        vms[-1].verify_alive()
        sessions.append(vms[-1].wait_for_login(timeout=login_timeout))

    # Make sure all NICs of all client VMs are up
    for vm in vms:
        nics = vm.params.objects("nics")
        for nic_index in range(len(nics)):
            s = vm.wait_for_login(nic_index, 600)
            s.close()

    # Collect parameters
    server_address = params.get("server_address")
    server_shell_port = int(params.get("server_shell_port"))
    server_file_transfer_port = int(params.get("server_file_transfer_port"))
    server_studio_path = params.get("server_studio_path", "%programfiles%\\ "
                                    "Microsoft Driver Test Manager\\Studio")
    dsso_test_binary = params.get("dsso_test_binary",
                                  "deps/whql_submission_15.exe")
    dsso_test_binary = kvm_utils.get_path(test.bindir, dsso_test_binary)
    dsso_delete_machine_binary = params.get("dsso_delete_machine_binary",
                                            "deps/whql_delete_machine_15.exe")
    dsso_delete_machine_binary = kvm_utils.get_path(test.bindir,
                                                    dsso_delete_machine_binary)
    test_timeout = float(params.get("test_timeout", 600))

    # Copy dsso binaries to the server
    for filename in dsso_test_binary, dsso_delete_machine_binary:
        rss_file_transfer.upload(server_address, server_file_transfer_port,
                                 filename, server_studio_path, timeout=60)

    # Open a shell session with the server
    server_session = kvm_utils.remote_login("nc", server_address,
                                            server_shell_port, "", "",
                                            sessions[0].prompt,
                                            sessions[0].linesep)
    server_session.set_status_test_command(sessions[0].status_test_command)

    # Get the computer names of the server and clients
    cmd = "echo %computername%"
    server_name = server_session.cmd_output(cmd).strip()
    client_names = [session.cmd_output(cmd).strip() for session in sessions]

    # Delete all client machines from the server's data store
    server_session.cmd("cd %s" % server_studio_path)
    for client_name in client_names:
        cmd = "%s %s %s" % (os.path.basename(dsso_delete_machine_binary),
                            server_name, client_name)
        server_session.cmd(cmd, print_func=logging.debug)

    # Reboot the client machines
    sessions = kvm_utils.parallel((vm.reboot, (session,))
                                  for vm, session in zip(vms, sessions))

    # Check the NICs again
    for vm in vms:
        nics = vm.params.objects("nics")
        for nic_index in range(len(nics)):
            s = vm.wait_for_login(nic_index, 600)
            s.close()

    # Run whql_pre_command and close the sessions
    if params.get("whql_pre_command"):
        for session in sessions:
            session.cmd(params.get("whql_pre_command"),
                        int(params.get("whql_pre_command_timeout", 600)))
            session.close()

    # Run the automation program on the server
    pool_name = "%s_pool" % client_names[0]
    submission_name = "%s_%s" % (client_names[0],
                                 params.get("submission_name"))
    cmd = "%s %s %s %s %s %s" % (os.path.basename(dsso_test_binary),
                                 server_name, pool_name, submission_name,
                                 test_timeout, " ".join(client_names))
    server_session.sendline(cmd)

    # Helper function: wait for a given prompt and raise an exception if an
    # error occurs
    def find_prompt(prompt):
        m, o = server_session.read_until_last_line_matches(
            [prompt, server_session.prompt], print_func=logging.info,
            timeout=600)
        if m != 0:
            errors = re.findall("^Error:.*$", o, re.I | re.M)
            if errors:
                raise error.TestError(errors[0])
            else:
                raise error.TestError("Error running automation program: "
                                      "could not find '%s' prompt" % prompt)

    # Tell the automation program which device to test
    find_prompt("Device to test:")
    server_session.sendline(params.get("test_device"))

    # Tell the automation program which jobs to run
    find_prompt("Jobs to run:")
    server_session.sendline(params.get("job_filter", ".*"))

    # Set submission DeviceData
    find_prompt("DeviceData name:")
    for dd in params.objects("device_data"):
        dd_params = params.object_params(dd)
        if dd_params.get("dd_name") and dd_params.get("dd_data"):
            server_session.sendline(dd_params.get("dd_name"))
            server_session.sendline(dd_params.get("dd_data"))
    server_session.sendline()

    # Set submission descriptors
    find_prompt("Descriptor path:")
    for desc in params.objects("descriptors"):
        desc_params = params.object_params(desc)
        if desc_params.get("desc_path"):
            server_session.sendline(desc_params.get("desc_path"))
    server_session.sendline()

    # Set machine dimensions for each client machine
    for vm_name in params.objects("vms"):
        vm_params = params.object_params(vm_name)
        find_prompt(r"Dimension name\b.*:")
        for dp in vm_params.objects("dimensions"):
            dp_params = vm_params.object_params(dp)
            if dp_params.get("dim_name") and dp_params.get("dim_value"):
                server_session.sendline(dp_params.get("dim_name"))
                server_session.sendline(dp_params.get("dim_value"))
        server_session.sendline()

    # Set extra parameters for tests that require them (e.g. NDISTest)
    for vm_name in params.objects("vms"):
        vm_params = params.object_params(vm_name)
        find_prompt(r"Parameter name\b.*:")
        for dp in vm_params.objects("device_params"):
            dp_params = vm_params.object_params(dp)
            if dp_params.get("dp_name") and dp_params.get("dp_regex"):
                server_session.sendline(dp_params.get("dp_name"))
                server_session.sendline(dp_params.get("dp_regex"))
                # Make sure the prompt appears again (if the device isn't found
                # the automation program will terminate)
                find_prompt(r"Parameter name\b.*:")
        server_session.sendline()

    # Wait for the automation program to terminate
    try:
        o = server_session.read_up_to_prompt(print_func=logging.info,
                                             timeout=test_timeout + 300)
        # (test_timeout + 300 is used here because the automation program is
        # supposed to terminate cleanly on its own when test_timeout expires)
        done = True
    except kvm_subprocess.ExpectError, e:
        o = e.output
        done = False
Example #28
0
def run_steps(test, params, env):
    vm = env.get_vm(params.get("main_vm"))
    if not vm:
        raise error.TestError("VM object not found in environment")
    if not vm.is_alive():
        e_msg = "VM seems to be dead. Guestwizard requires a living VM"
        raise error.TestError(e_msg)

    steps_filename = params.get("steps")
    if not steps_filename:
        raise error.TestError("Steps filename not specified")
    steps_filename = kvm_utils.get_path(test.bindir, steps_filename)
    if not os.path.exists(steps_filename):
        raise error.TestError("Steps file not found: %s" % steps_filename)

    sf = open(steps_filename, "r")
    lines = sf.readlines()
    sf.close()

    vm.monitor.cmd("cont")

    current_step_num = 0
    current_screendump = None
    skip_current_step = False

    # Iterate over the lines in the file
    for line in lines:
        line = line.strip()
        if not line:
            continue
        logging.info(line)

        if line.startswith("#"):
            continue

        words = line.split()
        if words[0] == "step":
            current_step_num += 1
            current_screendump = None
            skip_current_step = False
        elif words[0] == "screendump":
            current_screendump = words[1]
        elif skip_current_step:
            continue
        elif words[0] == "sleep":
            timeout_multiplier = float(params.get("timeout_multiplier") or 1)
            time.sleep(float(words[1]) * timeout_multiplier)
        elif words[0] == "key":
            vm.send_key(words[1])
        elif words[0] == "var":
            if not handle_var(vm, params, words[1]):
                logging.error("Variable not defined: %s", words[1])
        elif words[0] == "barrier_2":
            if current_screendump:
                scrdump_filename = os.path.join(
                    ppm_utils.get_data_dir(steps_filename), current_screendump)
            else:
                scrdump_filename = None
            if not barrier_2(vm, words, params, test.debugdir,
                             scrdump_filename, current_step_num):
                skip_current_step = True
        else:
            vm.send_key(words[0])
Example #29
0
def run_steps(test, params, env):
    vm = env.get_vm(params.get("main_vm"))
    if not vm:
        raise error.TestError("VM object not found in environment")
    if not vm.is_alive():
        e_msg = "VM seems to be dead. Guestwizard requires a living VM"
        raise error.TestError(e_msg)

    steps_filename = params.get("steps")
    if not steps_filename:
        raise error.TestError("Steps filename not specified")
    steps_filename = kvm_utils.get_path(test.bindir, steps_filename)
    if not os.path.exists(steps_filename):
        raise error.TestError("Steps file not found: %s" % steps_filename)

    sf = open(steps_filename, "r")
    lines = sf.readlines()
    sf.close()

    vm.monitor.cmd("cont")

    current_step_num = 0
    current_screendump = None
    skip_current_step = False

    # Iterate over the lines in the file
    for line in lines:
        line = line.strip()
        if not line:
            continue
        logging.info(line)

        if line.startswith("#"):
            continue

        words = line.split()
        if words[0] == "step":
            current_step_num += 1
            current_screendump = None
            skip_current_step = False
        elif words[0] == "screendump":
            current_screendump = words[1]
        elif skip_current_step:
            continue
        elif words[0] == "sleep":
            timeout_multiplier = float(params.get("timeout_multiplier") or 1)
            time.sleep(float(words[1]) * timeout_multiplier)
        elif words[0] == "key":
            vm.send_key(words[1])
        elif words[0] == "var":
            if not handle_var(vm, params, words[1]):
                logging.error("Variable not defined: %s", words[1])
        elif words[0] == "barrier_2":
            if current_screendump:
                scrdump_filename = os.path.join(
                    ppm_utils.get_data_dir(steps_filename),
                    current_screendump)
            else:
                scrdump_filename = None
            if not barrier_2(vm, words, params, test.debugdir,
                             scrdump_filename, current_step_num):
                skip_current_step = True
        else:
            vm.send_key(words[0])
Example #30
0
def preprocess(test, params, env):
    """
    Preprocess all VMs and images according to the instructions in params.
    Also, collect some host information, such as the KVM version.

    @param test: An Autotest test object.
    @param params: A dict containing all VM and image parameters.
    @param env: The environment (a dict-like object).
    """
    error.context("preprocessing")

    # Start tcpdump if it isn't already running
    if "address_cache" not in env:
        env["address_cache"] = {}
    if "tcpdump" in env and not env["tcpdump"].is_alive():
        env["tcpdump"].close()
        del env["tcpdump"]
    if "tcpdump" not in env and params.get("run_tcpdump", "yes") == "yes":
        cmd = "%s -npvi any 'dst port 68'" % kvm_utils.find_command("tcpdump")
        logging.debug("Starting tcpdump (%s)...", cmd)
        env["tcpdump"] = kvm_subprocess.Tail(
            command=cmd,
            output_func=_update_address_cache,
            output_params=(env["address_cache"],))
        if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(),
                              0.1, 0.1, 1.0):
            logging.warn("Could not start tcpdump")
            logging.warn("Status: %s" % env["tcpdump"].get_status())
            logging.warn("Output:" + kvm_utils.format_str_for_message(
                env["tcpdump"].get_output()))

    # Destroy and remove VMs that are no longer needed in the environment
    requested_vms = params.objects("vms")
    for key in env.keys():
        vm = env[key]
        if not kvm_utils.is_vm(vm):
            continue
        if not vm.name in requested_vms:
            logging.debug("VM '%s' found in environment but not required for "
                          "test; removing it..." % vm.name)
            vm.destroy()
            del env[key]

    # Get the KVM kernel module version and write it as a keyval
    logging.debug("Fetching KVM module version...")
    if os.path.exists("/dev/kvm"):
        try:
            kvm_version = open("/sys/module/kvm/version").read().strip()
        except:
            kvm_version = os.uname()[2]
    else:
        kvm_version = "Unknown"
        logging.debug("KVM module not loaded")
    logging.debug("KVM version: %s" % kvm_version)
    test.write_test_keyval({"kvm_version": kvm_version})

    # Get the KVM userspace version and write it as a keyval
    logging.debug("Fetching KVM userspace version...")
    qemu_path = kvm_utils.get_path(test.bindir, params.get("qemu_binary",
                                                           "qemu"))
    version_line = commands.getoutput("%s -help | head -n 1" % qemu_path)
    matches = re.findall("[Vv]ersion .*?,", version_line)
    if matches:
        kvm_userspace_version = " ".join(matches[0].split()[1:]).strip(",")
    else:
        kvm_userspace_version = "Unknown"
        logging.debug("Could not fetch KVM userspace version")
    logging.debug("KVM userspace version: %s" % kvm_userspace_version)
    test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version})

    if params.get("setup_hugepages") == "yes":
        h = test_setup.HugePageConfig(params)
        h.setup()

    if params.get("type") == "unattended_install":
        u = test_setup.UnattendedInstallConfig(test, params)
        u.setup()

    if params.get("type") == "enospc":
        e = test_setup.EnospcConfig(test, params)
        e.setup()

    # Execute any pre_commands
    if params.get("pre_command"):
        process_command(test, params, env, params.get("pre_command"),
                        int(params.get("pre_command_timeout", "600")),
                        params.get("pre_command_noncritical") == "yes")

    # Preprocess all VMs and images
    process(test, params, env, preprocess_image, preprocess_vm)

    # Start the screendump thread
    if params.get("take_regular_screendumps") == "yes":
        logging.debug("Starting screendump thread")
        global _screendump_thread, _screendump_thread_termination_event
        _screendump_thread_termination_event = threading.Event()
        _screendump_thread = threading.Thread(target=_take_screendumps,
                                              args=(test, params, env))
        _screendump_thread.start()
Example #31
0
    def make_qemu_command(self, name=None, params=None, root_dir=None):
        """
        Generate a qemu command line. All parameters are optional. If a
        parameter is not supplied, the corresponding value stored in the
        class attributes is used.

        @param name: The name of the object
        @param params: A dict containing VM params
        @param root_dir: Base directory for relative filenames

        @note: The params dict should contain:
               mem -- memory size in MBs
               cdrom -- ISO filename to use with the qemu -cdrom parameter
               extra_params -- a string to append to the qemu command
               shell_port -- port of the remote shell daemon on the guest
               (SSH, Telnet or the home-made Remote Shell Server)
               shell_client -- client program to use for connecting to the
               remote shell daemon on the guest (ssh, telnet or nc)
               x11_display -- if specified, the DISPLAY environment variable
               will be be set to this value for the qemu process (useful for
               SDL rendering)
               images -- a list of image object names, separated by spaces
               nics -- a list of NIC object names, separated by spaces

               For each image in images:
               drive_format -- string to pass as 'if' parameter for this
               image (e.g. ide, scsi)
               image_snapshot -- if yes, pass 'snapshot=on' to qemu for
               this image
               image_boot -- if yes, pass 'boot=on' to qemu for this image
               In addition, all parameters required by get_image_filename.

               For each NIC in nics:
               nic_model -- string to pass as 'model' parameter for this
               NIC (e.g. e1000)
        """
        # Helper function for command line option wrappers
        def has_option(help, option):
            return bool(re.search(r"^-%s(\s|$)" % option, help, re.MULTILINE))

        # Wrappers for all supported qemu command line parameters.
        # This is meant to allow support for multiple qemu versions.
        # Each of these functions receives the output of 'qemu -help' as a
        # parameter, and should add the requested command line option
        # accordingly.

        def add_name(help, name):
            return " -name '%s'" % name

        def add_human_monitor(help, filename):
            return " -monitor unix:'%s',server,nowait" % filename

        def add_qmp_monitor(help, filename):
            return " -qmp unix:'%s',server,nowait" % filename

        def add_serial(help, filename):
            return " -serial unix:'%s',server,nowait" % filename

        def add_mem(help, mem):
            return " -m %s" % mem

        def add_smp(help, smp):
            return " -smp %s" % smp

        def add_cdrom(help, filename, index=None):
            if has_option(help, "drive"):
                cmd = " -drive file='%s',media=cdrom" % filename
                if index is not None: cmd += ",index=%s" % index
                return cmd
            else:
                return " -cdrom '%s'" % filename

        def add_drive(help, filename, index=None, format=None, cache=None,
                      werror=None, serial=None, snapshot=False, boot=False):
            cmd = " -drive file='%s'" % filename
            if index is not None: cmd += ",index=%s" % index
            if format: cmd += ",if=%s" % format
            if cache: cmd += ",cache=%s" % cache
            if werror: cmd += ",werror=%s" % werror
            if serial: cmd += ",serial='%s'" % serial
            if snapshot: cmd += ",snapshot=on"
            if boot: cmd += ",boot=on"
            return cmd

        def add_nic(help, vlan, model=None, mac=None, netdev_id=None,
                    nic_extra_params=None):
            if has_option(help, "netdev"):
                netdev_vlan_str = ",netdev=%s" % netdev_id
            else:
                netdev_vlan_str = ",vlan=%d" % vlan
            if has_option(help, "device"):
                if not model:
                    model = "rtl8139"
                elif model == "virtio":
                    model = "virtio-net-pci"
                cmd = " -device %s" % model + netdev_vlan_str
                if mac:
                    cmd += ",mac='%s'" % mac
                if nic_extra_params:
                    cmd += ",%s" % nic_extra_params
            else:
                cmd = " -net nic" + netdev_vlan_str
                if model:
                    cmd += ",model=%s" % model
                if mac:
                    cmd += ",macaddr='%s'" % mac
            return cmd

        def add_net(help, vlan, mode, ifname=None, script=None,
                    downscript=None, tftp=None, bootfile=None, hostfwd=[],
                    netdev_id=None, netdev_extra_params=None):
            if has_option(help, "netdev"):
                cmd = " -netdev %s,id=%s" % (mode, netdev_id)
                if netdev_extra_params:
                    cmd += ",%s" % netdev_extra_params
            else:
                cmd = " -net %s,vlan=%d" % (mode, vlan)
            if mode == "tap":
                if ifname: cmd += ",ifname='%s'" % ifname
                if script: cmd += ",script='%s'" % script
                cmd += ",downscript='%s'" % (downscript or "no")
            elif mode == "user":
                if tftp and "[,tftp=" in help:
                    cmd += ",tftp='%s'" % tftp
                if bootfile and "[,bootfile=" in help:
                    cmd += ",bootfile='%s'" % bootfile
                if "[,hostfwd=" in help:
                    for host_port, guest_port in hostfwd:
                        cmd += ",hostfwd=tcp::%s-:%s" % (host_port, guest_port)
            return cmd

        def add_floppy(help, filename):
            return " -fda '%s'" % filename

        def add_tftp(help, filename):
            # If the new syntax is supported, don't add -tftp
            if "[,tftp=" in help:
                return ""
            else:
                return " -tftp '%s'" % filename

        def add_bootp(help, filename):
            # If the new syntax is supported, don't add -bootp
            if "[,bootfile=" in help:
                return ""
            else:
                return " -bootp '%s'" % filename

        def add_tcp_redir(help, host_port, guest_port):
            # If the new syntax is supported, don't add -redir
            if "[,hostfwd=" in help:
                return ""
            else:
                return " -redir tcp:%s::%s" % (host_port, guest_port)

        def add_vnc(help, vnc_port):
            return " -vnc :%d" % (vnc_port - 5900)

        def add_sdl(help):
            if has_option(help, "sdl"):
                return " -sdl"
            else:
                return ""

        def add_nographic(help):
            return " -nographic"

        def add_uuid(help, uuid):
            return " -uuid '%s'" % uuid

        def add_pcidevice(help, host):
            return " -pcidevice host='%s'" % host

        def add_kernel(help, filename):
            return " -kernel '%s'" % filename

        def add_initrd(help, filename):
            return " -initrd '%s'" % filename

        def add_kernel_cmdline(help, cmdline):
            return " -append %s" % cmdline

        def add_testdev(help, filename):
            return (" -chardev file,id=testlog,path=%s"
                    " -device testdev,chardev=testlog" % filename)

        def add_no_hpet(help):
            if has_option(help, "no-hpet"):
                return " -no-hpet"
            else:
                return ""

        # End of command line option wrappers

        if name is None: name = self.name
        if params is None: params = self.params
        if root_dir is None: root_dir = self.root_dir

        qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
                                                              "qemu"))
        # Get the output of 'qemu -help' (log a message in case this call never
        # returns or causes some other kind of trouble)
        logging.debug("Getting output of 'qemu -help'")
        help = commands.getoutput("%s -help" % qemu_binary)

        # Start constructing the qemu command
        qemu_cmd = ""
        # Set the X11 display parameter if requested
        if params.get("x11_display"):
            qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
        # Add the qemu binary
        qemu_cmd += qemu_binary
        # Add the VM's name
        qemu_cmd += add_name(help, name)
        # Add monitors
        for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
            monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
            monitor_filename = self.get_monitor_filename(monitor_name)
            if monitor_params.get("monitor_type") == "qmp":
                qemu_cmd += add_qmp_monitor(help, monitor_filename)
            else:
                qemu_cmd += add_human_monitor(help, monitor_filename)

        # Add serial console redirection
        qemu_cmd += add_serial(help, self.get_serial_console_filename())

        for image_name in kvm_utils.get_sub_dict_names(params, "images"):
            image_params = kvm_utils.get_sub_dict(params, image_name)
            if image_params.get("boot_drive") == "no":
                continue
            qemu_cmd += add_drive(help,
                                  get_image_filename(image_params, root_dir),
                                  image_params.get("drive_index"),
                                  image_params.get("drive_format"),
                                  image_params.get("drive_cache"),
                                  image_params.get("drive_werror"),
                                  image_params.get("drive_serial"),
                                  image_params.get("image_snapshot") == "yes",
                                  image_params.get("image_boot") == "yes")

        redirs = []
        for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
            redir_params = kvm_utils.get_sub_dict(params, redir_name)
            guest_port = int(redir_params.get("guest_port"))
            host_port = self.redirs.get(guest_port)
            redirs += [(host_port, guest_port)]

        vlan = 0
        for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
            nic_params = kvm_utils.get_sub_dict(params, nic_name)
            # Handle the '-net nic' part
            mac = self.get_mac_address(vlan)
            qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
                                self.netdev_id[vlan],
                                nic_params.get("nic_extra_params"))
            # Handle the '-net tap' or '-net user' part
            script = nic_params.get("nic_script")
            downscript = nic_params.get("nic_downscript")
            tftp = nic_params.get("tftp")
            if script:
                script = kvm_utils.get_path(root_dir, script)
            if downscript:
                downscript = kvm_utils.get_path(root_dir, downscript)
            if tftp:
                tftp = kvm_utils.get_path(root_dir, tftp)
            qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
                                self.get_ifname(vlan),
                                script, downscript, tftp,
                                nic_params.get("bootp"), redirs,
                                self.netdev_id[vlan],
                                nic_params.get("netdev_extra_params"))
            # Proceed to next NIC
            vlan += 1

        mem = params.get("mem")
        if mem:
            qemu_cmd += add_mem(help, mem)

        smp = params.get("smp")
        if smp:
            qemu_cmd += add_smp(help, smp)

        cdroms = kvm_utils.get_sub_dict_names(params, "cdroms")
        for cdrom in cdroms:
            cdrom_params = kvm_utils.get_sub_dict(params, cdrom)
            iso = cdrom_params.get("cdrom")
            if iso:
                qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso),
                                      cdrom_params.get("drive_index"))

        # We may want to add {floppy_otps} parameter for -fda
        # {fat:floppy:}/path/. However vvfat is not usually recommended.
        floppy = params.get("floppy")
        if floppy:
            floppy = kvm_utils.get_path(root_dir, floppy)
            qemu_cmd += add_floppy(help, floppy)

        tftp = params.get("tftp")
        if tftp:
            tftp = kvm_utils.get_path(root_dir, tftp)
            qemu_cmd += add_tftp(help, tftp)

        bootp = params.get("bootp")
        if bootp:
            qemu_cmd += add_bootp(help, bootp)

        kernel = params.get("kernel")
        if kernel:
            kernel = kvm_utils.get_path(root_dir, kernel)
            qemu_cmd += add_kernel(help, kernel)

        kernel_cmdline = params.get("kernel_cmdline")
        if kernel_cmdline:
            qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)

        initrd = params.get("initrd")
        if initrd:
            initrd = kvm_utils.get_path(root_dir, initrd)
            qemu_cmd += add_initrd(help, initrd)

        for host_port, guest_port in redirs:
            qemu_cmd += add_tcp_redir(help, host_port, guest_port)

        if params.get("display") == "vnc":
            qemu_cmd += add_vnc(help, self.vnc_port)
        elif params.get("display") == "sdl":
            qemu_cmd += add_sdl(help)
        elif params.get("display") == "nographic":
            qemu_cmd += add_nographic(help)

        if params.get("uuid") == "random":
            qemu_cmd += add_uuid(help, self.uuid)
        elif params.get("uuid"):
            qemu_cmd += add_uuid(help, params.get("uuid"))

        if params.get("testdev") == "yes":
            qemu_cmd += add_testdev(help, self.get_testlog_filename())

        if params.get("disable_hpet") == "yes":
            qemu_cmd += add_no_hpet(help)

        # If the PCI assignment step went OK, add each one of the PCI assigned
        # devices to the qemu command line.
        if self.pci_assignable:
            for pci_id in self.pa_pci_ids:
                qemu_cmd += add_pcidevice(help, pci_id)

        extra_params = params.get("extra_params")
        if extra_params:
            qemu_cmd += " %s" % extra_params

        return qemu_cmd
Example #32
0
def run_whql_submission(test, params, env):
    """
    WHQL submission test:
    1) Log into the client machines and into a DTM server machine
    2) Copy the automation program binary (dsso_test_binary) to the server machine
    3) Run the automation program
    4) Pass the program all relevant parameters (e.g. device_data)
    5) Wait for the program to terminate
    6) Parse and report job results
    (logs and HTML reports are placed in test.debugdir)

    @param test: kvm test object
    @param params: Dictionary with the test parameters
    @param env: Dictionary with test environment.
    """
    # Log into all client VMs
    login_timeout = int(params.get("login_timeout", 360))
    vms = []
    sessions = []
    for vm_name in params.objects("vms"):
        vms.append(env.get_vm(vm_name))
        vms[-1].verify_alive()
        sessions.append(vms[-1].wait_for_login(timeout=login_timeout))

    # Make sure all NICs of all client VMs are up
    for vm in vms:
        nics = vm.params.objects("nics")
        for nic_index in range(len(nics)):
            s = vm.wait_for_login(nic_index, 600)
            s.close()

    # Collect parameters
    server_address = params.get("server_address")
    server_shell_port = int(params.get("server_shell_port"))
    server_file_transfer_port = int(params.get("server_file_transfer_port"))
    server_studio_path = params.get(
        "server_studio_path", "%programfiles%\\ "
        "Microsoft Driver Test Manager\\Studio")
    dsso_test_binary = params.get("dsso_test_binary",
                                  "deps/whql_submission_15.exe")
    dsso_test_binary = kvm_utils.get_path(test.bindir, dsso_test_binary)
    dsso_delete_machine_binary = params.get("dsso_delete_machine_binary",
                                            "deps/whql_delete_machine_15.exe")
    dsso_delete_machine_binary = kvm_utils.get_path(
        test.bindir, dsso_delete_machine_binary)
    test_timeout = float(params.get("test_timeout", 600))

    # Copy dsso binaries to the server
    for filename in dsso_test_binary, dsso_delete_machine_binary:
        rss_file_transfer.upload(server_address,
                                 server_file_transfer_port,
                                 filename,
                                 server_studio_path,
                                 timeout=60)

    # Open a shell session with the server
    server_session = kvm_utils.remote_login("nc", server_address,
                                            server_shell_port, "", "",
                                            sessions[0].prompt,
                                            sessions[0].linesep)
    server_session.set_status_test_command(sessions[0].status_test_command)

    # Get the computer names of the server and clients
    cmd = "echo %computername%"
    server_name = server_session.cmd_output(cmd).strip()
    client_names = [session.cmd_output(cmd).strip() for session in sessions]

    # Delete all client machines from the server's data store
    server_session.cmd("cd %s" % server_studio_path)
    for client_name in client_names:
        cmd = "%s %s %s" % (os.path.basename(dsso_delete_machine_binary),
                            server_name, client_name)
        server_session.cmd(cmd, print_func=logging.debug)

    # Reboot the client machines
    sessions = kvm_utils.parallel(
        (vm.reboot, (session, )) for vm, session in zip(vms, sessions))

    # Check the NICs again
    for vm in vms:
        nics = vm.params.objects("nics")
        for nic_index in range(len(nics)):
            s = vm.wait_for_login(nic_index, 600)
            s.close()

    # Run whql_pre_command and close the sessions
    if params.get("whql_pre_command"):
        for session in sessions:
            session.cmd(params.get("whql_pre_command"),
                        int(params.get("whql_pre_command_timeout", 600)))
            session.close()

    # Run the automation program on the server
    pool_name = "%s_pool" % client_names[0]
    submission_name = "%s_%s" % (client_names[0],
                                 params.get("submission_name"))
    cmd = "%s %s %s %s %s %s" % (os.path.basename(dsso_test_binary),
                                 server_name, pool_name, submission_name,
                                 test_timeout, " ".join(client_names))
    server_session.sendline(cmd)

    # Helper function: wait for a given prompt and raise an exception if an
    # error occurs
    def find_prompt(prompt):
        m, o = server_session.read_until_last_line_matches(
            [prompt, server_session.prompt],
            print_func=logging.info,
            timeout=600)
        if m != 0:
            errors = re.findall("^Error:.*$", o, re.I | re.M)
            if errors:
                raise error.TestError(errors[0])
            else:
                raise error.TestError("Error running automation program: "
                                      "could not find '%s' prompt" % prompt)

    # Tell the automation program which device to test
    find_prompt("Device to test:")
    server_session.sendline(params.get("test_device"))

    # Tell the automation program which jobs to run
    find_prompt("Jobs to run:")
    server_session.sendline(params.get("job_filter", ".*"))

    # Set submission DeviceData
    find_prompt("DeviceData name:")
    for dd in params.objects("device_data"):
        dd_params = params.object_params(dd)
        if dd_params.get("dd_name") and dd_params.get("dd_data"):
            server_session.sendline(dd_params.get("dd_name"))
            server_session.sendline(dd_params.get("dd_data"))
    server_session.sendline()

    # Set submission descriptors
    find_prompt("Descriptor path:")
    for desc in params.objects("descriptors"):
        desc_params = params.object_params(desc)
        if desc_params.get("desc_path"):
            server_session.sendline(desc_params.get("desc_path"))
    server_session.sendline()

    # Set machine dimensions for each client machine
    for vm_name in params.objects("vms"):
        vm_params = params.object_params(vm_name)
        find_prompt(r"Dimension name\b.*:")
        for dp in vm_params.objects("dimensions"):
            dp_params = vm_params.object_params(dp)
            if dp_params.get("dim_name") and dp_params.get("dim_value"):
                server_session.sendline(dp_params.get("dim_name"))
                server_session.sendline(dp_params.get("dim_value"))
        server_session.sendline()

    # Set extra parameters for tests that require them (e.g. NDISTest)
    for vm_name in params.objects("vms"):
        vm_params = params.object_params(vm_name)
        find_prompt(r"Parameter name\b.*:")
        for dp in vm_params.objects("device_params"):
            dp_params = vm_params.object_params(dp)
            if dp_params.get("dp_name") and dp_params.get("dp_regex"):
                server_session.sendline(dp_params.get("dp_name"))
                server_session.sendline(dp_params.get("dp_regex"))
                # Make sure the prompt appears again (if the device isn't found
                # the automation program will terminate)
                find_prompt(r"Parameter name\b.*:")
        server_session.sendline()

    # Wait for the automation program to terminate
    try:
        o = server_session.read_up_to_prompt(print_func=logging.info,
                                             timeout=test_timeout + 300)
        # (test_timeout + 300 is used here because the automation program is
        # supposed to terminate cleanly on its own when test_timeout expires)
        done = True
    except kvm_subprocess.ExpectError, e:
        o = e.output
        done = False
Example #33
0
def preprocess(test, params, env):
    """
    Preprocess all VMs and images according to the instructions in params.
    Also, collect some host information, such as the KVM version.

    @param test: An Autotest test object.
    @param params: A dict containing all VM and image parameters.
    @param env: The environment (a dict-like object).
    """
    # Start tcpdump if it isn't already running
    if not env.has_key("address_cache"):
        env["address_cache"] = {}
    if env.has_key("tcpdump") and not env["tcpdump"].is_alive():
        env["tcpdump"].close()
        del env["tcpdump"]
    if not env.has_key("tcpdump"):
        command = "/usr/sbin/tcpdump -npvi any 'dst port 68'"
        logging.debug("Starting tcpdump (%s)...", command)
        env["tcpdump"] = kvm_subprocess.kvm_tail(
            command=command,
            output_func=_update_address_cache,
            output_params=(env["address_cache"],))
        if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(),
                              0.1, 0.1, 1.0):
            logging.warn("Could not start tcpdump")
            logging.warn("Status: %s" % env["tcpdump"].get_status())
            logging.warn("Output:" + kvm_utils.format_str_for_message(
                env["tcpdump"].get_output()))

    # Destroy and remove VMs that are no longer needed in the environment
    requested_vms = kvm_utils.get_sub_dict_names(params, "vms")
    for key in env.keys():
        vm = env[key]
        if not kvm_utils.is_vm(vm):
            continue
        if not vm.name in requested_vms:
            logging.debug("VM '%s' found in environment but not required for"
                          " test; removing it..." % vm.name)
            vm.destroy()
            del env[key]

    # Execute any pre_commands
    if params.get("pre_command"):
        process_command(test, params, env, params.get("pre_command"),
                        int(params.get("pre_command_timeout", "600")),
                        params.get("pre_command_noncritical") == "yes")

    # Preprocess all VMs and images
    process(test, params, env, preprocess_image, preprocess_vm)

    # Get the KVM kernel module version and write it as a keyval
    logging.debug("Fetching KVM module version...")
    if os.path.exists("/dev/kvm"):
        kvm_version = os.uname()[2]
        try:
            file = open("/sys/module/kvm/version", "r")
            kvm_version = file.read().strip()
            file.close()
        except:
            pass
    else:
        kvm_version = "Unknown"
        logging.debug("KVM module not loaded")
    logging.debug("KVM version: %s" % kvm_version)
    test.write_test_keyval({"kvm_version": kvm_version})

    # Get the KVM userspace version and write it as a keyval
    logging.debug("Fetching KVM userspace version...")
    qemu_path = kvm_utils.get_path(test.bindir, params.get("qemu_binary",
                                                           "qemu"))
    version_line = commands.getoutput("%s -help | head -n 1" % qemu_path)
    exp = re.compile("[Vv]ersion .*?,")
    match = exp.search(version_line)
    if match:
        kvm_userspace_version = " ".join(match.group().split()[1:]).strip(",")
    else:
        kvm_userspace_version = "Unknown"
        logging.debug("Could not fetch KVM userspace version")
    logging.debug("KVM userspace version: %s" % kvm_userspace_version)
    test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version})