| Index: client/tests/kvm/kvm_utils.py
 | 
| diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py
 | 
| index d13597903d2afe6453d5c9bc9855876c7c79a244..b849b37b2dd83a1a8670a4a5d71af82459d6a40e 100644
 | 
| --- a/client/tests/kvm/kvm_utils.py
 | 
| +++ b/client/tests/kvm/kvm_utils.py
 | 
| @@ -5,7 +5,7 @@ KVM test utility functions.
 | 
|  """
 | 
|  
 | 
|  import time, string, random, socket, os, signal, re, logging, commands, cPickle
 | 
| -import fcntl, shelve, ConfigParser, rss_file_transfer, threading, sys, UserDict
 | 
| +import fcntl, shelve, ConfigParser
 | 
|  from autotest_lib.client.bin import utils, os_dep
 | 
|  from autotest_lib.client.common_lib import error, logging_config
 | 
|  import kvm_subprocess
 | 
| @@ -27,152 +27,74 @@ def _unlock_file(f):
 | 
|      f.close()
 | 
|  
 | 
|  
 | 
| -def is_vm(obj):
 | 
| +def dump_env(obj, filename):
 | 
|      """
 | 
| -    Tests whether a given object is a VM object.
 | 
| +    Dump KVM test environment to a file.
 | 
|  
 | 
| -    @param obj: Python object.
 | 
| +    @param filename: Path to a file where the environment will be dumped to.
 | 
|      """
 | 
| -    return obj.__class__.__name__ == "VM"
 | 
| +    file = open(filename, "w")
 | 
| +    cPickle.dump(obj, file)
 | 
| +    file.close()
 | 
|  
 | 
|  
 | 
| -class Env(UserDict.IterableUserDict):
 | 
| +def load_env(filename, version):
 | 
|      """
 | 
| -    A dict-like object containing global objects used by tests.
 | 
| -    """
 | 
| -    def __init__(self, filename=None, version=0):
 | 
| -        """
 | 
| -        Create an empty Env object or load an existing one from a file.
 | 
| -
 | 
| -        If the version recorded in the file is lower than version, or if some
 | 
| -        error occurs during unpickling, or if filename is not supplied,
 | 
| -        create an empty Env object.
 | 
| -
 | 
| -        @param filename: Path to an env file.
 | 
| -        @param version: Required env version (int).
 | 
| -        """
 | 
| -        UserDict.IterableUserDict.__init__(self)
 | 
| -        empty = {"version": version}
 | 
| -        if filename:
 | 
| -            self._filename = filename
 | 
| -            try:
 | 
| -                f = open(filename, "r")
 | 
| -                env = cPickle.load(f)
 | 
| -                f.close()
 | 
| -                if env.get("version", 0) >= version:
 | 
| -                    self.data = env
 | 
| -                else:
 | 
| -                    logging.warn("Incompatible env file found. Not using it.")
 | 
| -                    self.data = empty
 | 
| -            # Almost any exception can be raised during unpickling, so let's
 | 
| -            # catch them all
 | 
| -            except Exception, e:
 | 
| -                logging.warn(e)
 | 
| -                self.data = empty
 | 
| -        else:
 | 
| -            self.data = empty
 | 
| -
 | 
| -
 | 
| -    def save(self, filename=None):
 | 
| -        """
 | 
| -        Pickle the contents of the Env object into a file.
 | 
| -
 | 
| -        @param filename: Filename to pickle the dict into.  If not supplied,
 | 
| -                use the filename from which the dict was loaded.
 | 
| -        """
 | 
| -        filename = filename or self._filename
 | 
| -        f = open(filename, "w")
 | 
| -        cPickle.dump(self.data, f)
 | 
| -        f.close()
 | 
| -
 | 
| -
 | 
| -    def get_all_vms(self):
 | 
| -        """
 | 
| -        Return a list of all VM objects in this Env object.
 | 
| -        """
 | 
| -        return [o for o in self.values() if is_vm(o)]
 | 
| -
 | 
| -
 | 
| -    def get_vm(self, name):
 | 
| -        """
 | 
| -        Return a VM object by its name.
 | 
| -
 | 
| -        @param name: VM name.
 | 
| -        """
 | 
| -        return self.get("vm__%s" % name)
 | 
| -
 | 
| -
 | 
| -    def register_vm(self, name, vm):
 | 
| -        """
 | 
| -        Register a VM in this Env object.
 | 
| -
 | 
| -        @param name: VM name.
 | 
| -        @param vm: VM object.
 | 
| -        """
 | 
| -        self["vm__%s" % name] = vm
 | 
| -
 | 
| -
 | 
| -    def unregister_vm(self, name):
 | 
| -        """
 | 
| -        Remove a given VM.
 | 
| -
 | 
| -        @param name: VM name.
 | 
| -        """
 | 
| -        del self["vm__%s" % name]
 | 
| -
 | 
| +    Load KVM test environment from an env file.
 | 
| +    If the version recorded in the file is lower than version, return an empty
 | 
| +    env.  If some other error occurs during unpickling, return an empty env.
 | 
|  
 | 
| -    def register_installer(self, installer):
 | 
| -        """
 | 
| -        Register a installer that was just run
 | 
| -
 | 
| -        The installer will be available for other tests, so that
 | 
| -        information about the installed KVM modules and qemu-kvm can be used by
 | 
| -        them.
 | 
| -        """
 | 
| -        self['last_installer'] = installer
 | 
| +    @param filename: Path to an env file.
 | 
| +    """
 | 
| +    default = {"version": version}
 | 
| +    try:
 | 
| +        file = open(filename, "r")
 | 
| +        env = cPickle.load(file)
 | 
| +        file.close()
 | 
| +        if env.get("version", 0) < version:
 | 
| +            logging.warn("Incompatible env file found. Not using it.")
 | 
| +            return default
 | 
| +        return env
 | 
| +    # Almost any exception can be raised during unpickling, so let's catch
 | 
| +    # them all
 | 
| +    except Exception, e:
 | 
| +        logging.warn(e)
 | 
| +        return default
 | 
|  
 | 
|  
 | 
| -    def previous_installer(self):
 | 
| -        """
 | 
| -        Return the last installer that was registered
 | 
| -        """
 | 
| -        return self.get('last_installer')
 | 
| +def get_sub_dict(dict, name):
 | 
| +    """
 | 
| +    Return a "sub-dict" corresponding to a specific object.
 | 
|  
 | 
| +    Operate on a copy of dict: for each key that ends with the suffix
 | 
| +    "_" + name, strip the suffix from the key, and set the value of
 | 
| +    the stripped key to that of the key. Return the resulting dict.
 | 
|  
 | 
| -class Params(UserDict.IterableUserDict):
 | 
| +    @param name: Suffix of the key we want to set the value.
 | 
|      """
 | 
| -    A dict-like object passed to every test.
 | 
| -    """
 | 
| -    def objects(self, key):
 | 
| -        """
 | 
| -        Return the names of objects defined using a given key.
 | 
| -
 | 
| -        @param key: The name of the key whose value lists the objects
 | 
| -                (e.g. 'nics').
 | 
| -        """
 | 
| -        return self.get(key, "").split()
 | 
| +    suffix = "_" + name
 | 
| +    new_dict = dict.copy()
 | 
| +    for key in dict.keys():
 | 
| +        if key.endswith(suffix):
 | 
| +            new_key = key.split(suffix)[0]
 | 
| +            new_dict[new_key] = dict[key]
 | 
| +    return new_dict
 | 
|  
 | 
|  
 | 
| -    def object_params(self, obj_name):
 | 
| -        """
 | 
| -        Return a dict-like object containing the parameters of an individual
 | 
| -        object.
 | 
| +def get_sub_dict_names(dict, keyword):
 | 
| +    """
 | 
| +    Return a list of "sub-dict" names that may be extracted with get_sub_dict.
 | 
|  
 | 
| -        This method behaves as follows: the suffix '_' + obj_name is removed
 | 
| -        from all key names that have it.  Other key names are left unchanged.
 | 
| -        The values of keys with the suffix overwrite the values of their
 | 
| -        suffixless versions.
 | 
| +    This function may be modified to change the behavior of all functions that
 | 
| +    deal with multiple objects defined in dicts (e.g. VMs, images, NICs).
 | 
|  
 | 
| -        @param obj_name: The name of the object (objects are listed by the
 | 
| -                objects() method).
 | 
| -        """
 | 
| -        suffix = "_" + obj_name
 | 
| -        new_dict = self.copy()
 | 
| -        for key in self:
 | 
| -            if key.endswith(suffix):
 | 
| -                new_key = key.split(suffix)[0]
 | 
| -                new_dict[new_key] = self[key]
 | 
| -        return new_dict
 | 
| +    @param keyword: A key in dict (e.g. "vms", "images", "nics").
 | 
| +    """
 | 
| +    names = dict.get(keyword)
 | 
| +    if names:
 | 
| +        return names.split()
 | 
| +    else:
 | 
| +        return []
 | 
|  
 | 
|  
 | 
|  # Functions related to MAC/IP addresses
 | 
| @@ -318,6 +240,60 @@ def verify_ip_address_ownership(ip, macs, timeout=10.0):
 | 
|      return bool(regex.search(o))
 | 
|  
 | 
|  
 | 
| +# Functions for working with the environment (a dict-like object)
 | 
| +
 | 
| +def is_vm(obj):
 | 
| +    """
 | 
| +    Tests whether a given object is a VM object.
 | 
| +
 | 
| +    @param obj: Python object (pretty much everything on python).
 | 
| +    """
 | 
| +    return obj.__class__.__name__ == "VM"
 | 
| +
 | 
| +
 | 
| +def env_get_all_vms(env):
 | 
| +    """
 | 
| +    Return a list of all VM objects on a given environment.
 | 
| +
 | 
| +    @param env: Dictionary with environment items.
 | 
| +    """
 | 
| +    vms = []
 | 
| +    for obj in env.values():
 | 
| +        if is_vm(obj):
 | 
| +            vms.append(obj)
 | 
| +    return vms
 | 
| +
 | 
| +
 | 
| +def env_get_vm(env, name):
 | 
| +    """
 | 
| +    Return a VM object by its name.
 | 
| +
 | 
| +    @param name: VM name.
 | 
| +    """
 | 
| +    return env.get("vm__%s" % name)
 | 
| +
 | 
| +
 | 
| +def env_register_vm(env, name, vm):
 | 
| +    """
 | 
| +    Register a given VM in a given env.
 | 
| +
 | 
| +    @param env: Environment where we will register the VM.
 | 
| +    @param name: VM name.
 | 
| +    @param vm: VM object.
 | 
| +    """
 | 
| +    env["vm__%s" % name] = vm
 | 
| +
 | 
| +
 | 
| +def env_unregister_vm(env, name):
 | 
| +    """
 | 
| +    Remove a given VM from a given env.
 | 
| +
 | 
| +    @param env: Environment where we will un-register the VM.
 | 
| +    @param name: VM name.
 | 
| +    """
 | 
| +    del env["vm__%s" % name]
 | 
| +
 | 
| +
 | 
|  # Utility functions for dealing with external processes
 | 
|  
 | 
|  def find_command(cmd):
 | 
| @@ -445,7 +421,7 @@ def check_kvm_source_dir(source_dir):
 | 
|      os.chdir(source_dir)
 | 
|      has_qemu_dir = os.path.isdir('qemu')
 | 
|      has_kvm_dir = os.path.isdir('kvm')
 | 
| -    if has_qemu_dir:
 | 
| +    if has_qemu_dir and not has_kvm_dir:
 | 
|          logging.debug("qemu directory detected, source dir layout 1")
 | 
|          return 1
 | 
|      if has_kvm_dir and not has_qemu_dir:
 | 
| @@ -466,7 +442,7 @@ def _remote_login(session, username, password, prompt, timeout=10):
 | 
|  
 | 
|      @brief: Log into a remote host (guest) using SSH or Telnet.
 | 
|  
 | 
| -    @param session: An Expect or ShellSession instance to operate on
 | 
| +    @param session: A kvm_expect or kvm_shell_session instance to operate on
 | 
|      @param username: The username to send in reply to a login prompt
 | 
|      @param password: The password to send in reply to a password prompt
 | 
|      @param prompt: The shell prompt that indicates a successful login
 | 
| @@ -480,52 +456,48 @@ def _remote_login(session, username, password, prompt, timeout=10):
 | 
|      login_prompt_count = 0
 | 
|  
 | 
|      while True:
 | 
| -        try:
 | 
| -            match, text = session.read_until_last_line_matches(
 | 
| +        (match, text) = session.read_until_last_line_matches(
 | 
|                  [r"[Aa]re you sure", r"[Pp]assword:\s*$", r"[Ll]ogin:\s*$",
 | 
|                   r"[Cc]onnection.*closed", r"[Cc]onnection.*refused",
 | 
|                   r"[Pp]lease wait", prompt],
 | 
| -                timeout=timeout, internal_timeout=0.5)
 | 
| -            if match == 0:  # "Are you sure you want to continue connecting"
 | 
| -                logging.debug("Got 'Are you sure...'; sending 'yes'")
 | 
| -                session.sendline("yes")
 | 
| +                 timeout=timeout, internal_timeout=0.5)
 | 
| +        if match == 0:  # "Are you sure you want to continue connecting"
 | 
| +            logging.debug("Got 'Are you sure...'; sending 'yes'")
 | 
| +            session.sendline("yes")
 | 
| +            continue
 | 
| +        elif match == 1:  # "password:"
 | 
| +            if password_prompt_count == 0:
 | 
| +                logging.debug("Got password prompt; sending '%s'" % password)
 | 
| +                session.sendline(password)
 | 
| +                password_prompt_count += 1
 | 
|                  continue
 | 
| -            elif match == 1:  # "password:"
 | 
| -                if password_prompt_count == 0:
 | 
| -                    logging.debug("Got password prompt; sending '%s'" % password)
 | 
| -                    session.sendline(password)
 | 
| -                    password_prompt_count += 1
 | 
| -                    continue
 | 
| -                else:
 | 
| -                    logging.debug("Got password prompt again")
 | 
| -                    return False
 | 
| -            elif match == 2:  # "login:"
 | 
| -                if login_prompt_count == 0:
 | 
| -                    logging.debug("Got username prompt; sending '%s'" % username)
 | 
| -                    session.sendline(username)
 | 
| -                    login_prompt_count += 1
 | 
| -                    continue
 | 
| -                else:
 | 
| -                    logging.debug("Got username prompt again")
 | 
| -                    return False
 | 
| -            elif match == 3:  # "Connection closed"
 | 
| -                logging.debug("Got 'Connection closed'")
 | 
| -                return False
 | 
| -            elif match == 4:  # "Connection refused"
 | 
| -                logging.debug("Got 'Connection refused'")
 | 
| +            else:
 | 
| +                logging.debug("Got password prompt again")
 | 
|                  return False
 | 
| -            elif match == 5:  # "Please wait"
 | 
| -                logging.debug("Got 'Please wait'")
 | 
| -                timeout = 30
 | 
| +        elif match == 2:  # "login:"
 | 
| +            if login_prompt_count == 0:
 | 
| +                logging.debug("Got username prompt; sending '%s'" % username)
 | 
| +                session.sendline(username)
 | 
| +                login_prompt_count += 1
 | 
|                  continue
 | 
| -            elif match == 6:  # prompt
 | 
| -                logging.debug("Got shell prompt -- logged in")
 | 
| -                return True
 | 
| -        except kvm_subprocess.ExpectTimeoutError, e:
 | 
| -            logging.debug("Timeout elapsed (output so far: %r)" % e.output)
 | 
| +            else:
 | 
| +                logging.debug("Got username prompt again")
 | 
| +                return False
 | 
| +        elif match == 3:  # "Connection closed"
 | 
| +            logging.debug("Got 'Connection closed'")
 | 
| +            return False
 | 
| +        elif match == 4:  # "Connection refused"
 | 
| +            logging.debug("Got 'Connection refused'")
 | 
|              return False
 | 
| -        except kvm_subprocess.ExpectProcessTerminatedError, e:
 | 
| -            logging.debug("Process terminated (output so far: %r)" % e.output)
 | 
| +        elif match == 5:  # "Please wait"
 | 
| +            logging.debug("Got 'Please wait'")
 | 
| +            timeout = 30
 | 
| +            continue
 | 
| +        elif match == 6:  # prompt
 | 
| +            logging.debug("Got shell prompt -- logged in")
 | 
| +            return session
 | 
| +        else:  # match == None
 | 
| +            logging.debug("Timeout elapsed or process terminated")
 | 
|              return False
 | 
|  
 | 
|  
 | 
| @@ -538,7 +510,7 @@ def _remote_scp(session, password, transfer_timeout=600, login_timeout=10):
 | 
|  
 | 
|      @brief: Transfer files using SCP, given a command line.
 | 
|  
 | 
| -    @param session: An Expect or ShellSession instance to operate on
 | 
| +    @param session: A kvm_expect or kvm_shell_session instance to operate on
 | 
|      @param password: The password to send in reply to a password prompt.
 | 
|      @param transfer_timeout: The time duration (in seconds) to wait for the
 | 
|              transfer to complete.
 | 
| @@ -552,33 +524,34 @@ def _remote_scp(session, password, transfer_timeout=600, login_timeout=10):
 | 
|      timeout = login_timeout
 | 
|  
 | 
|      while True:
 | 
| -        try:
 | 
| -            match, text = session.read_until_last_line_matches(
 | 
| +        (match, text) = session.read_until_last_line_matches(
 | 
|                  [r"[Aa]re you sure", r"[Pp]assword:\s*$", r"lost connection"],
 | 
|                  timeout=timeout, internal_timeout=0.5)
 | 
| -            if match == 0:  # "Are you sure you want to continue connecting"
 | 
| -                logging.debug("Got 'Are you sure...'; sending 'yes'")
 | 
| -                session.sendline("yes")
 | 
| +        if match == 0:  # "Are you sure you want to continue connecting"
 | 
| +            logging.debug("Got 'Are you sure...'; sending 'yes'")
 | 
| +            session.sendline("yes")
 | 
| +            continue
 | 
| +        elif match == 1:  # "password:"
 | 
| +            if password_prompt_count == 0:
 | 
| +                logging.debug("Got password prompt; sending '%s'" % password)
 | 
| +                session.sendline(password)
 | 
| +                password_prompt_count += 1
 | 
| +                timeout = transfer_timeout
 | 
|                  continue
 | 
| -            elif match == 1:  # "password:"
 | 
| -                if password_prompt_count == 0:
 | 
| -                    logging.debug("Got password prompt; sending '%s'" % password)
 | 
| -                    session.sendline(password)
 | 
| -                    password_prompt_count += 1
 | 
| -                    timeout = transfer_timeout
 | 
| -                    continue
 | 
| -                else:
 | 
| -                    logging.debug("Got password prompt again")
 | 
| -                    return False
 | 
| -            elif match == 2:  # "lost connection"
 | 
| -                logging.debug("Got 'lost connection'")
 | 
| +            else:
 | 
| +                logging.debug("Got password prompt again")
 | 
|                  return False
 | 
| -        except kvm_subprocess.ExpectTimeoutError, e:
 | 
| -            logging.debug("Timeout expired")
 | 
| +        elif match == 2:  # "lost connection"
 | 
| +            logging.debug("Got 'lost connection'")
 | 
|              return False
 | 
| -        except kvm_subprocess.ExpectProcessTerminatedError, e:
 | 
| -            logging.debug("SCP process terminated with status %s", e.status)
 | 
| -            return e.status == 0
 | 
| +        else:  # match == None
 | 
| +            if session.is_alive():
 | 
| +                logging.debug("Timeout expired")
 | 
| +                return False
 | 
| +            else:
 | 
| +                status = session.get_status()
 | 
| +                logging.debug("SCP process terminated with status %s", status)
 | 
| +                return status == 0
 | 
|  
 | 
|  
 | 
|  def remote_login(client, host, port, username, password, prompt, linesep="\n",
 | 
| @@ -599,7 +572,7 @@ def remote_login(client, host, port, username, password, prompt, linesep="\n",
 | 
|              each step of the login procedure (i.e. the "Are you sure" prompt
 | 
|              or the password prompt)
 | 
|  
 | 
| -    @return: ShellSession object on success and None on failure.
 | 
| +    @return: kvm_shell_session object on success and None on failure.
 | 
|      """
 | 
|      if client == "ssh":
 | 
|          cmd = ("ssh -o UserKnownHostsFile=/dev/null "
 | 
| @@ -614,7 +587,8 @@ def remote_login(client, host, port, username, password, prompt, linesep="\n",
 | 
|          return
 | 
|  
 | 
|      logging.debug("Trying to login with command '%s'" % cmd)
 | 
| -    session = kvm_subprocess.ShellSession(cmd, linesep=linesep, prompt=prompt)
 | 
| +    session = kvm_subprocess.kvm_shell_session(cmd, linesep=linesep,
 | 
| +                                               prompt=prompt)
 | 
|      if _remote_login(session, username, password, prompt, timeout):
 | 
|          if log_filename:
 | 
|              session.set_output_func(log_line)
 | 
| @@ -653,83 +627,19 @@ def remote_scp(command, password, log_filename=None, transfer_timeout=600,
 | 
|          output_func = None
 | 
|          output_params = ()
 | 
|  
 | 
| -    session = kvm_subprocess.Expect(command,
 | 
| -                                    output_func=output_func,
 | 
| -                                    output_params=output_params)
 | 
| +    session = kvm_subprocess.kvm_expect(command,
 | 
| +                                        output_func=output_func,
 | 
| +                                        output_params=output_params)
 | 
|      try:
 | 
|          return _remote_scp(session, password, transfer_timeout, login_timeout)
 | 
|      finally:
 | 
|          session.close()
 | 
|  
 | 
|  
 | 
| -def copy_files_to(address, client, username, password, port, local_path,
 | 
| -                  remote_path, log_filename=None, timeout=600):
 | 
| -    """
 | 
| -    Decide the transfer cleint and copy file to a remote host (guest).
 | 
| -
 | 
| -    @param client: Type of transfer client
 | 
| -    @param username: Username (if required)
 | 
| -    @param password: Password (if requried)
 | 
| -    @param local_path: Path on the local machine where we are copying from
 | 
| -    @param remote_path: Path on the remote machine where we are copying to
 | 
| -    @param address: Address of remote host(guest)
 | 
| -    @param log_filename: If specified, log all output to this file
 | 
| -    @param timeout: The time duration (in seconds) to wait for the transfer to
 | 
| -    complete.
 | 
| -
 | 
| -    @return: True on success and False on failure.
 | 
| -    """
 | 
| -
 | 
| -    if not address or not port:
 | 
| -        logging.debug("IP address or port unavailable")
 | 
| -        return None
 | 
| -
 | 
| -    if client == "scp":
 | 
| -        return scp_to_remote(address, port, username, password, local_path,
 | 
| -                             remote_path, log_filename, timeout)
 | 
| -    elif client == "rss":
 | 
| -        c = rss_file_transfer.FileUploadClient(address, port)
 | 
| -        c.upload(local_path, remote_path, timeout)
 | 
| -        c.close()
 | 
| -        return True
 | 
| -
 | 
| -
 | 
| -def copy_files_from(address, client, username, password, port, local_path,
 | 
| -                  remote_path, log_filename=None, timeout=600):
 | 
| -    """
 | 
| -    Decide the transfer cleint and copy file from a remote host (guest).
 | 
| -
 | 
| -    @param client: Type of transfer client
 | 
| -    @param username: Username (if required)
 | 
| -    @param password: Password (if requried)
 | 
| -    @param local_path: Path on the local machine where we are copying from
 | 
| -    @param remote_path: Path on the remote machine where we are copying to
 | 
| -    @param address: Address of remote host(guest)
 | 
| -    @param log_filename: If specified, log all output to this file
 | 
| -    @param timeout: The time duration (in seconds) to wait for the transfer to
 | 
| -    complete.
 | 
| -
 | 
| -    @return: True on success and False on failure.
 | 
| -    """
 | 
| -
 | 
| -    if not address or not port:
 | 
| -        logging.debug("IP address or port unavailable")
 | 
| -        return None
 | 
| -
 | 
| -    if client == "scp":
 | 
| -        return scp_from_remote(address, port, username, password, remote_path,
 | 
| -                             local_path, log_filename, timeout)
 | 
| -    elif client == "rss":
 | 
| -        c = rss_file_transfer.FileDownloadClient(address, port)
 | 
| -        c.download(remote_path, local_path, timeout)
 | 
| -        c.close()
 | 
| -        return True
 | 
| -
 | 
| -
 | 
|  def scp_to_remote(host, port, username, password, local_path, remote_path,
 | 
|                    log_filename=None, timeout=600):
 | 
|      """
 | 
| -    Copy files to a remote host (guest) through scp.
 | 
| +    Copy files to a remote host (guest).
 | 
|  
 | 
|      @param host: Hostname or IP address
 | 
|      @param username: Username (if required)
 | 
| @@ -1068,86 +978,6 @@ def get_vendor_from_pci_id(pci_id):
 | 
|      return re.sub(":", " ", commands.getoutput(cmd))
 | 
|  
 | 
|  
 | 
| -class Thread(threading.Thread):
 | 
| -    """
 | 
| -    Run a function in a background thread.
 | 
| -    """
 | 
| -    def __init__(self, target, args=(), kwargs={}):
 | 
| -        """
 | 
| -        Initialize the instance.
 | 
| -
 | 
| -        @param target: Function to run in the thread.
 | 
| -        @param args: Arguments to pass to target.
 | 
| -        @param kwargs: Keyword arguments to pass to target.
 | 
| -        """
 | 
| -        threading.Thread.__init__(self)
 | 
| -        self._target = target
 | 
| -        self._args = args
 | 
| -        self._kwargs = kwargs
 | 
| -
 | 
| -
 | 
| -    def run(self):
 | 
| -        """
 | 
| -        Run target (passed to the constructor).  No point in calling this
 | 
| -        function directly.  Call start() to make this function run in a new
 | 
| -        thread.
 | 
| -        """
 | 
| -        self._e = None
 | 
| -        self._retval = None
 | 
| -        try:
 | 
| -            try:
 | 
| -                self._retval = self._target(*self._args, **self._kwargs)
 | 
| -            except:
 | 
| -                self._e = sys.exc_info()
 | 
| -                raise
 | 
| -        finally:
 | 
| -            # Avoid circular references (start() may be called only once so
 | 
| -            # it's OK to delete these)
 | 
| -            del self._target, self._args, self._kwargs
 | 
| -
 | 
| -
 | 
| -    def join(self, timeout=None):
 | 
| -        """
 | 
| -        Join the thread.  If target raised an exception, re-raise it.
 | 
| -        Otherwise, return the value returned by target.
 | 
| -
 | 
| -        @param timeout: Timeout value to pass to threading.Thread.join().
 | 
| -        """
 | 
| -        threading.Thread.join(self, timeout)
 | 
| -        try:
 | 
| -            if self._e:
 | 
| -                raise self._e[0], self._e[1], self._e[2]
 | 
| -            else:
 | 
| -                return self._retval
 | 
| -        finally:
 | 
| -            # Avoid circular references (join() may be called multiple times
 | 
| -            # so we can't delete these)
 | 
| -            self._e = None
 | 
| -            self._retval = None
 | 
| -
 | 
| -
 | 
| -def parallel(targets):
 | 
| -    """
 | 
| -    Run multiple functions in parallel.
 | 
| -
 | 
| -    @param targets: A sequence of tuples or functions.  If it's a sequence of
 | 
| -            tuples, each tuple will be interpreted as (target, args, kwargs) or
 | 
| -            (target, args) or (target,) depending on its length.  If it's a
 | 
| -            sequence of functions, the functions will be called without
 | 
| -            arguments.
 | 
| -    @return: A list of the values returned by the functions called.
 | 
| -    """
 | 
| -    threads = []
 | 
| -    for target in targets:
 | 
| -        if isinstance(target, tuple) or isinstance(target, list):
 | 
| -            t = Thread(*target)
 | 
| -        else:
 | 
| -            t = Thread(target)
 | 
| -        threads.append(t)
 | 
| -        t.start()
 | 
| -    return [t.join() for t in threads]
 | 
| -
 | 
| -
 | 
|  class KvmLoggingConfig(logging_config.LoggingConfig):
 | 
|      """
 | 
|      Used with the sole purpose of providing convenient logging setup
 | 
| @@ -1517,7 +1347,7 @@ class KojiDownloader(object):
 | 
|                               "provide an appropriate tag or build name.")
 | 
|  
 | 
|          if not build:
 | 
| -            builds = self.session.listTagged(tag, latest=True, inherit=True,
 | 
| +            builds = self.session.listTagged(tag, latest=True,
 | 
|                                               package=src_package)
 | 
|              if not builds:
 | 
|                  raise ValueError("Tag %s has no builds of %s" % (tag,
 | 
| @@ -1560,58 +1390,3 @@ class KojiDownloader(object):
 | 
|                  rpm_paths.append(r)
 | 
|  
 | 
|          return rpm_paths
 | 
| -
 | 
| -
 | 
| -def umount(src, mount_point, type):
 | 
| -    """
 | 
| -    Umount the src mounted in mount_point.
 | 
| -
 | 
| -    @src: mount source
 | 
| -    @mount_point: mount point
 | 
| -    @type: file system type
 | 
| -    """
 | 
| -
 | 
| -    mount_string = "%s %s %s" % (src, mount_point, type)
 | 
| -    if mount_string in file("/etc/mtab").read():
 | 
| -        umount_cmd = "umount %s" % mount_point
 | 
| -        try:
 | 
| -            utils.system(umount_cmd)
 | 
| -            return True
 | 
| -        except error.CmdError:
 | 
| -            return False
 | 
| -    else:
 | 
| -        logging.debug("%s is not mounted under %s" % (src, mount_point))
 | 
| -        return True
 | 
| -
 | 
| -
 | 
| -def mount(src, mount_point, type, perm="rw"):
 | 
| -    """
 | 
| -    Mount the src into mount_point of the host.
 | 
| -
 | 
| -    @src: mount source
 | 
| -    @mount_point: mount point
 | 
| -    @type: file system type
 | 
| -    @perm: mount premission
 | 
| -    """
 | 
| -    umount(src, mount_point, type)
 | 
| -    mount_string = "%s %s %s %s" % (src, mount_point, type, perm)
 | 
| -
 | 
| -    if mount_string in file("/etc/mtab").read():
 | 
| -        logging.debug("%s is already mounted in %s with %s" %
 | 
| -                      (src, mount_point, perm))
 | 
| -        return True
 | 
| -
 | 
| -    mount_cmd = "mount -t %s %s %s -o %s" % (type, src, mount_point, perm)
 | 
| -    try:
 | 
| -        utils.system(mount_cmd)
 | 
| -    except error.CmdError:
 | 
| -        return False
 | 
| -
 | 
| -    logging.debug("Verify the mount through /etc/mtab")
 | 
| -    if mount_string in file("/etc/mtab").read():
 | 
| -        logging.debug("%s is successfully mounted" % src)
 | 
| -        return True
 | 
| -    else:
 | 
| -        logging.error("Can't find mounted NFS share - /etc/mtab contents \n%s" %
 | 
| -                      file("/etc/mtab").read())
 | 
| -        return False
 | 
| 
 |