"""
High-level QEMU test utility functions.
This module is meant to reduce code size by performing common test procedures.
Generally, code here should look like test code.
More specifically:
    - Functions in this module should raise exceptions if things go wrong
    - Functions in this module typically use functions and classes from
      lower-level modules (e.g. utils_misc, qemu_vm, aexpect).
    - Functions in this module should not be used by lower-level modules.
    - Functions in this module should be used in the right context.
      For example, a function should not be used where it may display
      misleading or inaccurate info or debug messages.
:copyright: 2008-2013 Red Hat Inc.
"""
import os
import re
import six
import time
import logging
from functools import reduce
from avocado.core import exceptions
from avocado.utils import path as utils_path
from avocado.utils import process
from avocado.utils import cpu as cpuutil
from virttest import error_context
from virttest import utils_misc
from virttest import qemu_monitor
from virttest.qemu_devices import qdevices
from virttest.staging import utils_memory
from virttest.compat_52lts import decode_to_text
def guest_active(vm):
    o = vm.monitor.info("status")
    if isinstance(o, six.string_types):
        return "status: running" in o
    else:
        if "status" in o:
            return o.get("status") == "running"
        else:
            return o.get("running")
def get_numa_status(numa_node_info, qemu_pid, debug=True):
    """
    Get the qemu process memory use status and the cpu list in each node.
    :param numa_node_info: Host numa node information
    :type numa_node_info: NumaInfo object
    :param qemu_pid: process id of qemu
    :type numa_node_info: string
    :param debug: Print the debug info or not
    :type debug: bool
    :return: memory and cpu list in each node
    :rtype: tuple
    """
    node_list = numa_node_info.online_nodes
    qemu_memory = []
    qemu_cpu = []
    cpus = cpuutil.get_pid_cpus(qemu_pid)
    for node_id in node_list:
        qemu_memory_status = utils_memory.read_from_numa_maps(qemu_pid,
                                                              "N%d" % node_id)
        memory = sum([int(_) for _ in list(qemu_memory_status.values())])
        qemu_memory.append(memory)
        cpu = [_ for _ in cpus if _ in numa_node_info.nodes[node_id].cpus]
        qemu_cpu.append(cpu)
        if debug:
            logging.debug("qemu-kvm process using %s pages and cpu %s in "
                          "node %s" % (memory, " ".join(cpu), node_id))
    return (qemu_memory, qemu_cpu)
def pin_vm_threads(vm, node):
    """
    Pin VM threads to single cpu of a numa node
    :param vm: VM object
    :param node: NumaNode object
    """
    if len(vm.vcpu_threads) + len(vm.vhost_threads) < len(node.cpus):
        for i in vm.vcpu_threads:
            logging.info("pin vcpu thread(%s) to cpu(%s)" %
                         (i, node.pin_cpu(i)))
        for i in vm.vhost_threads:
            logging.info("pin vhost thread(%s) to cpu(%s)" %
                         (i, node.pin_cpu(i)))
    elif (len(vm.vcpu_threads) <= len(node.cpus) and
          len(vm.vhost_threads) <= len(node.cpus)):
        for i in vm.vcpu_threads:
            logging.info("pin vcpu thread(%s) to cpu(%s)" %
                         (i, node.pin_cpu(i)))
        for i in vm.vhost_threads:
            logging.info("pin vhost thread(%s) to extra cpu(%s)" %
                         (i, node.pin_cpu(i, extra=True)))
    else:
        logging.info("Skip pinning, no enough nodes")
def _check_driver_verifier(session, driver, timeout=300):
    """
    Check driver verifier status
    :param session: VM session.
    :param driver: The driver need to query
    :param timeout: Timeout in seconds
    """
    logging.info("Check %s driver verifier status" % driver)
    query_cmd = "verifier /querysettings"
    output = session.cmd_output(query_cmd, timeout=timeout)
    return (driver in output, output)
@error_context.context_aware
def setup_win_driver_verifier(session, driver, vm, timeout=300):
    """
    Enable driver verifier for windows guest.
    :param driver: The driver which needs enable the verifier.
    :param vm: VM object.
    :param timeout: Timeout in seconds.
    """
    verifier_status = _check_driver_verifier(session, driver)[0]
    if not verifier_status:
        error_context.context("Enable %s driver verifier" % driver,
                              logging.info)
        verifier_setup_cmd = "verifier /standard /driver %s.sys" % driver
        session.cmd(verifier_setup_cmd,
                    timeout=timeout,
                    ignore_all_errors=True)
        session = vm.reboot(session)
        verifier_status, output = _check_driver_verifier(session, driver)
        if not verifier_status:
            msg = "%s verifier is not enabled, details: %s" % (driver,
                                                               output)
            raise exceptions.TestFail(msg)
    logging.info("%s verifier is enabled already" % driver)
    return session
def clear_win_driver_verifier(driver, vm, timeout=300):
    """
    Clear the driver verifier in windows guest.
    :param driver: The driver need to clear
    :param vm: VM object.
    :param timeout: Timeout in seconds.
    """
    session = vm.wait_for_login(timeout=timeout)
    try:
        verifier_status = _check_driver_verifier(session, driver)[1]
        if verifier_status:
            logging.info("Clear driver verifier")
            verifier_clear_cmd = "verifier /reset"
            session.cmd(verifier_clear_cmd,
                        timeout=timeout,
                        ignore_all_errors=True)
            session = vm.reboot(session)
    finally:
        session.close()
@error_context.context_aware
def windrv_verify_running(session, test, driver, timeout=300):
    """
    Check if driver is running for windows guest within a period time.
    :param session: VM session
    :param test: Kvm test object
    :param driver: The driver which needs to check.
    :param timeout: Timeout in seconds.
    """
    def _check_driver_stat():
        """
        Check if driver is in Running status.
        """
        output = session.cmd_output(driver_check_cmd, timeout=timeout)
        if "Running" in output:
            return True
        return False
    error_context.context("Check %s driver state." % driver, logging.info)
    driver_check_cmd = (r'wmic sysdriver where PathName="C:\\Windows\\System32'
                        r'\\drivers\\%s.sys" get State /value') % driver
    if not utils_misc.wait_for(_check_driver_stat, timeout, 0, 5):
        test.error("%s driver is not running" % driver)
@error_context.context_aware
def windrv_check_running_verifier(session, vm, test, driver, timeout=300):
    """
    Check whether the windows driver is running, then enable driver verifier.
    :param vm: the VM that use the driver.
    :param test: the KVM test object.
    :param driver: the driver concerned.
    :timeout: the timeout to use in this process, in seconds.
    """
    windrv_verify_running(session, test, driver, timeout)
    return setup_win_driver_verifier(session, driver, vm, timeout)
def setup_runlevel(params, session):
    """
    Setup the runlevel in guest.
    :param params: Dictionary with the test parameters.
    :param session: VM session.
    """
    cmd = "runlevel"
    ori_runlevel = "0"
    expect_runlevel = params.get("expect_runlevel", "3")
    # Note: All guest services may have not been started when
    #       the guest gets IP addr; the guest runlevel maybe
    #       is "unknown" whose exit status is 1 at that time,
    #       which will cause the cmd execution failed. Need some
    #       time here to wait for the guest services start.
    if utils_misc.wait_for(lambda: session.cmd_status(cmd) == 0, 15):
        ori_runlevel = session.cmd(cmd)
    ori_runlevel = ori_runlevel.split()[-1]
    if ori_runlevel == expect_runlevel:
        logging.info("Guest runlevel is already %s as expected" % ori_runlevel)
    else:
        session.cmd("init %s" % expect_runlevel)
        tmp_runlevel = session.cmd(cmd)
        tmp_runlevel = tmp_runlevel.split()[-1]
        if tmp_runlevel != expect_runlevel:
            logging.warn("Changing runlevel from %s to %s failed (%s)!",
                         ori_runlevel, expect_runlevel, tmp_runlevel)
class GuestSuspend(object):
    """
    Suspend guest, supports both Linux and Windows.
    """
    SUSPEND_TYPE_MEM = "mem"
    SUSPEND_TYPE_DISK = "disk"
    def __init__(self, test, params, vm):
        if not params or not vm:
            raise exceptions.TestError("Missing 'params' or 'vm' parameters")
        self._open_session_list = []
        self.test = test
        self.vm = vm
        self.params = params
        self.login_timeout = float(self.params.get("login_timeout", 360))
        self.services_up_timeout = float(self.params.get("services_up_timeout",
                                                         30))
        self.os_type = self.params.get("os_type")
    def _get_session(self):
        self.vm.verify_alive()
        session = self.vm.wait_for_login(timeout=self.login_timeout)
        return session
    def _session_cmd_close(self, session, cmd):
        try:
            return session.cmd_status_output(cmd)
        finally:
            try:
                session.close()
            except Exception:
                pass
    def _cleanup_open_session(self):
        try:
            for s in self._open_session_list:
                if s:
                    s.close()
        except Exception:
            pass
    @error_context.context_aware
    def setup_bg_program(self, **args):
        """
        Start up a program as a flag in guest.
        """
        suspend_bg_program_setup_cmd = args.get("suspend_bg_program_setup_cmd")
        error_context.context(
            "Run a background program as a flag", logging.info)
        session = self._get_session()
        self._open_session_list.append(session)
        logging.debug("Waiting all services in guest are fully started.")
        time.sleep(self.services_up_timeout)
        session.sendline(suspend_bg_program_setup_cmd)
    @error_context.context_aware
    def check_bg_program(self, **args):
        """
        Make sure the background program is running as expected
        """
        suspend_bg_program_chk_cmd = args.get("suspend_bg_program_chk_cmd")
        error_context.context(
            "Verify background program is running", logging.info)
        session = self._get_session()
        s, _ = self._session_cmd_close(session, suspend_bg_program_chk_cmd)
        if s:
            raise exceptions.TestFail(
                "Background program is dead. Suspend failed.")
    @error_context.context_aware
    def kill_bg_program(self, **args):
        error_context.context("Kill background program after resume")
        suspend_bg_program_kill_cmd = args.get("suspend_bg_program_kill_cmd")
        try:
            session = self._get_session()
            self._session_cmd_close(session, suspend_bg_program_kill_cmd)
        except Exception as e:
            logging.warn("Could not stop background program: '%s'", e)
            pass
    @error_context.context_aware
    def _check_guest_suspend_log(self, **args):
        error_context.context("Check whether guest supports suspend",
                              logging.info)
        suspend_support_chk_cmd = args.get("suspend_support_chk_cmd")
        session = self._get_session()
        s, o = self._session_cmd_close(session, suspend_support_chk_cmd)
        return s, o
    def verify_guest_support_suspend(self, **args):
        s, _ = self._check_guest_suspend_log(**args)
        if s:
            raise exceptions.TestError("Guest doesn't support suspend.")
    @error_context.context_aware
    def start_suspend(self, **args):
        suspend_start_cmd = args.get("suspend_start_cmd")
        error_context.context(
            "Start suspend [%s]" % (suspend_start_cmd), logging.info)
        session = self._get_session()
        self._open_session_list.append(session)
        # Suspend to disk
        session.sendline(suspend_start_cmd)
    @error_context.context_aware
    def verify_guest_down(self, **args):
        # Make sure the VM goes down
        error_context.context("Wait for guest goes down after suspend")
        suspend_timeout = 240 + int(self.params.get("smp")) * 60
        if not utils_misc.wait_for(self.vm.is_dead, suspend_timeout, 2, 2):
            raise exceptions.TestFail("VM refuses to go down. Suspend failed.")
    @error_context.context_aware
    def resume_guest_mem(self, **args):
        error_context.context("Resume suspended VM from memory")
        self.vm.monitor.system_wakeup()
    @error_context.context_aware
    def resume_guest_disk(self, **args):
        error_context.context("Resume suspended VM from disk")
        self.vm.create()
    @error_context.context_aware
    def verify_guest_up(self, **args):
        error_context.context("Verify guest system log", logging.info)
        suspend_log_chk_cmd = args.get("suspend_log_chk_cmd")
        session = self._get_session()


Answer:         s, o = self._session_cmd_close(session, suspend_log_chk_cmd)