Exemple #1
0
def run_shutdown(test, params, env):
    """
    KVM shutdown test:
    1) Log into a guest
    2) Send a shutdown command to the guest
    3) Wait until it's down

    @param test: kvm test object
    @param params: Dictionary with the test parameters
    @param env: Dictionary with test environment
    """
    vm = kvm_utils.env_get_vm(env, 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; Test requires a living VM")

    logging.info("Waiting for guest to be up...")

    session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest")

    logging.info("Logged in")

    # Send the VM's shutdown command
    session.sendline(vm.get_params().get("cmd_shutdown"))
    session.close()

    logging.info("Shutdown command sent; waiting for guest to go down...")

    if not kvm_utils.wait_for(vm.is_dead, 240, 0, 1):
        raise error.TestFail("Guest refuses to go down")

    logging.info("Guest is down")
def wait_for_login(vm, nic_index=0, timeout=240, start=0, step=2, serial=None):
    """
    Try logging into a VM repeatedly.  Stop on success or when timeout expires.

    @param vm: VM object.
    @param nic_index: Index of NIC to access in the VM.
    @param timeout: Time to wait before giving up.
    @param serial: Whether to use a serial connection instead of a remote
            (ssh, rss) one.
    @return: A shell session object.
    """
    type = 'remote'
    if serial:
        type = 'serial'
        logging.info("Trying to log into guest %s using serial connection,"
                     " timeout %ds", vm.name, timeout)
        session = kvm_utils.wait_for(lambda: vm.serial_login(), timeout,
                                     start, step)
    else:
        logging.info("Trying to log into guest %s using remote connection,"
                     " timeout %ds", vm.name, timeout)
        session = kvm_utils.wait_for(lambda: vm.remote_login(
                  nic_index=nic_index), timeout, start, step)
    if not session:
        raise error.TestFail("Could not log into guest %s using %s connection" %
                             (vm.name, type))
    logging.info("Logged into guest %s using %s connection", vm.name, type)
    return session
Exemple #3
0
    def destroy(self, gracefully=True):
        """
        Destroy the VM.

        If gracefully is True, first attempt to shutdown the VM with a shell
        command.  Then, attempt to destroy the VM via the monitor with a 'quit'
        command.  If that fails, send SIGKILL to the qemu process.

        @param gracefully: Whether an attempt will be made to end the VM
                using a shell command before trying to end the qemu process
                with a 'quit' or a kill signal.
        """
        try:
            # Is it already dead?
            if self.is_dead():
                logging.debug("VM is already down")
                return

            logging.debug("Destroying VM with PID %s...", self.get_pid())

            if gracefully and self.params.get("shutdown_command"):
                # Try to destroy with shell command
                logging.debug("Trying to shutdown VM with shell command...")
                session = self.remote_login()
                if session:
                    try:
                        # Send the shutdown command
                        session.sendline(self.params.get("shutdown_command"))
                        logging.debug("Shutdown command sent; waiting for VM "
                                      "to go down...")
                        if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
                            logging.debug("VM is down, freeing mac address.")
                            return
                    finally:
                        session.close()

            if self.monitor:
                # Try to destroy with a monitor command
                logging.debug("Trying to kill VM with monitor command...")
                try:
                    self.monitor.quit()
                except kvm_monitor.MonitorError, e:
                    logging.warn(e)
                else:
                    # Wait for the VM to be really dead
                    if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
                        logging.debug("VM is down")
                        return

            # If the VM isn't dead yet...
            logging.debug("Cannot quit normally; sending a kill to close the "
                          "deal...")
            kvm_utils.kill_process_tree(self.process.get_pid(), 9)
            # Wait for the VM to be really dead
            if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
                logging.debug("VM is down")
                return

            logging.error("Process %s is a zombie!" % self.process.get_pid())
Exemple #4
0
    def destroy(self, gracefully=True):
        """
        Destroy the VM.

        If gracefully is True, first attempt to kill the VM via SSH/Telnet
        with a shutdown command. Then, attempt to destroy the VM via the
        monitor with a 'quit' command. If that fails, send SIGKILL to the
        qemu process.

        @param gracefully: Whether an attempt will be made to end the VM
                using monitor command before trying to kill the qemu process
                or not.
        """
        # Is it already dead?
        if self.is_dead():
            logging.debug("VM is already down")
            if self.process:
                self.process.close()
            return

        logging.debug("Destroying VM with PID %d..." % self.process.get_pid())

        if gracefully and self.params.get("cmd_shutdown"):
            # Try to destroy with SSH command
            logging.debug("Trying to shutdown VM with SSH command...")
            (status, output) = self.ssh(self.params.get("cmd_shutdown"))
            # Was the command sent successfully?
            if status == 0:
                logging.debug("Shutdown command sent; waiting for VM to go "
                              "down...")
                if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
                    logging.debug("VM is down")
                    self.process.close()
                    return

        # Try to destroy with a monitor command
        logging.debug("Trying to kill VM with monitor command...")
        (status, output) = self.send_monitor_cmd("quit", block=False)
        # Was the command sent successfully?
        if status == 0:
            # Wait for the VM to be really dead
            if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
                logging.debug("VM is down")
                self.process.close()
                return

        # If the VM isn't dead yet...
        logging.debug("Cannot quit normally; sending a kill to close the "
                      "deal...")
        kvm_utils.safe_kill(self.process.get_pid(), 9)
        # Wait for the VM to be really dead
        if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
            logging.debug("VM is down")
            self.process.close()
            return

        logging.error("Process %s is a zombie!" % self.process.get_pid())
        self.process.close()
def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0,
           timeout=240):
    """
    Reboot the VM and wait for it to come back up by trying to log in until
    timeout expires.

    @param vm: VM object.
    @param session: A shell session object.
    @param method: Reboot method.  Can be "shell" (send a shell reboot
            command) or "system_reset" (send a system_reset monitor command).
    @param nic_index: Index of NIC to access in the VM, when logging in after
            rebooting.
    @param timeout: Time to wait before giving up (after rebooting).
    @return: A new shell session object.
    """
    if method == "shell":
        # Send a reboot command to the guest's shell
        session.sendline(vm.get_params().get("reboot_command"))
        logging.info("Reboot command sent. Waiting for guest to go down...")
    elif method == "system_reset":
        # Sleep for a while before sending the command
        time.sleep(sleep_before_reset)
        # Clear the event list of all QMP monitors
        monitors = [m for m in vm.monitors if m.protocol == "qmp"]
        for m in monitors:
            m.clear_events()
        # Send a system_reset monitor command
        vm.monitor.cmd("system_reset")
        logging.info("Monitor command system_reset sent. Waiting for guest to "
                     "go down...")
        # Look for RESET QMP events
        time.sleep(1)
        for m in monitors:
            if not m.get_event("RESET"):
                raise error.TestFail("RESET QMP event not received after "
                                     "system_reset (monitor '%s')" % m.name)
            else:
                logging.info("RESET QMP event received")
    else:
        logging.error("Unknown reboot method: %s", method)

    # Wait for the session to become unresponsive and close it
    if not kvm_utils.wait_for(lambda: not session.is_responsive(timeout=30),
                              120, 0, 1):
        raise error.TestFail("Guest refuses to go down")
    session.close()

    # Try logging into the guest until timeout expires
    logging.info("Guest is down. Waiting for it to go up again, timeout %ds",
                 timeout)
    session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index),
                                 timeout, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest after reboot")
    logging.info("Guest is up again")
    return session
Exemple #6
0
    def crash_test(vcpu):
        """
        Trigger a crash dump through sysrq-trigger

        @param vcpu: vcpu which is used to trigger a crash
        """
        session = kvm_test_utils.wait_for_login(vm, 0, timeout, 0, 2)
        session.cmd_output("rm -rf /var/crash/*")

        logging.info("Triggering crash on vcpu %d ...", vcpu)
        crash_cmd = "taskset -c %d echo c > /proc/sysrq-trigger" % vcpu
        session.sendline(crash_cmd)

        if not kvm_utils.wait_for(lambda: not session.is_responsive(), 240, 0,
                                  1):
            raise error.TestFail("Could not trigger crash on vcpu %d" % vcpu)

        logging.info("Waiting for kernel crash dump to complete")
        session = kvm_test_utils.wait_for_login(vm, 0, crash_timeout, 0, 2)

        logging.info("Probing vmcore file...")
        session.cmd("ls -R /var/crash | grep vmcore")
        logging.info("Found vmcore.")

        session.cmd_output("rm -rf /var/crash/*")
def postprocess_vm(test, params, env, name):
    """
    Postprocess a single VM object according to the instructions in params.
    Kill the VM if requested and get a screendump.

    @param test: An Autotest test object.
    @param params: A dict containing VM postprocessing parameters.
    @param env: The environment (a dict-like object).
    @param name: The name of the VM object.
    """
    logging.debug("Postprocessing VM '%s'..." % name)
    vm = kvm_utils.env_get_vm(env, name)
    if vm:
        logging.debug("VM object found in environment")
    else:
        logging.debug("VM object does not exist in environment")
        return

    scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name)
    vm.send_monitor_cmd("screendump %s" % scrdump_filename)

    if params.get("kill_vm") == "yes":
        if not kvm_utils.wait_for(vm.is_dead,
                float(params.get("kill_vm_timeout", 0)), 0.0, 1.0,
                "Waiting for VM to kill itself..."):
            logging.debug("'kill_vm' specified; killing VM...")
        vm.destroy(gracefully = params.get("kill_vm_gracefully") == "yes")
Exemple #8
0
def run_yum_update(test, params, env):
    """
    Runs yum update and yum update kernel on the remote host (yum enabled
    hosts only).

    @param test: kvm test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
    if not vm:
        message = "VM object not found in environment"
        logging.error(message)
        raise error.TestError(message)
    if not vm.is_alive():
        message = "VM seems to be dead; Test requires a living VM"
        logging.error(message)
        raise error.TestError(message)

    logging.info("Logging into guest...")

    session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
    if not session:
        message = "Could not log into guest"
        logging.error(message)
        raise error.TestFail(message)

    logging.info("Logged in")

    internal_yum_update(session, "yum update", params.get("ssh_prompt"), 600)
    internal_yum_update(session, "yum update kernel", params.get("ssh_prompt"), 600)

    session.close()
Exemple #9
0
    def crash_test(vcpu):
        """
        Trigger a crash dump through sysrq-trigger

        @param vcpu: vcpu which is used to trigger a crash
        """
        session = vm.wait_for_login(timeout=timeout)
        session.cmd_output("rm -rf /var/crash/*")

        logging.info("Triggering crash on vcpu %d ...", vcpu)
        crash_cmd = "taskset -c %d echo c > /proc/sysrq-trigger" % vcpu
        session.sendline(crash_cmd)

        if not kvm_utils.wait_for(lambda: not session.is_responsive(), 240, 0,
                                  1):
            raise error.TestFail("Could not trigger crash on vcpu %d" % vcpu)

        logging.info("Waiting for kernel crash dump to complete")
        session = vm.wait_for_login(timeout=crash_timeout)

        logging.info("Probing vmcore file...")
        session.cmd("ls -R /var/crash | grep vmcore")
        logging.info("Found vmcore.")

        session.cmd_output("rm -rf /var/crash/*")
def run_shutdown(test, params, env):
    """
    KVM shutdown test:
    1) Log into a guest
    2) Send a shutdown command to the guest, or issue a system_powerdown
       monitor command (depending on the value of shutdown_method)
    3) Wait until the guest is down

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

    try:
        if params.get("shutdown_method") == "shell":
            # Send a shutdown command to the guest's shell
            session.sendline(vm.get_params().get("shutdown_command"))
            logging.info("Shutdown command sent; waiting for guest to go " "down...")
        elif params.get("shutdown_method") == "system_powerdown":
            # Sleep for a while -- give the guest a chance to finish booting
            time.sleep(float(params.get("sleep_before_powerdown", 10)))
            # Send a system_powerdown monitor command
            vm.monitor.cmd("system_powerdown")
            logging.info("system_powerdown monitor command sent; waiting for " "guest to go down...")

        if not kvm_utils.wait_for(vm.is_dead, 240, 0, 1):
            raise error.TestFail("Guest refuses to go down")

        logging.info("Guest is down")

    finally:
        session.close()
Exemple #11
0
def run_boot(test, params, env):
    """
    KVM reboot test:
    1) Log into a guest
    2) Send a reboot command or a system_reset monitor command (optional)
    3) Wait until the guest is up again
    4) Log into the guest to verify it's up again

    @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)

    try:
        if params.get("reboot_method") == "shell":
            # Send a reboot command to the guest's shell
            session.sendline(vm.get_params().get("reboot_command"))
            logging.info("Reboot command sent; waiting for guest to go "
                         "down...")
        elif params.get("reboot_method") == "system_reset":
            # Sleep for a while -- give the guest a chance to finish booting
            time.sleep(float(params.get("sleep_before_reset", 10)))
            # Send a system_reset monitor command
            vm.send_monitor_cmd("system_reset")
            logging.info("system_reset monitor command sent; waiting for "
                         "guest to go down...")
        else: return

        # Wait for the session to become unresponsive
        if not kvm_utils.wait_for(lambda: not session.is_responsive(),
                                  120, 0, 1):
            raise error.TestFail("Guest refuses to go down")

    finally:
        session.close()

    logging.info("Guest is down; waiting for it to go up again...")

    session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest after reboot")
    session.close()

    logging.info("Guest is up again")
Exemple #12
0
def run_boot(test, params, env):
    """
    KVM reboot test:
    1) Log into a guest
    2) Send a reboot command to the guest
    3) Wait until it's up.
    4) Log into the guest to verify it's up again.

    @param test: kvm test object
    @param params: Dictionary with the test parameters
    @param env: Dictionary with test environment.
    """
    vm = kvm_utils.env_get_vm(env, 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; Test requires a living VM")

    logging.info("Waiting for guest to be up...")

    session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest")

    logging.info("Logged in")

    if params.get("reboot") == "yes":
        # Send the VM's reboot command
        session.sendline(vm.get_params().get("cmd_reboot"))
        logging.info("Reboot command sent; waiting for guest to go down...")

        if not kvm_utils.wait_for(lambda: not session.is_responsive(), 120, 0, 1):
            raise error.TestFail("Guest refuses to go down")

        session.close()

        logging.info("Guest is down; waiting for it to go up again...")

        session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
        if not session:
            raise error.TestFail("Could not log into guest after reboot")

        logging.info("Guest is up again")

    session.close()
def reboot(vm,
           session,
           method="shell",
           sleep_before_reset=10,
           nic_index=0,
           timeout=240):
    """
    Reboot the VM and wait for it to come back up by trying to log in until
    timeout expires.

    @param vm: VM object.
    @param session: A shell session object.
    @param method: Reboot method.  Can be "shell" (send a shell reboot
            command) or "system_reset" (send a system_reset monitor command).
    @param nic_index: Index of NIC to access in the VM, when logging in after
            rebooting.
    @param timeout: Time to wait before giving up (after rebooting).
    @return: A new shell session object.
    """
    if method == "shell":
        # Send a reboot command to the guest's shell
        session.sendline(vm.get_params().get("reboot_command"))
        logging.info("Reboot command sent. Waiting for guest to go down...")
    elif method == "system_reset":
        # Sleep for a while before sending the command
        time.sleep(sleep_before_reset)
        # Clear the event list of all QMP monitors
        monitors = [m for m in vm.monitors if m.protocol == "qmp"]
        for m in monitors:
            m.clear_events()
        # Send a system_reset monitor command
        vm.monitor.cmd("system_reset")
        logging.info("Monitor command system_reset sent. Waiting for guest to "
                     "go down...")
        # Look for RESET QMP events
        time.sleep(1)
        for m in monitors:
            if not m.get_event("RESET"):
                raise error.TestFail("RESET QMP event not received after "
                                     "system_reset (monitor '%s')" % m.name)
            else:
                logging.info("RESET QMP event received")
    else:
        logging.error("Unknown reboot method: %s", method)

    # Wait for the session to become unresponsive and close it
    if not kvm_utils.wait_for(lambda: not session.is_responsive(timeout=30),
                              120, 0, 1):
        raise error.TestFail("Guest refuses to go down")
    session.close()

    # Try logging into the guest until timeout expires
    logging.info("Guest is down. Waiting for it to go up again, timeout %ds",
                 timeout)
    session = vm.wait_for_login(nic_index, timeout=timeout)
    logging.info("Guest is up again")
    return session
def run_mac_change(test, params, env):
    """
    Change MAC address of guest.

    1) Get a new mac from pool, and the old mac addr of guest.
    2) Set new mac in guest and regain new IP.
    3) Re-log into guest with new MAC.

    @param test: KVM test object.
    @param params: Dictionary with the test parameters.
    @param env: Dictionary with test environment.
    """
    timeout = int(params.get("login_timeout", 360))
    vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
    session_serial = kvm_test_utils.wait_for_login(vm, 0, timeout, 0, 2,
                                                   serial=True)
    # This session will be used to assess whether the IP change worked
    session = kvm_test_utils.wait_for_login(vm, 0, timeout, 0, 2)
    old_mac = vm.get_mac_address(0)
    while True:
        vm.free_mac_address(0)
        new_mac = kvm_utils.generate_mac_address(vm.instance, 0)
        if old_mac != new_mac:
            break
    logging.info("The initial MAC address is %s", old_mac)
    interface = kvm_test_utils.get_linux_ifname(session_serial, old_mac)
    # Start change MAC address
    logging.info("Changing MAC address to %s", new_mac)
    change_cmd = ("ifconfig %s down && ifconfig %s hw ether %s && "
                  "ifconfig %s up" % (interface, interface, new_mac, interface))
    session_serial.cmd(change_cmd)

    # Verify whether MAC address was changed to the new one
    logging.info("Verifying the new mac address")
    session_serial.cmd("ifconfig | grep -i %s" % new_mac)

    # Restart `dhclient' to regain IP for new mac address
    logging.info("Restart the network to gain new IP")
    dhclient_cmd = "dhclient -r && dhclient %s" % interface
    session_serial.sendline(dhclient_cmd)

    # Re-log into the guest after changing mac address
    if kvm_utils.wait_for(session.is_responsive, 120, 20, 3):
        # Just warning when failed to see the session become dead,
        # because there is a little chance the ip does not change.
        logging.warn("The session is still responsive, settings may fail.")
    session.close()

    # Re-log into guest and check if session is responsive
    logging.info("Re-log into the guest")
    session = kvm_test_utils.wait_for_login(vm,
              timeout=int(params.get("login_timeout", 360)))
    if not session.is_responsive():
        raise error.TestFail("The new session is not responsive.")

    session.close()
Exemple #15
0
    def read_until_output_matches(self, patterns, filter=lambda x: x,
                                  timeout=60, internal_timeout=None,
                                  print_func=None):
        """
        Read using read_nonblocking until a match is found using match_patterns,
        or until timeout expires. Before attempting to search for a match, the
        data is filtered using the filter function provided.

        @brief: Read from child using read_nonblocking until a pattern
                matches.
        @param patterns: List of strings (regular expression patterns)
        @param filter: Function to apply to the data read from the child before
                attempting to match it against the patterns (should take and
                return a string)
        @param timeout: The duration (in seconds) to wait until a match is
                found
        @param internal_timeout: The timeout to pass to read_nonblocking
        @param print_func: A function to be used to print the data being read
                (should take a string parameter)
        @return: Tuple containing the match index and the data read so far
        @raise ExpectTimeoutError: Raised if timeout expires
        @raise ExpectProcessTerminatedError: Raised if the child process
                terminates while waiting for output
        @raise ExpectError: Raised if an unknown error occurs
        """
        fd = self._get_fd("expect")
        o = ""
        end_time = time.time() + timeout
        while True:
            try:
                r, w, x = select.select([fd], [], [],
                                        max(0, end_time - time.time()))
            except (select.error, TypeError):
                break
            if not r:
                raise ExpectTimeoutError(patterns, o)
            # Read data from child
            data = self.read_nonblocking(internal_timeout)
            if not data:
                break
            # Print it if necessary
            if print_func:
                for line in data.splitlines():
                    print_func(line)
            # Look for patterns
            o += data
            match = self.match_patterns(filter(o), patterns)
            if match is not None:
                return match, o

        # Check if the child has terminated
        if kvm_utils.wait_for(lambda: not self.is_alive(), 5, 0, 0.1):
            raise ExpectProcessTerminatedError(patterns, self.get_status(), o)
        else:
            # This shouldn't happen
            raise ExpectError(patterns, o)
    def read_until_output_matches(self, patterns, filter=lambda x: x,
                                  timeout=30.0, internal_timeout=None,
                                  print_func=None):
        """
        Read using read_nonblocking until a match is found using match_patterns,
        or until timeout expires. Before attempting to search for a match, the
        data is filtered using the filter function provided.

        @brief: Read from child using read_nonblocking until a pattern
                matches.
        @param patterns: List of strings (regular expression patterns)
        @param filter: Function to apply to the data read from the child before
                attempting to match it against the patterns (should take and
                return a string)
        @param timeout: The duration (in seconds) to wait until a match is
                found
        @param internal_timeout: The timeout to pass to read_nonblocking
        @param print_func: A function to be used to print the data being read
                (should take a string parameter)
        @return: Tuple containing the match index and the data read so far
        @raise ExpectTimeoutError: Raised if timeout expires
        @raise ExpectProcessTerminatedError: Raised if the child process
                terminates while waiting for output
        @raise ExpectError: Raised if an unknown error occurs
        """
        fd = self._get_fd("expect")
        o = ""
        end_time = time.time() + timeout
        while True:
            try:
                r, w, x = select.select([fd], [], [],
                                        max(0, end_time - time.time()))
            except (select.error, TypeError):
                break
            if not r:
                raise ExpectTimeoutError(patterns, o)
            # Read data from child
            data = self.read_nonblocking(internal_timeout)
            if not data:
                break
            # Print it if necessary
            if print_func:
                for line in data.splitlines():
                    print_func(line)
            # Look for patterns
            o += data
            match = self.match_patterns(filter(o), patterns)
            if match is not None:
                return match, o

        # Check if the child has terminated
        if kvm_utils.wait_for(lambda: not self.is_alive(), 5, 0, 0.1):
            raise ExpectProcessTerminatedError(patterns, self.get_status(), o)
        else:
            # This shouldn't happen
            raise ExpectError(patterns, o)
Exemple #17
0
def run_mac_change(test, params, env):
    """
    Change MAC address of guest.

    1) Get a new mac from pool, and the old mac addr of guest.
    2) Set new mac in guest and regain new IP.
    3) Re-log into guest with new MAC.

    @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()
    timeout = int(params.get("login_timeout", 360))
    session_serial = vm.wait_for_serial_login(timeout=timeout)
    # This session will be used to assess whether the IP change worked
    session = vm.wait_for_login(timeout=timeout)
    old_mac = vm.get_mac_address(0)
    while True:
        vm.free_mac_address(0)
        new_mac = kvm_utils.generate_mac_address(vm.instance, 0)
        if old_mac != new_mac:
            break
    logging.info("The initial MAC address is %s", old_mac)
    interface = kvm_test_utils.get_linux_ifname(session_serial, old_mac)
    # Start change MAC address
    logging.info("Changing MAC address to %s", new_mac)
    change_cmd = ("ifconfig %s down && ifconfig %s hw ether %s && "
                  "ifconfig %s up" %
                  (interface, interface, new_mac, interface))
    session_serial.cmd(change_cmd)

    # Verify whether MAC address was changed to the new one
    logging.info("Verifying the new mac address")
    session_serial.cmd("ifconfig | grep -i %s" % new_mac)

    # Restart `dhclient' to regain IP for new mac address
    logging.info("Restart the network to gain new IP")
    dhclient_cmd = "dhclient -r && dhclient %s" % interface
    session_serial.sendline(dhclient_cmd)

    # Re-log into the guest after changing mac address
    if kvm_utils.wait_for(session.is_responsive, 120, 20, 3):
        # Just warning when failed to see the session become dead,
        # because there is a little chance the ip does not change.
        logging.warn("The session is still responsive, settings may fail.")
    session.close()

    # Re-log into guest and check if session is responsive
    logging.info("Re-log into the guest")
    session = vm.wait_for_login(timeout=timeout)
    if not session.is_responsive():
        raise error.TestFail("The new session is not responsive.")

    session.close()
Exemple #18
0
def run_linux_s3(test, params, env):
    """
    Suspend a guest Linux OS to memory.

    @param test: kvm test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    vm = kvm_utils.env_get_vm(env, 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; Test requires a living VM")

    logging.info("Waiting for guest to be up...")

    session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest")

    logging.info("Logged in")
    logging.info("Checking that VM supports S3")

    status = session.get_command_status("grep -q mem /sys/power/state")
    if status == None:
        logging.error("Failed to check if S3 exists")
    elif status != 0:
        raise error.TestFail("Guest does not support S3")

    logging.info("Waiting for a while for X to start")
    time.sleep(10)

    src_tty = session.get_command_output("fgconsole").strip()
    logging.info("Current virtual terminal is %s" % src_tty)
    if src_tty not in map(str, range(1, 10)):
        raise error.TestFail("Got a strange current vt (%s)" % src_tty)

    dst_tty = "1"
    if src_tty == "1":
        dst_tty = "2"

    logging.info("Putting VM into S3")
    command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty, src_tty)
    status = session.get_command_status(command, timeout=120)
    if status != 0:
        raise error.TestFail("Suspend to mem failed")

    logging.info("VM resumed after S3")

    session.close()
Exemple #19
0
    def transfer_file(src="guest"):
        """
        Transfer file by scp, use tcpdump to capture packets, then check the
        return string.

        @param src: Source host of transfer file
        @return: Tuple (status, error msg/tcpdump result)
        """
        session2.cmd_output("rm -rf %s" % filename)
        dd_cmd = ("dd if=/dev/urandom of=%s bs=1M count=%s" %
                  (filename, params.get("filesize")))
        logging.info("Creat file in source host, cmd: %s" % dd_cmd)
        tcpdump_cmd = "tcpdump -lep -s 0 tcp -vv port ssh"
        if src == "guest":
            session.cmd_output(dd_cmd, timeout=360)
            tcpdump_cmd += " and src %s" % guest_ip
            copy_files_fun = vm.copy_files_from
        else:
            s, o = commands.getstatusoutput(dd_cmd)
            tcpdump_cmd += " and dst %s" % guest_ip
            copy_files_fun = vm.copy_files_to
        if s != 0:
            return (False, "Fail to create file by dd, cmd: %s" % dd_cmd)

        # only capture the new tcp port after offload setup
        original_tcp_ports = re.findall("tcp.*:(\d+).*%s" % guest_ip,
                                      utils.system_output("/bin/netstat -nap"))
        for i in original_tcp_ports:
            tcpdump_cmd += " and not port %s" % i
        logging.debug("Listen by command: %s" % tcpdump_cmd)
        session2.sendline(tcpdump_cmd)
        if not kvm_utils.wait_for(
                           lambda:session.cmd_status("pgrep tcpdump") == 0, 30):
            return (False, "Tcpdump process wasn't launched")

        logging.info("Start to transfer file")
        if not copy_files_fun(filename, filename):
            return (False, "Child process transfer file failed")
        logging.info("Transfer file completed")
        session.cmd("killall tcpdump")
        try:
            tcpdump_string = session2.read_up_to_prompt(timeout=60)
        except kvm_subprocess.ExpectError:
            return (False, "Fail to read tcpdump's output")

        if not compare_md5sum(filename):
            return (False, "Files' md5sum mismatched")
        return (True, tcpdump_string)
Exemple #20
0
def wait_for_login(vm, nic_index=0, timeout=240):
    """
    Try logging into a VM repeatedly.  Stop on success or when timeout expires.

    @param vm: VM object.
    @param nic_index: Index of NIC to access in the VM.
    @param timeout: Time to wait before giving up.
    @return: A shell session object.
    """
    logging.info("Waiting for guest '%s' to be up..." % vm.name)
    session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index),
                                 timeout, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest '%s'" % vm.name)
    logging.info("Logged in")
    return session
Exemple #21
0
    def pci_del(ignore_failure=False):
        if cmd_type == "pci_add":
            result_domain, bus, slot, function = add_output.split(",")
            domain = int(result_domain.split()[2])
            bus = int(bus.split()[1])
            slot = int(slot.split()[1])
            pci_addr = "%x:%x:%x" % (domain, bus, slot)
            cmd = "pci_del pci_addr=%s" % pci_addr
        elif cmd_type == "device_add":
            cmd = "device_del %s" % device_id
        # This should be replaced by a proper monitor method call
        vm.monitor.cmd(cmd)

        def device_removed():
            after_del = vm.monitor.info("pci")
            return after_del != after_add

        if not kvm_utils.wait_for(device_removed, 10, 0, 1) and not ignore_failure:
            raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (tested_model, cmd))
Exemple #22
0
    def nic_del(vm, nic_id, wait=True):
        """
        Remove the nic from pci tree.

        @vm: VM object
        @id: the nic id
        @wait: Whether need to wait for the guest to unplug the device
        """
        nic_del_cmd = "device_del %s" % nic_id
        vm.monitor.cmd(nic_del_cmd)
        if wait:
            logging.info("waiting for the guest to finish the unplug")
            if not kvm_utils.wait_for(
                    lambda: nic_id not in vm.monitor.info("qtree"),
                    guest_delay, 5, 1):
                logging.error(vm.monitor.info("qtree"))
                raise error.TestError("Device is not unplugged by "
                                      "guest, please check whether the "
                                      "hotplug module was loaded in guest")
Exemple #23
0
    def nic_del(vm, nic_id, wait=True):
        """
        Remove the nic from pci tree.

        @vm: VM object
        @id: the nic id
        @wait: Whether need to wait for the guest to unplug the device
        """
        nic_del_cmd = "device_del %s" % nic_id
        vm.monitor.cmd(nic_del_cmd)
        if wait:
            logging.info("waiting for the guest to finish the unplug")
            if not kvm_utils.wait_for(lambda: nic_id not in
                                      vm.monitor.info("qtree"),
                                      guest_delay, 5 ,1):
                logging.error(vm.monitor.info("qtree"))
                raise error.TestError("Device is not unplugged by "
                                      "guest, please check whether the "
                                      "hotplug module was loaded in guest")
Exemple #24
0
    def pci_del(ignore_failure=False):
        if cmd_type == "pci_add":
            result_domain, bus, slot, function = add_output.split(',')
            domain = int(result_domain.split()[2])
            bus = int(bus.split()[1])
            slot = int(slot.split()[1])
            pci_addr = "%x:%x:%x" % (domain, bus, slot)
            cmd = "pci_del pci_addr=%s" % pci_addr
        elif cmd_type == "device_add":
            cmd = "device_del %s" % device_id
        # This should be replaced by a proper monitor method call
        vm.monitor.cmd(cmd)

        def device_removed():
            after_del = vm.monitor.info("pci")
            return after_del != after_add

        if (not kvm_utils.wait_for(device_removed, 10, 0, 1)
                and not ignore_failure):
            raise error.TestFail("Failed to hot remove PCI device: %s. "
                                 "Monitor command: %s" % (tested_model, cmd))
Exemple #25
0
def run_shutdown(test, params, env):
    """
    KVM shutdown test:
    1) Log into a guest
    2) Send a shutdown command to the guest, or issue a system_powerdown
       monitor command (depending on the value of shutdown_method)
    3) Wait until the guest is down

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

    try:
        if params.get("shutdown_method") == "shell":
            # Send a shutdown command to the guest's shell
            session.sendline(vm.get_params().get("shutdown_command"))
            logging.info("Shutdown command sent; waiting for guest to go "
                         "down...")
        elif params.get("shutdown_method") == "system_powerdown":
            # Sleep for a while -- give the guest a chance to finish booting
            time.sleep(float(params.get("sleep_before_powerdown", 10)))
            # Send a system_powerdown monitor command
            vm.monitor.cmd("system_powerdown")
            logging.info("system_powerdown monitor command sent; waiting for "
                         "guest to go down...")

        if not kvm_utils.wait_for(vm.is_dead, 240, 0, 1):
            raise error.TestFail("Guest refuses to go down")

        logging.info("Guest is down")

    finally:
        session.close()
def run_guest_s4(test, params, env):
    """
    Suspend guest to disk, supports both Linux & Windows OSes.

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

    logging.info("Checking whether guest OS supports suspend to disk (S4)...")
    session.cmd(params.get("check_s4_support_cmd"))

    logging.info("Waiting until all guest OS services are fully started...")
    time.sleep(float(params.get("services_up_timeout", 30)))

    # Start up a program (tcpdump for linux & ping for Windows), as a flag.
    # If the program died after suspend, then fails this testcase.
    test_s4_cmd = params.get("test_s4_cmd")
    session.sendline(test_s4_cmd)
    time.sleep(5)

    # Get the second session to start S4
    session2 = kvm_test_utils.wait_for_login(vm, timeout=timeout)

    # Make sure the background program is running as expected
    check_s4_cmd = params.get("check_s4_cmd")
    session2.cmd(check_s4_cmd)
    logging.info("Launched background command in guest: %s" % test_s4_cmd)

    # Suspend to disk
    logging.info("Starting suspend to disk now...")
    session2.sendline(params.get("set_s4_cmd"))

    # Make sure the VM goes down
    suspend_timeout = 240 + int(params.get("smp")) * 60
    if not kvm_utils.wait_for(vm.is_dead, suspend_timeout, 2, 2):
        raise error.TestFail("VM refuses to go down. Suspend failed.")
    logging.info("VM suspended successfully. Sleeping for a while before "
                 "resuming it.")
    time.sleep(10)

    # Start vm, and check whether the program is still running
    logging.info("Resuming suspended VM...")
    if not vm.create():
        raise error.TestError("Failed to start VM after suspend to disk")

    # Log into the resumed VM
    relogin_timeout = int(params.get("relogin_timeout", 240))
    logging.info("Logging into resumed VM, timeout %s", relogin_timeout)
    session2 = kvm_utils.wait_for(vm.remote_login, relogin_timeout, 0, 2)
    if not session2:
        raise error.TestFail("Could not log into VM after resuming from "
                             "suspend to disk")

    # Check whether the test command is still alive
    logging.info("Checking if background command is still alive...")
    session2.cmd(check_s4_cmd)

    logging.info("VM resumed successfuly after suspend to disk")
    session2.cmd_output(params.get("kill_test_s4_cmd"))
    session.close()
    session2.close()
Exemple #27
0
def run_guest_s4(test, params, env):
    """
    Suspend guest to disk, supports both Linux & Windows OSes.

    @param test: kvm test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    error.base_context("before S4")
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 360))
    session = vm.wait_for_login(timeout=timeout)

    error.context("checking whether guest OS supports S4", logging.info)
    session.cmd(params.get("check_s4_support_cmd"))
    error.context()

    logging.info("Waiting until all guest OS services are fully started...")
    time.sleep(float(params.get("services_up_timeout", 30)))

    # Start up a program (tcpdump for linux & ping for Windows), as a flag.
    # If the program died after suspend, then fails this testcase.
    test_s4_cmd = params.get("test_s4_cmd")
    session.sendline(test_s4_cmd)
    time.sleep(5)

    # Get the second session to start S4
    session2 = vm.wait_for_login(timeout=timeout)

    # Make sure the background program is running as expected
    error.context("making sure background program is running")
    check_s4_cmd = params.get("check_s4_cmd")
    session2.cmd(check_s4_cmd)
    logging.info("Launched background command in guest: %s", test_s4_cmd)
    error.context()
    error.base_context()

    # Suspend to disk
    logging.info("Starting suspend to disk now...")
    session2.sendline(params.get("set_s4_cmd"))

    # Make sure the VM goes down
    error.base_context("after S4")
    suspend_timeout = 240 + int(params.get("smp")) * 60
    if not kvm_utils.wait_for(vm.is_dead, suspend_timeout, 2, 2):
        raise error.TestFail("VM refuses to go down. Suspend failed.")
    logging.info("VM suspended successfully. Sleeping for a while before "
                 "resuming it.")
    time.sleep(10)

    # Start vm, and check whether the program is still running
    logging.info("Resuming suspended VM...")
    vm.create()

    # Log into the resumed VM
    relogin_timeout = int(params.get("relogin_timeout", 240))
    logging.info("Logging into resumed VM, timeout %s", relogin_timeout)
    session2 = vm.wait_for_login(timeout=relogin_timeout)

    # Check whether the test command is still alive
    error.context("making sure background program is still running",
                  logging.info)
    session2.cmd(check_s4_cmd)
    error.context()

    logging.info("VM resumed successfuly after suspend to disk")
    session2.cmd_output(params.get("kill_test_s4_cmd"))
    session.close()
    session2.close()
Exemple #28
0
def run_jumbo(test, params, env):
    """
    Test the RX jumbo frame function of vnics:

    1) Boot the VM.
    2) Change the MTU of guest nics and host taps depending on the NIC model.
    3) Add the static ARP entry for guest NIC.
    4) Wait for the MTU ok.
    5) Verify the path MTU using ping.
    6) Ping the guest with large frames.
    7) Increment size ping.
    8) Flood ping the guest with large frames.
    9) Verify the path MTU.
    10) Recover the MTU.

    @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)))
    mtu = params.get("mtu", "1500")
    flood_time = params.get("flood_time", "300")
    max_icmp_pkt_size = int(mtu) - 28

    ifname = vm.get_ifname(0)
    ip = vm.get_address(0)
    if ip is None:
        raise error.TestError("Could not get the IP address")

    try:
        # Environment preparation
        ethname = kvm_test_utils.get_linux_ifname(session, vm.get_mac_address(0))

        logging.info("Changing the MTU of guest ...")
        guest_mtu_cmd = "ifconfig %s mtu %s" % (ethname , mtu)
        session.cmd(guest_mtu_cmd)

        logging.info("Chaning the MTU of host tap ...")
        host_mtu_cmd = "ifconfig %s mtu %s" % (ifname, mtu)
        utils.run(host_mtu_cmd)

        logging.info("Add a temporary static ARP entry ...")
        arp_add_cmd = "arp -s %s %s -i %s" % (ip, vm.get_mac_address(0), ifname)
        utils.run(arp_add_cmd)

        def is_mtu_ok():
            s, o = kvm_test_utils.ping(ip, 1, interface=ifname,
                                       packetsize=max_icmp_pkt_size,
                                       hint="do", timeout=2)
            return s == 0

        def verify_mtu():
            logging.info("Verify the path MTU")
            s, o = kvm_test_utils.ping(ip, 10, interface=ifname,
                                       packetsize=max_icmp_pkt_size,
                                       hint="do", timeout=15)
            if s != 0 :
                logging.error(o)
                raise error.TestFail("Path MTU is not as expected")
            if kvm_test_utils.get_loss_ratio(o) != 0:
                logging.error(o)
                raise error.TestFail("Packet loss ratio during MTU "
                                     "verification is not zero")

        def flood_ping():
            logging.info("Flood with large frames")
            kvm_test_utils.ping(ip, interface=ifname,
                                packetsize=max_icmp_pkt_size,
                                flood=True, timeout=float(flood_time))

        def large_frame_ping(count=100):
            logging.info("Large frame ping")
            s, o = kvm_test_utils.ping(ip, count, interface=ifname,
                                       packetsize=max_icmp_pkt_size,
                                       timeout=float(count) * 2)
            ratio = kvm_test_utils.get_loss_ratio(o)
            if ratio != 0:
                raise error.TestFail("Loss ratio of large frame ping is %s" %
                                     ratio)

        def size_increase_ping(step=random.randrange(90, 110)):
            logging.info("Size increase ping")
            for size in range(0, max_icmp_pkt_size + 1, step):
                logging.info("Ping %s with size %s", ip, size)
                s, o = kvm_test_utils.ping(ip, 1, interface=ifname,
                                           packetsize=size,
                                           hint="do", timeout=1)
                if s != 0:
                    s, o = kvm_test_utils.ping(ip, 10, interface=ifname,
                                               packetsize=size,
                                               adaptive=True, hint="do",
                                               timeout=20)

                    if kvm_test_utils.get_loss_ratio(o) > int(params.get(
                                                      "fail_ratio", 50)):
                        raise error.TestFail("Ping loss ratio is greater "
                                             "than 50% for size %s" % size)

        logging.info("Waiting for the MTU to be OK")
        wait_mtu_ok = 10
        if not kvm_utils.wait_for(is_mtu_ok, wait_mtu_ok, 0, 1):
            logging.debug(commands.getoutput("ifconfig -a"))
            raise error.TestError("MTU is not as expected even after %s "
                                  "seconds" % wait_mtu_ok)

        # Functional Test
        verify_mtu()
        large_frame_ping()
        size_increase_ping()

        # Stress test
        flood_ping()
        verify_mtu()

    finally:
        # Environment clean
        session.close()
        logging.info("Removing the temporary ARP entry")
        utils.run("arp -d %s -i %s" % (ip, ifname))
Exemple #29
0
 def wait_for_migration():
     if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,
                               "Waiting for migration to finish..."):
         raise error.TestFail("Timeout expired while waiting for migration "
                              "to finish")
Exemple #30
0
def run_nic_hotplug(test, params, env):
    """
    Test hotplug of NIC devices

    1) Boot up guest with one nic
    2) Add a host network device through monitor cmd and check if it's added
    3) Add nic device through monitor cmd and check if it's added
    4) Check if new interface gets ip address
    5) Disable primary link of guest
    6) Ping guest new ip from host
    7) Delete nic device and netdev
    8) Re-enable primary link of guest

    @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"))
    timeout = int(params.get("login_timeout", 360))
    guest_delay = int(params.get("guest_delay", 20))
    session = kvm_test_utils.wait_for_login(vm, timeout=timeout)
    romfile = params.get("romfile")

    # Modprobe the module if specified in config file
    module = params.get("modprobe_module")
    if module:
        session.get_command_output("modprobe %s" % module)

    def netdev_add(vm):
        netdev_id = kvm_utils.generate_random_id()
        attach_cmd = ("netdev_add tap,id=%s" % netdev_id)
        nic_script = params.get("nic_script")
        if nic_script:
            attach_cmd += ",script=%s" % kvm_utils.get_path(
                vm.root_dir, 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

    def netdev_del(vm, n_id):
        vm.monitor.cmd("netdev_del %s" % n_id)

        network = vm.monitor.info("network")
        if n_id in network:
            logging.error(network)
            raise error.TestError("Fail to remove netdev %s" % n_id)

    def nic_add(vm, model, netdev_id, mac, rom=None):
        """
        Add a nic to virtual machine

        @vm: VM object
        @model: nic model
        @netdev_id: id of netdev
        @mac: Mac address of new nic
        @rom: Rom file
        """
        nic_id = kvm_utils.generate_random_id()
        if model == "virtio":
            model = "virtio-net-pci"
        device_add_cmd = "device_add %s,netdev=%s,mac=%s,id=%s" % (
            model, netdev_id, mac, nic_id)
        if rom:
            device_add_cmd += ",romfile=%s" % rom
        logging.info("Adding nic through %s", device_add_cmd)
        vm.monitor.cmd(device_add_cmd)

        qdev = vm.monitor.info("qtree")
        if not nic_id in qdev:
            logging.error(qdev)
            raise error.TestFail("Device %s was not plugged into qdev"
                                 "tree" % nic_id)
        else:
            return nic_id

    def nic_del(vm, nic_id, wait=True):
        """
        Remove the nic from pci tree.

        @vm: VM object
        @id: the nic id
        @wait: Whether need to wait for the guest to unplug the device
        """
        nic_del_cmd = "device_del %s" % nic_id
        vm.monitor.cmd(nic_del_cmd)
        if wait:
            logging.info("waiting for the guest to finish the unplug")
            if not kvm_utils.wait_for(
                    lambda: nic_id not in vm.monitor.info("qtree"),
                    guest_delay, 5, 1):
                logging.error(vm.monitor.info("qtree"))
                raise error.TestError("Device is not unplugged by "
                                      "guest, please check whether the "
                                      "hotplug module was loaded in guest")

    logging.info("Attach a virtio nic to vm")
    mac = kvm_utils.generate_mac_address(vm.instance, 1)
    if not mac:
        mac = "00:00:02:00:00:02"
    netdev_id = netdev_add(vm)
    device_id = nic_add(vm, "virtio", netdev_id, mac, romfile)

    if "Win" not in params.get("guest_name", ""):
        session.sendline("dhclient %s &" %
                         kvm_test_utils.get_linux_ifname(session, mac))

    logging.info("Shutting down the primary link")
    vm.monitor.cmd("set_link %s down" % vm.netdev_id[0])

    try:
        logging.info("Waiting for new nic's ip address acquisition...")
        if not kvm_utils.wait_for(
                lambda: (vm.address_cache.get(mac) is not None), 10, 1):
            raise error.TestFail("Could not get ip address of new nic")
        ip = vm.address_cache.get(mac)
        if not kvm_utils.verify_ip_address_ownership(ip, mac):
            raise error.TestFail("Could not verify the ip address of new nic")
        else:
            logging.info("Got the ip address of new nic: %s", ip)

        logging.info("Ping test the new nic ...")
        s, o = kvm_test_utils.ping(ip, 100)
        if s != 0:
            logging.error(o)
            raise error.TestFail("New nic failed ping test")

        logging.info("Detaching a virtio nic from vm")
        nic_del(vm, device_id)
        netdev_del(vm, netdev_id)

    finally:
        vm.free_mac_address(1)
        logging.info("Re-enabling the primary link")
        vm.monitor.cmd("set_link %s up" % vm.netdev_id[0])
Exemple #31
0
            tcpdump_cmd += " and dst %s" % guest_ip
            copy_files_from = vm.copy_files_to
            try:
                utils.system(dd_cmd)
            except error.CmdError, e:
                return failure

        # only capture the new tcp port after offload setup
        original_tcp_ports = re.findall(
            "tcp.*:(\d+).*%s" % guest_ip,
            utils.system_output("/bin/netstat -nap"))
        for i in original_tcp_ports:
            tcpdump_cmd += " and not port %s" % i
        logging.debug("Listen using command: %s", tcpdump_cmd)
        session2.sendline(tcpdump_cmd)
        if not kvm_utils.wait_for(
                lambda: session.cmd_status("pgrep tcpdump") == 0, 30):
            return (False, "Tcpdump process wasn't launched")

        logging.info("Start to transfer file")
        try:
            copy_files_from(filename, filename)
        except kvm_utils.SCPError, e:
            return (False, "File transfer failed (%s)" % e)
        logging.info("Transfer file completed")
        session.cmd("killall tcpdump")
        try:
            tcpdump_string = session2.read_up_to_prompt(timeout=60)
        except kvm_subprocess.ExpectError:
            return (False, "Fail to read tcpdump's output")

        if not compare_md5sum(filename):
def migrate(vm,
            env=None,
            mig_timeout=3600,
            mig_protocol="tcp",
            mig_cancel=False,
            offline=False,
            stable_check=False,
            clean=False,
            save_path=None,
            dest_host='localhost',
            mig_port=None):
    """
    Migrate a VM locally and re-register it in the environment.

    @param vm: The VM to migrate.
    @param env: The environment dictionary.  If omitted, the migrated VM will
            not be registered.
    @param mig_timeout: timeout value for migration.
    @param mig_protocol: migration protocol
    @param mig_cancel: Test migrate_cancel or not when protocol is tcp.
    @param dest_host: Destination host (defaults to 'localhost').
    @param mig_port: Port that will be used for migration.
    @return: The post-migration VM, in case of same host migration, True in
            case of multi-host migration.
    """
    def mig_finished():
        o = vm.monitor.info("migrate")
        if isinstance(o, str):
            return "status: active" not in o
        else:
            return o.get("status") != "active"

    def mig_succeeded():
        o = vm.monitor.info("migrate")
        if isinstance(o, str):
            return "status: completed" in o
        else:
            return o.get("status") == "completed"

    def mig_failed():
        o = vm.monitor.info("migrate")
        if isinstance(o, str):
            return "status: failed" in o
        else:
            return o.get("status") == "failed"

    def mig_cancelled():
        o = vm.monitor.info("migrate")
        if isinstance(o, str):
            return ("Migration status: cancelled" in o
                    or "Migration status: canceled" in o)
        else:
            return (o.get("status") == "cancelled"
                    or o.get("status") == "canceled")

    def wait_for_migration():
        if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,
                                  "Waiting for migration to finish..."):
            raise error.TestFail("Timeout expired while waiting for migration "
                                 "to finish")

    if dest_host == 'localhost':
        dest_vm = vm.clone()

    if (dest_host == 'localhost') and stable_check:
        # Pause the dest vm after creation
        dest_vm.params['extra_params'] = (
            dest_vm.params.get('extra_params', '') + ' -S')

    if dest_host == 'localhost':
        dest_vm.create(migration_mode=mig_protocol, mac_source=vm)

    try:
        try:
            if mig_protocol == "tcp":
                if dest_host == 'localhost':
                    uri = "tcp:localhost:%d" % dest_vm.migration_port
                else:
                    uri = 'tcp:%s:%d' % (dest_host, mig_port)
            elif mig_protocol == "unix":
                uri = "unix:%s" % dest_vm.migration_file
            elif mig_protocol == "exec":
                uri = '"exec:nc localhost %s"' % dest_vm.migration_port

            if offline:
                vm.monitor.cmd("stop")
            vm.monitor.migrate(uri)

            if mig_cancel:
                time.sleep(2)
                vm.monitor.cmd("migrate_cancel")
                if not kvm_utils.wait_for(
                        mig_cancelled, 60, 2, 2, "Waiting for migration "
                        "cancellation"):
                    raise error.TestFail("Failed to cancel migration")
                if offline:
                    vm.monitor.cmd("cont")
                if dest_host == 'localhost':
                    dest_vm.destroy(gracefully=False)
                return vm
            else:
                wait_for_migration()
                if (dest_host == 'localhost') and stable_check:
                    save_path = None or "/tmp"
                    save1 = os.path.join(save_path, "src")
                    save2 = os.path.join(save_path, "dst")

                    vm.save_to_file(save1)
                    dest_vm.save_to_file(save2)

                    # Fail if we see deltas
                    md5_save1 = utils.hash_file(save1)
                    md5_save2 = utils.hash_file(save2)
                    if md5_save1 != md5_save2:
                        raise error.TestFail("Mismatch of VM state before "
                                             "and after migration")

                if (dest_host == 'localhost') and offline:
                    dest_vm.monitor.cmd("cont")
        except:
            if dest_host == 'localhost':
                dest_vm.destroy()
            raise

    finally:
        if (dest_host == 'localhost') and stable_check and clean:
            logging.debug("Cleaning the state files")
            if os.path.isfile(save1):
                os.remove(save1)
            if os.path.isfile(save2):
                os.remove(save2)

    # Report migration status
    if mig_succeeded():
        logging.info("Migration finished successfully")
    elif mig_failed():
        raise error.TestFail("Migration failed")
    else:
        raise error.TestFail("Migration ended with unknown status")

    if dest_host == 'localhost':
        if "paused" in dest_vm.monitor.info("status"):
            logging.debug("Destination VM is paused, resuming it...")
            dest_vm.monitor.cmd("cont")

    # Kill the source VM
    vm.destroy(gracefully=False)

    # Replace the source VM with the new cloned VM
    if (dest_host == 'localhost') and (env is not None):
        env.register_vm(vm.name, dest_vm)

    # Return the new cloned VM
    if dest_host == 'localhost':
        return dest_vm
    else:
        return vm
Exemple #33
0
def run_stress_boot(tests, params, env):
    """
    Boots VMs until one of them becomes unresponsive, and records the maximum
    number of VMs successfully started:
    1) boot the first vm
    2) boot the second vm cloned from the first vm, check whether it boots up
       and all booted vms can ssh-login
    3) go on until cannot create VM anymore or cannot allocate memory for VM

    @param test:   kvm test object
    @param params: Dictionary with the test parameters
    @param env:    Dictionary with test environment.
    """
    # boot the first vm
    vm = kvm_utils.env_get_vm(env, 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; Test requires a living VM")

    logging.info("Waiting for first guest to be up...")

    session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
    if not session:
        raise error.TestFail("Could not log into first guest")

    num = 2
    vms = []
    sessions = [session]

    # boot the VMs
    while num <= int(params.get("max_vms")):
        try:
            vm_name = "vm" + str(num)

            # clone vm according to the first one
            vm_params = params.copy()
            vm_params["image_snapshot"] = "yes"
            vm_params["kill_vm"] = "yes"
            vm_params["kill_vm_gracefully"] = "no"
            curr_vm = vm.clone(vm_name, vm_params)
            kvm_utils.env_register_vm(env, vm_name, curr_vm)
            params["vms"] += " " + vm_name

            # vms.append(curr_vm)
            logging.info("Booting guest #%d" % num)
            if not curr_vm.create():
                raise error.TestFail("Cannot create VM #%d" % num)

            curr_vm_session = kvm_utils.wait_for(curr_vm.ssh_login, 240, 0, 2)
            if not curr_vm_session:
                raise error.TestFail("Could not log into guest #%d" % num)

            logging.info("Guest #%d boots up successfully" % num)
            sessions.append(curr_vm_session)

            # check whether all previous ssh sessions are responsive
            for i, vm_session in enumerate(sessions):
                if vm_session.get_command_status(params.get("alive_test_cmd")):
                    raise error.TestFail("Session #%d is not responsive" % i)
            num += 1

        except (error.TestFail, OSError):
            for se in sessions:
                se.close()
            logging.info("Total number booted: %d" % (num - 1))
            raise
    else:
        for se in sessions:
            se.close()
        logging.info("Total number booted: %d" % (num - 1))
Exemple #34
0
def run_jumbo(test, params, env):
    """
    Test the RX jumbo frame function of vnics:

    1) Boot the VM.
    2) Change the MTU of guest nics and host taps depending on the NIC model.
    3) Add the static ARP entry for guest NIC.
    4) Wait for the MTU ok.
    5) Verify the path MTU using ping.
    6) Ping the guest with large frames.
    7) Increment size ping.
    8) Flood ping the guest with large frames.
    9) Verify the path MTU.
    10) Recover the MTU.

    @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)))
    mtu = params.get("mtu", "1500")
    flood_time = params.get("flood_time", "300")
    max_icmp_pkt_size = int(mtu) - 28

    ifname = vm.get_ifname(0)
    ip = vm.get_address(0)
    if ip is None:
        raise error.TestError("Could not get the IP address")

    try:
        # Environment preparation
        ethname = kvm_test_utils.get_linux_ifname(session,
                                                  vm.get_mac_address(0))

        logging.info("Changing the MTU of guest ...")
        guest_mtu_cmd = "ifconfig %s mtu %s" % (ethname, mtu)
        session.cmd(guest_mtu_cmd)

        logging.info("Chaning the MTU of host tap ...")
        host_mtu_cmd = "ifconfig %s mtu %s" % (ifname, mtu)
        utils.run(host_mtu_cmd)

        logging.info("Add a temporary static ARP entry ...")
        arp_add_cmd = "arp -s %s %s -i %s" % (ip, vm.get_mac_address(0),
                                              ifname)
        utils.run(arp_add_cmd)

        def is_mtu_ok():
            s, o = kvm_test_utils.ping(ip,
                                       1,
                                       interface=ifname,
                                       packetsize=max_icmp_pkt_size,
                                       hint="do",
                                       timeout=2)
            return s == 0

        def verify_mtu():
            logging.info("Verify the path MTU")
            s, o = kvm_test_utils.ping(ip,
                                       10,
                                       interface=ifname,
                                       packetsize=max_icmp_pkt_size,
                                       hint="do",
                                       timeout=15)
            if s != 0:
                logging.error(o)
                raise error.TestFail("Path MTU is not as expected")
            if kvm_test_utils.get_loss_ratio(o) != 0:
                logging.error(o)
                raise error.TestFail("Packet loss ratio during MTU "
                                     "verification is not zero")

        def flood_ping():
            logging.info("Flood with large frames")
            kvm_test_utils.ping(ip,
                                interface=ifname,
                                packetsize=max_icmp_pkt_size,
                                flood=True,
                                timeout=float(flood_time))

        def large_frame_ping(count=100):
            logging.info("Large frame ping")
            s, o = kvm_test_utils.ping(ip,
                                       count,
                                       interface=ifname,
                                       packetsize=max_icmp_pkt_size,
                                       timeout=float(count) * 2)
            ratio = kvm_test_utils.get_loss_ratio(o)
            if ratio != 0:
                raise error.TestFail("Loss ratio of large frame ping is %s" %
                                     ratio)

        def size_increase_ping(step=random.randrange(90, 110)):
            logging.info("Size increase ping")
            for size in range(0, max_icmp_pkt_size + 1, step):
                logging.info("Ping %s with size %s", ip, size)
                s, o = kvm_test_utils.ping(ip,
                                           1,
                                           interface=ifname,
                                           packetsize=size,
                                           hint="do",
                                           timeout=1)
                if s != 0:
                    s, o = kvm_test_utils.ping(ip,
                                               10,
                                               interface=ifname,
                                               packetsize=size,
                                               adaptive=True,
                                               hint="do",
                                               timeout=20)

                    if kvm_test_utils.get_loss_ratio(o) > int(
                            params.get("fail_ratio", 50)):
                        raise error.TestFail("Ping loss ratio is greater "
                                             "than 50% for size %s" % size)

        logging.info("Waiting for the MTU to be OK")
        wait_mtu_ok = 10
        if not kvm_utils.wait_for(is_mtu_ok, wait_mtu_ok, 0, 1):
            logging.debug(commands.getoutput("ifconfig -a"))
            raise error.TestError("MTU is not as expected even after %s "
                                  "seconds" % wait_mtu_ok)

        # Functional Test
        verify_mtu()
        large_frame_ping()
        size_increase_ping()

        # Stress test
        flood_ping()
        verify_mtu()

    finally:
        # Environment clean
        session.close()
        logging.info("Removing the temporary ARP entry")
        utils.run("arp -d %s -i %s" % (ip, ifname))
Exemple #35
0
def run_unittest(test, params, env):
    """
    KVM RHEL-6 style unit test:
    1) Resume a stopped VM
    2) Wait for VM to terminate
    3) If qemu exited with code = 0, the unittest passed. Otherwise, it failed
    4) Collect all logs generated

    @param test: kvm test object
    @param params: Dictionary with the test parameters
    @param env: Dictionary with test environment
    """
    unittest_dir = os.path.join(test.bindir, 'unittests')
    if not os.path.isdir(unittest_dir):
        raise error.TestError("No unittest dir %s available (did you run the "
                              "build test first?)" % unittest_dir)
    os.chdir(unittest_dir)
    unittest_list = glob.glob('*.flat')
    if not unittest_list:
        raise error.TestError("No unittest files available (did you run the "
                              "build test first?)")
    logging.debug('Flat file list: %s', unittest_list)

    unittest_cfg = os.path.join(unittest_dir, 'unittests.cfg')
    parser = ConfigParser.ConfigParser()
    parser.read(unittest_cfg)
    test_list = parser.sections()

    if not test_list:
        raise error.TestError("No tests listed on config file %s" %
                              unittest_cfg)
    logging.debug('Unit test list: %s', test_list)

    if params.get('test_list'):
        test_list = params.get('test_list').split()
        logging.info('Original test list overriden by user')
        logging.info('User defined unit test list: %s', test_list)

    nfail = 0
    tests_failed = []

    timeout = int(params.get('unittest_timeout', 600))

    extra_params_original = params['extra_params']

    for t in test_list:
        logging.info('Running %s', t)

        flat_file = None
        if parser.has_option(t, 'file'):
            flat_file = parser.get(t, 'file')

        if flat_file is None:
            nfail += 1
            tests_failed.append(t)
            logging.error(
                'Unittest config file %s has section %s but no '
                'mandatory option file', unittest_cfg, t)
            continue

        if flat_file not in unittest_list:
            nfail += 1
            tests_failed.append(t)
            logging.error(
                'Unittest file %s referenced in config file %s but '
                'was not find under the unittest dir', flat_file, unittest_cfg)
            continue

        smp = None
        if parser.has_option(t, 'smp'):
            smp = int(parser.get(t, 'smp'))
            params['smp'] = smp

        extra_params = None
        if parser.has_option(t, 'extra_params'):
            extra_params = parser.get(t, 'extra_params')
            params['extra_params'] += ' %s' % extra_params

        vm_name = params.get("main_vm")
        params['kernel'] = os.path.join(unittest_dir, flat_file)
        testlog_path = os.path.join(test.debugdir, "%s.log" % t)

        try:
            try:
                vm_name = params.get('main_vm')
                kvm_preprocessing.preprocess_vm(test, params, env, vm_name)
                vm = env.get_vm(vm_name)
                vm.create()
                vm.monitor.cmd("cont")
                logging.info(
                    "Waiting for unittest %s to complete, timeout %s, "
                    "output in %s", t, timeout, vm.get_testlog_filename())
                if not kvm_utils.wait_for(vm.is_dead, timeout):
                    raise error.TestFail("Timeout elapsed (%ss)" % timeout)
                # Check qemu's exit status
                status = vm.process.get_status()
                if status != 0:
                    nfail += 1
                    tests_failed.append(t)
                    logging.error("Unit test %s failed", t)
            except Exception, e:
                nfail += 1
                tests_failed.append(t)
                logging.error('Exception happened during %s: %s', t, str(e))
        finally:
            try:
                shutil.copy(vm.get_testlog_filename(), testlog_path)
                logging.info("Unit test log collected and available under %s",
                             testlog_path)
            except (NameError, IOError):
                logging.error("Not possible to collect logs")

        # Restore the extra params so other tests can run normally
        params['extra_params'] = extra_params_original

    if nfail != 0:
        raise error.TestFail("Unit tests failed: %s" % " ".join(tests_failed))
 def wait_for_migration():
     if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,
                               "Waiting for migration to finish..."):
         raise error.TestFail("Timeout expired while waiting for migration "
                              "to finish")
    if not vm:
        return

    scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name)
    try:
        if vm.monitor:
            vm.monitor.screendump(scrdump_filename)
    except kvm_monitor.MonitorError, e:
        logging.warn(e)

    if params.get("kill_vm") == "yes":
        kill_vm_timeout = float(params.get("kill_vm_timeout", 0))
        if kill_vm_timeout:
            logging.debug("'kill_vm' specified; waiting for VM to shut down "
                          "before killing it...")
            kvm_utils.wait_for(vm.is_dead, kill_vm_timeout, 0, 1)
        else:
            logging.debug("'kill_vm' specified; killing VM...")
        vm.destroy(gracefully=params.get("kill_vm_gracefully") == "yes")


def process_command(test, params, env, command, command_timeout,
                    command_noncritical):
    """
    Pre- or post- custom commands to be executed before/after a test is run

    @param test: An Autotest test object.
    @param params: A dict containing all VM and image parameters.
    @param env: The environment (a dict-like object).
    @param command: Command to be run.
    @param command_timeout: Timeout for command execution.
Exemple #38
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()
Exemple #39
0
def run_pci_hotplug(test, params, env):
    """
    Test hotplug of PCI devices.

    (Elements between [] are configurable test parameters)
    1) PCI add a deivce (NIC / block)
    2) Compare output of monitor command 'info pci'.
    3) Compare output of guest command [reference_cmd].
    4) Verify whether pci_model is shown in [pci_find_cmd].
    5) Check whether the newly added PCI device works fine.
    6) PCI delete the device, verify whether could remove the PCI device.

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

    # Modprobe the module if specified in config file
    module = params.get("modprobe_module")
    if module:
        session.cmd("modprobe %s" % module)

    # Get output of command 'info pci' as reference
    info_pci_ref = vm.monitor.info("pci")

    # Get output of command as reference
    reference = session.cmd_output(params.get("reference_cmd"))

    tested_model = params.get("pci_model")
    test_type = params.get("pci_type")
    image_format = params.get("image_format_stg")

    # Probe qemu to verify what is the supported syntax for PCI hotplug
    cmd_output = vm.monitor.cmd("?")
    if len(re.findall("\ndevice_add", cmd_output)) > 0:
        cmd_type = "device_add"
    elif len(re.findall("\npci_add", cmd_output)) > 0:
        cmd_type = "pci_add"
    else:
        raise error.TestError("Unknow version of qemu")

    # Determine syntax of drive hotplug
    # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6
    if len(re.findall("\n__com.redhat_drive_add", cmd_output)) > 0:
        drive_cmd_type = "__com.redhat_drive_add"
    # drive_add == qemu-kvm-0.13 onwards
    elif len(re.findall("\ndrive_add", cmd_output)) > 0:
        drive_cmd_type = "drive_add"
    else:
        raise error.TestError("Unknow version of qemu")

    # Probe qemu for a list of supported devices
    devices_support = vm.monitor.cmd("%s ?" % cmd_type)

    if cmd_type == "pci_add":
        if test_type == "nic":
            pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % tested_model
        elif test_type == "block":
            image_params = params.object_params("stg")
            image_filename = kvm_vm.get_image_filename(image_params,
                                                       test.bindir)
            pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" %
                           (image_filename, tested_model))
        # Execute pci_add (should be replaced by a proper monitor method call)
        add_output = vm.monitor.cmd(pci_add_cmd)
        if not "OK domain" in add_output:
            raise error.TestFail("Add PCI device failed. "
                                 "Monitor command is: %s, Output: %r" %
                                 (pci_add_cmd, add_output))
        after_add = vm.monitor.info("pci")

    elif cmd_type == "device_add":
        driver_id = test_type + "-" + kvm_utils.generate_random_id()
        device_id = test_type + "-" + kvm_utils.generate_random_id()
        if test_type == "nic":
            if tested_model == "virtio":
                tested_model = "virtio-net-pci"
            pci_add_cmd = "device_add id=%s,driver=%s" % (device_id,
                                                          tested_model)

        elif test_type == "block":
            image_params = params.object_params("stg")
            image_filename = kvm_vm.get_image_filename(image_params,
                                                       test.bindir)
            controller_model = None
            if tested_model == "virtio":
                tested_model = "virtio-blk-pci"

            if tested_model == "scsi":
                tested_model = "scsi-disk"
                controller_model = "lsi53c895a"
                if len(re.findall(controller_model, devices_support)) == 0:
                    raise error.TestError("scsi controller device (%s) not "
                                          "supported by qemu" %
                                          controller_model)

            if controller_model is not None:
                controller_id = "controller-" + device_id
                controller_add_cmd = ("device_add %s,id=%s" %
                                      (controller_model, controller_id))
                vm.monitor.cmd(controller_add_cmd)

            if drive_cmd_type == "drive_add":
                driver_add_cmd = ("drive_add auto "
                                  "file=%s,if=none,id=%s,format=%s" %
                                  (image_filename, driver_id, image_format))
            elif drive_cmd_type == "__com.redhat_drive_add":
                driver_add_cmd = ("__com.redhat_drive_add "
                                  "file=%s,format=%s,id=%s" %
                                  (image_filename, image_format, driver_id))

            pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" %
                           (device_id, tested_model, driver_id))
            vm.monitor.cmd(driver_add_cmd)

        # Check if the device is support in qemu
        if len(re.findall(tested_model, devices_support)) > 0:
            add_output = vm.monitor.cmd(pci_add_cmd)
        else:
            raise error.TestError("%s doesn't support device: %s" %
                                  (cmd_type, tested_model))
        after_add = vm.monitor.info("pci")

        if not device_id in after_add:
            raise error.TestFail("Add device failed. Monitor command is: %s"
                                 ". Output: %r" % (pci_add_cmd, add_output))

    # Define a helper function to delete the device
    def pci_del(ignore_failure=False):
        if cmd_type == "pci_add":
            result_domain, bus, slot, function = add_output.split(',')
            domain = int(result_domain.split()[2])
            bus = int(bus.split()[1])
            slot = int(slot.split()[1])
            pci_addr = "%x:%x:%x" % (domain, bus, slot)
            cmd = "pci_del pci_addr=%s" % pci_addr
        elif cmd_type == "device_add":
            cmd = "device_del %s" % device_id
        # This should be replaced by a proper monitor method call
        vm.monitor.cmd(cmd)

        def device_removed():
            after_del = vm.monitor.info("pci")
            return after_del != after_add

        if (not kvm_utils.wait_for(device_removed, 10, 0, 1)
                and not ignore_failure):
            raise error.TestFail("Failed to hot remove PCI device: %s. "
                                 "Monitor command: %s" % (tested_model, cmd))

    try:
        # Compare the output of 'info pci'
        if after_add == info_pci_ref:
            raise error.TestFail("No new PCI device shown after executing "
                                 "monitor command: 'info pci'")

        # Define a helper function to compare the output
        def new_shown():
            o = session.cmd_output(params.get("reference_cmd"))
            return o != reference

        secs = int(params.get("wait_secs_for_hook_up"))
        if not kvm_utils.wait_for(new_shown, 30, secs, 3):
            raise error.TestFail("No new device shown in output of command "
                                 "executed inside the guest: %s" %
                                 params.get("reference_cmd"))

        # Define a helper function to catch PCI device string
        def find_pci():
            o = session.cmd_output(params.get("find_pci_cmd"))
            return params.get("match_string") in o

        if not kvm_utils.wait_for(find_pci, 30, 3, 3):
            raise error.TestFail(
                "PCI %s %s device not found in guest. "
                "Command was: %s" %
                (tested_model, test_type, params.get("find_pci_cmd")))

        # Test the newly added device
        try:
            session.cmd(params.get("pci_test_cmd"))
        except kvm_subprocess.ShellError, e:
            raise error.TestFail("Check for %s device failed after PCI "
                                 "hotplug. Output: %r" % (test_type, e.output))

        session.close()
Exemple #40
0
def run_autotest(test, params, env):
    """
    Run an autotest test inside a guest.

    @param test: kvm test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    vm = kvm_utils.env_get_vm(env, 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; Test requires a living VM")

    logging.info("Logging into guest...")

    session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest")

    logging.info("Logged in")

    # Collect some info
    test_name = params.get("test_name")
    test_timeout = int(params.get("test_timeout", 300))
    test_control_file = params.get("test_control_file", "control")
    tarred_autotest_path = "/tmp/autotest.tar.bz2"
    tarred_test_path = "/tmp/%s.tar.bz2" % test_name

    # tar the contents of bindir/autotest
    cmd = "cd %s; tar cvjf %s autotest/*"
    cmd += " --exclude=autotest/tests"
    cmd += " --exclude=autotest/results"
    cmd += " --exclude=autotest/tmp"
    cmd += " --exclude=autotest/control"
    cmd += " --exclude=*.pyc"
    cmd += " --exclude=*.svn"
    cmd += " --exclude=*.git"
    kvm_subprocess.run_fg(cmd % (test.bindir, tarred_autotest_path), timeout=30)

    # tar the contents of bindir/autotest/tests/<test_name>
    cmd = "cd %s; tar cvjf %s %s/*"
    cmd += " --exclude=*.pyc"
    cmd += " --exclude=*.svn"
    cmd += " --exclude=*.git"
    kvm_subprocess.run_fg(
        cmd % (os.path.join(test.bindir, "autotest", "tests"), tarred_test_path, test_name), timeout=30
    )

    # Check if we need to copy autotest.tar.bz2
    copy = False
    output = session.get_command_output("ls -l autotest.tar.bz2")
    if "such file" in output:
        copy = True
    else:
        size = int(output.split()[4])
        if size != os.path.getsize(tarred_autotest_path):
            copy = True
    # Perform the copy
    if copy:
        logging.info("Copying autotest.tar.bz2 to guest" " (file is missing or has a different size)...")
        if not vm.scp_to_remote(tarred_autotest_path, ""):
            raise error.TestFail("Could not copy autotest.tar.bz2 to guest")

    # Check if we need to copy <test_name>.tar.bz2
    copy = False
    output = session.get_command_output("ls -l %s.tar.bz2" % test_name)
    if "such file" in output:
        copy = True
    else:
        size = int(output.split()[4])
        if size != os.path.getsize(tarred_test_path):
            copy = True
    # Perform the copy
    if copy:
        logging.info("Copying %s.tar.bz2 to guest (file is missing or has a" " different size)..." % test_name)
        if not vm.scp_to_remote(tarred_test_path, ""):
            raise error.TestFail("Could not copy %s.tar.bz2 to guest" % test_name)

    # Extract autotest.tar.bz2
    logging.info("Extracting autotest.tar.bz2...")
    status = session.get_command_status("tar xvfj autotest.tar.bz2")
    if status != 0:
        raise error.TestFail("Could not extract autotest.tar.bz2")

    # mkdir autotest/tests
    session.sendline("mkdir autotest/tests")

    # Extract <test_name>.tar.bz2 into autotest/tests
    logging.info("Extracting %s.tar.bz2..." % test_name)
    status = session.get_command_status("tar xvfj %s.tar.bz2 -C " "autotest/tests" % test_name)
    if status != 0:
        raise error.TestFail("Could not extract %s.tar.bz2" % test_name)

    # Cleaning up old remaining results
    session.sendline("rm -rf autotest/results/*")
    # Copying the selected control file (located inside
    # test.bindir/autotest_control to the autotest dir
    control_file_path = os.path.join(test.bindir, "autotest_control", test_control_file)
    if not vm.scp_to_remote(control_file_path, "autotest/control"):
        raise error.TestFail("Could not copy the test control file to guest")
    # Run the test
    logging.info("Running test '%s'..." % test_name)
    session.sendline("cd autotest")
    session.sendline("rm -f control.state")
    session.read_up_to_prompt()
    session.sendline("bin/autotest control")
    logging.info("---------------- Test output ----------------")
    match = session.read_up_to_prompt(timeout=test_timeout, print_func=logging.info)[0]
    logging.info("---------------- End of test output ----------------")
    if not match:
        raise error.TestFail("Timeout elapsed while waiting for test to " "complete")
    # Get the results generated by autotest
    output = session.get_command_output("cat results/*/status")

    # Parse test results
    result_list = scan_results.parse_results(output)

    # Report test results and check for FAIL/ERROR status
    logging.info("Results (test, status, duration, info):")
    status_error = False
    status_fail = False
    if result_list == []:
        status_fail = True
        message_fail = "Test '%s' did not produce any recognizable " "results" % test_name
    for result in result_list:
        logging.info(str(result))
        if result[1] == "FAIL":
            status_fail = True
            message_fail = "Test '%s' ended with FAIL " "(info: '%s')" % (result[0], result[3])
        if result[1] == "ERROR":
            status_error = True
            message_error = "Test '%s' ended with ERROR " "(info: '%s')" % (result[0], result[3])
        if result[1] == "ABORT":
            status_error = True
            message_error = "Test '%s' ended with ABORT " "(info: '%s')" % (result[0], result[3])

    # Copy test results to the local bindir/guest_results
    logging.info("Copying results back from guest...")
    guest_results_dir = os.path.join(test.outputdir, "guest_results")
    if not os.path.exists(guest_results_dir):
        os.mkdir(guest_results_dir)
    if not vm.scp_from_remote("autotest/results/default/*", guest_results_dir):
        logging.error("Could not copy results back from guest")

    # Fail the test if necessary
    if status_fail:
        raise error.TestFail(message_fail)
    elif status_error:
        raise error.TestError(message_error)
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()
    if not vm:
        return

    scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name)
    try:
        if vm.monitor:
            vm.monitor.screendump(scrdump_filename)
    except kvm_monitor.MonitorError, e:
        logging.warn(e)

    if params.get("kill_vm") == "yes":
        kill_vm_timeout = float(params.get("kill_vm_timeout", 0))
        if kill_vm_timeout:
            logging.debug("'kill_vm' specified; waiting for VM to shut down "
                          "before killing it...")
            kvm_utils.wait_for(vm.is_dead, kill_vm_timeout, 0, 1)
        else:
            logging.debug("'kill_vm' specified; killing VM...")
        vm.destroy(gracefully = params.get("kill_vm_gracefully") == "yes")


def process_command(test, params, env, command, command_timeout,
                    command_noncritical):
    """
    Pre- or post- custom commands to be executed before/after a test is run

    @param test: An Autotest test object.
    @param params: A dict containing all VM and image parameters.
    @param env: The environment (a dict-like object).
    @param command: Command to be run.
    @param command_timeout: Timeout for command execution.
Exemple #43
0
def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
            mig_cancel=False, offline=False, stable_check=False,
            clean=False, save_path=None, dest_host='localhost', mig_port=None):
    """
    Migrate a VM locally and re-register it in the environment.

    @param vm: The VM to migrate.
    @param env: The environment dictionary.  If omitted, the migrated VM will
            not be registered.
    @param mig_timeout: timeout value for migration.
    @param mig_protocol: migration protocol
    @param mig_cancel: Test migrate_cancel or not when protocol is tcp.
    @param dest_host: Destination host (defaults to 'localhost').
    @param mig_port: Port that will be used for migration.
    @return: The post-migration VM, in case of same host migration, True in
            case of multi-host migration.
    """
    def mig_finished():
        o = vm.monitor.info("migrate")
        if isinstance(o, str):
            return "status: active" not in o
        else:
            return o.get("status") != "active"

    def mig_succeeded():
        o = vm.monitor.info("migrate")
        if isinstance(o, str):
            return "status: completed" in o
        else:
            return o.get("status") == "completed"

    def mig_failed():
        o = vm.monitor.info("migrate")
        if isinstance(o, str):
            return "status: failed" in o
        else:
            return o.get("status") == "failed"

    def mig_cancelled():
        o = vm.monitor.info("migrate")
        if isinstance(o, str):
            return ("Migration status: cancelled" in o or
                    "Migration status: canceled" in o)
        else:
            return (o.get("status") == "cancelled" or
                    o.get("status") == "canceled")

    def wait_for_migration():
        if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,
                                  "Waiting for migration to finish..."):
            raise error.TestFail("Timeout expired while waiting for migration "
                                 "to finish")

    if dest_host == 'localhost':
        dest_vm = vm.clone()

    if (dest_host == 'localhost') and stable_check:
        # Pause the dest vm after creation
        dest_vm.params['extra_params'] = (dest_vm.params.get('extra_params','')
                                          + ' -S')

    if dest_host == 'localhost':
        dest_vm.create(migration_mode=mig_protocol, mac_source=vm)

    try:
        try:
            if mig_protocol == "tcp":
                if dest_host == 'localhost':
                    uri = "tcp:localhost:%d" % dest_vm.migration_port
                else:
                    uri = 'tcp:%s:%d' % (dest_host, mig_port)
            elif mig_protocol == "unix":
                uri = "unix:%s" % dest_vm.migration_file
            elif mig_protocol == "exec":
                uri = '"exec:nc localhost %s"' % dest_vm.migration_port

            if offline:
                vm.monitor.cmd("stop")
            vm.monitor.migrate(uri)

            if mig_cancel:
                time.sleep(2)
                vm.monitor.cmd("migrate_cancel")
                if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2,
                                          "Waiting for migration "
                                          "cancellation"):
                    raise error.TestFail("Failed to cancel migration")
                if offline:
                    vm.monitor.cmd("cont")
                if dest_host == 'localhost':
                    dest_vm.destroy(gracefully=False)
                return vm
            else:
                wait_for_migration()
                if (dest_host == 'localhost') and stable_check:
                    save_path = None or "/tmp"
                    save1 = os.path.join(save_path, "src")
                    save2 = os.path.join(save_path, "dst")

                    vm.save_to_file(save1)
                    dest_vm.save_to_file(save2)

                    # Fail if we see deltas
                    md5_save1 = utils.hash_file(save1)
                    md5_save2 = utils.hash_file(save2)
                    if md5_save1 != md5_save2:
                        raise error.TestFail("Mismatch of VM state before "
                                             "and after migration")

                if (dest_host == 'localhost') and offline:
                    dest_vm.monitor.cmd("cont")
        except:
            if dest_host == 'localhost':
                dest_vm.destroy()
            raise

    finally:
        if (dest_host == 'localhost') and stable_check and clean:
            logging.debug("Cleaning the state files")
            if os.path.isfile(save1):
                os.remove(save1)
            if os.path.isfile(save2):
                os.remove(save2)

    # Report migration status
    if mig_succeeded():
        logging.info("Migration finished successfully")
    elif mig_failed():
        raise error.TestFail("Migration failed")
    else:
        raise error.TestFail("Migration ended with unknown status")

    if dest_host == 'localhost':
        if "paused" in dest_vm.monitor.info("status"):
            logging.debug("Destination VM is paused, resuming it...")
            dest_vm.monitor.cmd("cont")

    # Kill the source VM
    vm.destroy(gracefully=False)

    # Replace the source VM with the new cloned VM
    if (dest_host == 'localhost') and (env is not None):
        env.register_vm(vm.name, dest_vm)

    # Return the new cloned VM
    if dest_host == 'localhost':
        return dest_vm
    else:
        return vm
Exemple #44
0
def run_timedrift(test, params, env):
    """
    Time drift test (mainly for Windows guests):

    1) Log into a guest.
    2) Take a time reading from the guest and host.
    3) Run load on the guest and host.
    4) Take a second time reading.
    5) Stop the load and rest for a while.
    6) Take a third time reading.
    7) If the drift immediately after load is higher than a user-
    specified value (in %), fail.
    If the drift after the rest period is higher than a user-specified value,
    fail.

    @param test: KVM test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    vm = kvm_utils.env_get_vm(env, 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; Test requires a living VM")

    logging.info("Waiting for guest to be up...")

    session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest")

    logging.info("Logged in")

    # Collect test parameters:
    # Command to run to get the current time
    time_command = params.get("time_command")
    # Filter which should match a string to be passed to time.strptime()
    time_filter_re = params.get("time_filter_re")
    # Time format for time.strptime()
    time_format = params.get("time_format")
    guest_load_command = params.get("guest_load_command")
    guest_load_stop_command = params.get("guest_load_stop_command")
    host_load_command = params.get("host_load_command")
    guest_load_instances = int(params.get("guest_load_instances", "1"))
    host_load_instances = int(params.get("host_load_instances", "0"))
    # CPU affinity mask for taskset
    cpu_mask = params.get("cpu_mask", "0xFF")
    load_duration = float(params.get("load_duration", "30"))
    rest_duration = float(params.get("rest_duration", "10"))
    drift_threshold = float(params.get("drift_threshold", "200"))
    drift_threshold_after_rest = float(params.get("drift_threshold_after_rest", "200"))

    guest_load_sessions = []
    host_load_sessions = []

    # Remember the VM's previous CPU affinity
    prev_cpu_mask = commands.getoutput("taskset -p %s" % vm.get_pid())
    prev_cpu_mask = prev_cpu_mask.split()[-1]
    # Set the VM's CPU affinity
    commands.getoutput("taskset -p %s %s" % (cpu_mask, vm.get_pid()))

    try:
        # Get time before load
        host_time_0 = time.time()
        session.sendline(time_command)
        (match, s) = session.read_up_to_prompt()
        s = re.findall(time_filter_re, s)[0]
        guest_time_0 = time.mktime(time.strptime(s, time_format))

        # Run some load on the guest
        logging.info("Starting load on guest...")
        for i in range(guest_load_instances):
            load_session = vm.ssh_login()
            if not load_session:
                raise error.TestFail("Could not log into guest")
            load_session.set_output_prefix("(guest load %d) " % i)
            load_session.set_output_func(logging.debug)
            load_session.sendline(guest_load_command)
            guest_load_sessions.append(load_session)

        # Run some load on the host
        logging.info("Starting load on host...")
        for i in range(host_load_instances):
            host_load_sessions.append(
                kvm_subprocess.run_bg(
                    host_load_command, output_func=logging.debug, output_prefix="(host load %d) " % i, timeout=0.5
                )
            )
            # Set the CPU affinity of the shell running the load process
            pid = host_load_sessions[-1].get_shell_pid()
            commands.getoutput("taskset -p %s %s" % (cpu_mask, pid))
            # Try setting the CPU affinity of the load process itself
            pid = host_load_sessions[-1].get_pid()
            if pid:
                commands.getoutput("taskset -p %s %s" % (cpu_mask, pid))

        # Sleep for a while (during load)
        logging.info("Sleeping for %s seconds..." % load_duration)
        time.sleep(load_duration)

        # Get time delta after load
        host_time_1 = time.time()
        session.sendline(time_command)
        (match, s) = session.read_up_to_prompt()
        s = re.findall(time_filter_re, s)[0]
        guest_time_1 = time.mktime(time.strptime(s, time_format))

        # Report results
        host_delta = host_time_1 - host_time_0
        guest_delta = guest_time_1 - guest_time_0
        drift = 100.0 * (host_delta - guest_delta) / host_delta
        logging.info("Host duration: %.2f" % host_delta)
        logging.info("Guest duration: %.2f" % guest_delta)
        logging.info("Drift: %.2f%%" % drift)

    finally:
        logging.info("Cleaning up...")
        # Restore the VM's CPU affinity
        commands.getoutput("taskset -p %s %s" % (prev_cpu_mask, vm.get_pid()))
        # Stop the guest load
        if guest_load_stop_command:
            session.get_command_output(guest_load_stop_command)
        # Close all load shell sessions
        for load_session in guest_load_sessions:
            load_session.close()
        for load_session in host_load_sessions:
            load_session.close()

    # Sleep again (rest)
    logging.info("Sleeping for %s seconds..." % rest_duration)
    time.sleep(rest_duration)

    # Get time after rest
    host_time_2 = time.time()
    session.sendline(time_command)
    (match, s) = session.read_up_to_prompt()
    s = re.findall(time_filter_re, s)[0]
    guest_time_2 = time.mktime(time.strptime(s, time_format))

    # Report results
    host_delta_total = host_time_2 - host_time_0
    guest_delta_total = guest_time_2 - guest_time_0
    drift_total = 100.0 * (host_delta_total - guest_delta_total) / host_delta
    logging.info("Total host duration including rest: %.2f" % host_delta_total)
    logging.info("Total guest duration including rest: %.2f" % guest_delta_total)
    logging.info("Total drift after rest: %.2f%%" % drift_total)

    # Fail the test if necessary
    if drift > drift_threshold:
        raise error.TestFail("Time drift too large: %.2f%%" % drift)
    if drift > drift_threshold_after_rest:
        raise error.TestFail("Time drift too large after rest period: %.2f%%" % drift_total)

    session.close()
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()
Exemple #46
0
def run_migration(test, params, env):
    """
    KVM migration test:

    1) Get two live VMs. One will be the 'source', the other will be the
    'destination'.
    2) Verify if the source VM supports migration. If it does, proceed with
    the test
    3) Send a migration command to the source vm and wait until it's finished.
    4) Kill off the source vm
    3) Log into the destination vm after the migration is finished.
    4) Compare the output of a reference command executed on the source with
    the output of the same command on the destination machine

    @param test: kvm test object.
    @param params: Dictionary with test parameters.
    @param env: Dictionary with the test environment.
    """
    src_vm_name = params.get("migration_src")
    vm = kvm_utils.env_get_vm(env, src_vm_name)
    if not vm:
        raise error.TestError("VM '%s' not found in environment" % src_vm_name)
    if not vm.is_alive():
        raise error.TestError("VM '%s' seems to be dead; Test requires a" " living VM" % src_vm_name)

    dest_vm_name = params.get("migration_dst")
    dest_vm = kvm_utils.env_get_vm(env, dest_vm_name)
    if not dest_vm:
        raise error.TestError("VM '%s' not found in environment" % dest_vm_name)
    if not dest_vm.is_alive():
        raise error.TestError("VM '%s' seems to be dead; Test requires a" " living VM" % dest_vm_name)

    pre_scrdump_filename = os.path.join(test.debugdir, "migration_pre.ppm")
    post_scrdump_filename = os.path.join(test.debugdir, "migration_post.ppm")

    # See if migration is supported
    s, o = vm.send_monitor_cmd("help info")
    if not "info migrate" in o:
        raise error.TestError("Migration is not supported")

    # Log into guest and get the output of migration_test_command
    logging.info("Waiting for guest to be up...")

    session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
    if not session:
        raise error.TestFail("Could not log into guest")

    logging.info("Logged in")

    reference_output = session.get_command_output(params.get("migration_test_" "command"))
    session.close()

    # Define the migration command
    cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port
    logging.debug("Migration command: %s" % cmd)

    # Migrate
    s, o = vm.send_monitor_cmd(cmd)
    if s:
        logging.error("Migration command failed (command: %r, output: %r)" % (cmd, o))
        raise error.TestFail("Migration command failed")

    # Define some helper functions
    def mig_finished():
        s, o = vm.send_monitor_cmd("info migrate")
        if s:
            return False
        if "Migration status: active" in o:
            return False
        return True

    def mig_succeeded():
        s, o = vm.send_monitor_cmd("info migrate")
        if s == 0 and "Migration status: completed" in o:
            return True
        return False

    def mig_failed():
        s, o = vm.send_monitor_cmd("info migrate")
        if s == 0 and "Migration status: failed" in o:
            return True
        return False

    # Wait for migration to finish
    if not kvm_utils.wait_for(mig_finished, 90, 2, 2, "Waiting for migration to finish..."):
        raise error.TestFail("Timeout elapsed while waiting for migration to" "finish")

    # Report migration status
    if mig_succeeded():
        logging.info("Migration finished successfully")
    else:
        if mig_failed():
            message = "Migration failed"
        else:
            message = "Migration ended with unknown status"
        raise error.TestFail(message)

    # Get 'post' screendump
    dest_vm.send_monitor_cmd("screendump %s" % post_scrdump_filename)

    # Get 'pre' screendump
    vm.send_monitor_cmd("screendump %s" % pre_scrdump_filename)

    # Kill the source VM
    vm.send_monitor_cmd("quit", block=False)

    # Hack: it seems that the first attempt to communicate with the SSH port
    # following migration always fails (or succeeds after a very long time).
    # So just connect to the port once so the following call to ssh_login
    # succeeds.
    dest_vm.is_sshd_running(timeout=0.0)

    # Log into guest and get the output of migration_test_command
    logging.info("Logging into guest after migration...")

    session = dest_vm.ssh_login()
    if not session:
        raise error.TestFail("Could not log into guest after migration")

    logging.info("Logged in after migration")

    output = session.get_command_output(params.get("migration_test_command"))
    session.close()

    # Compare output to reference output
    if output != reference_output:
        logging.info("Command output before migration differs from command" " output after migration")
        logging.info("Command: %s" % params.get("migration_test_command"))
        logging.info("Output before:" + kvm_utils.format_str_for_message(reference_output))
        logging.info("Output after:" + kvm_utils.format_str_for_message(output))
        raise error.TestFail("Command produced different output before and" " after migration")
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})