Message ID | f4284b903c6d581389a46c305e92904058fa47b6.1248102188.git.mgoldish@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Applied. On Mon, Jul 20, 2009 at 12:07 PM, Michael Goldish<mgoldish@redhat.com> wrote: > These are now provided by kvm_subprocess.py. > > Signed-off-by: Michael Goldish <mgoldish@redhat.com> > --- > Â client/tests/kvm/kvm_utils.py | Â 477 +---------------------------------------- > Â 1 files changed, 2 insertions(+), 475 deletions(-) > > diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py > index fb587c5..9391874 100644 > --- a/client/tests/kvm/kvm_utils.py > +++ b/client/tests/kvm/kvm_utils.py > @@ -227,390 +227,8 @@ def check_kvm_source_dir(source_dir): > Â Â Â Â raise error.TestError("Unknown source dir layout, cannot proceed.") > > > -# The following are a class and functions used for SSH, SCP and Telnet > -# communication with guests. > - > -class kvm_spawn: > - Â Â """ > - Â Â This class is used for spawning and controlling a child process. > - Â Â """ > - > - Â Â def __init__(self, command, linesep="\n"): > - Â Â Â Â """ > - Â Â Â Â Initialize the class and run command as a child process. > - > - Â Â Â Â @param command: Command that will be run. > - Â Â Â Â @param linesep: Line separator for the given platform. > - Â Â Â Â """ > - Â Â Â Â self.exitstatus = None > - Â Â Â Â self.linesep = linesep > - Â Â Â Â (pid, fd) = pty.fork() > - Â Â Â Â if pid == 0: > - Â Â Â Â Â Â os.execv("/bin/sh", ["/bin/sh", "-c", command]) > - Â Â Â Â else: > - Â Â Â Â Â Â self.pid = pid > - Â Â Â Â Â Â self.fd = fd > - > - > - Â Â def set_linesep(self, linesep): > - Â Â Â Â """ > - Â Â Â Â Sets the line separator string (usually "\\n"). > - > - Â Â Â Â @param linesep: Line separator character. > - Â Â Â Â """ > - Â Â Â Â self.linesep = linesep > - > - > - Â Â def is_responsive(self, timeout=5.0): > - Â Â Â Â """ > - Â Â Â Â Return True if the session is responsive. > - > - Â Â Â Â Send a newline to the child process (e.g. SSH or Telnet) and read some > - Â Â Â Â output using read_nonblocking. > - Â Â Â Â If all is OK, some output should be available (e.g. the shell prompt). > - Â Â Â Â In that case return True. Otherwise return False. > - > - Â Â Â Â @param timeout: Timeout that will happen before we consider the > - Â Â Â Â Â Â Â Â process unresponsive > - Â Â Â Â """ > - Â Â Â Â self.read_nonblocking(timeout=0.1) > - Â Â Â Â self.sendline() > - Â Â Â Â output = self.read_nonblocking(timeout=timeout) > - Â Â Â Â if output.strip(): > - Â Â Â Â Â Â return True > - Â Â Â Â return False > - > - > - Â Â def poll(self): > - Â Â Â Â """ > - Â Â Â Â If the process exited, return its exit status. Otherwise return None. > - Â Â Â Â The exit status is stored for use in subsequent calls. > - Â Â Â Â """ > - Â Â Â Â if self.exitstatus != None: > - Â Â Â Â Â Â return self.exitstatus > - Â Â Â Â pid, status = os.waitpid(self.pid, os.WNOHANG) > - Â Â Â Â if pid: > - Â Â Â Â Â Â self.exitstatus = os.WEXITSTATUS(status) > - Â Â Â Â Â Â return self.exitstatus > - Â Â Â Â else: > - Â Â Â Â Â Â return None > - > - > - Â Â def close(self): > - Â Â Â Â """ > - Â Â Â Â Close the session (close the process filedescriptors and kills the > - Â Â Â Â process ID), and return the exit status. > - Â Â Â Â """ > - Â Â Â Â try: > - Â Â Â Â Â Â os.close(self.fd) > - Â Â Â Â Â Â os.kill(self.pid, signal.SIGTERM) > - Â Â Â Â except OSError: > - Â Â Â Â Â Â pass > - Â Â Â Â return self.poll() > - > - > - Â Â def sendline(self, str=""): > - Â Â Â Â """ > - Â Â Â Â Sends a string followed by a line separator to the child process. > - > - Â Â Â Â @param str: String that will be sent to the child process. > - Â Â Â Â """ > - Â Â Â Â try: > - Â Â Â Â Â Â os.write(self.fd, str + self.linesep) > - Â Â Â Â except OSError: > - Â Â Â Â Â Â pass > - > - > - Â Â def read_nonblocking(self, timeout=1.0): > - Â Â Â Â """ > - Â Â Â Â Read from child until there is nothing to read for timeout seconds. > - > - Â Â Â Â @param timeout: Time (seconds) of wait before we give up reading from > - Â Â Â Â Â Â Â Â the child process. > - Â Â Â Â """ > - Â Â Â Â data = "" > - Â Â Â Â while True: > - Â Â Â Â Â Â r, w, x = select.select([self.fd], [], [], timeout) > - Â Â Â Â Â Â if self.fd in r: > - Â Â Â Â Â Â Â Â try: > - Â Â Â Â Â Â Â Â Â Â data += os.read(self.fd, 1024) > - Â Â Â Â Â Â Â Â except OSError: > - Â Â Â Â Â Â Â Â Â Â return data > - Â Â Â Â Â Â else: > - Â Â Â Â Â Â Â Â return data > - > - > - Â Â def match_patterns(self, str, patterns): > - Â Â Â Â """ > - Â Â Â Â Match str against a list of patterns. > - > - Â Â Â Â Return the index of the first pattern that matches a substring of str. > - Â Â Â Â None and empty strings in patterns are ignored. > - Â Â Â Â If no match is found, return None. > - > - Â Â Â Â @param patterns: List of strings (regular expression patterns). > - Â Â Â Â """ > - Â Â Â Â for i in range(len(patterns)): > - Â Â Â Â Â Â if not patterns[i]: > - Â Â Â Â Â Â Â Â continue > - Â Â Â Â Â Â exp = re.compile(patterns[i]) > - Â Â Â Â Â Â if exp.search(str): > - Â Â Â Â Â Â Â Â return i > - > - > - Â Â def read_until_output_matches(self, patterns, filter=lambda(x):x, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â timeout=30.0, internal_timeout=1.0, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â 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 (or None if no match was > - Â Â Â Â Â Â Â Â found) and the data read so far. > - Â Â Â Â """ > - Â Â Â Â match = None > - Â Â Â Â data = "" > - > - Â Â Â Â end_time = time.time() + timeout > - Â Â Â Â while time.time() < end_time: > - Â Â Â Â Â Â # Read data from child > - Â Â Â Â Â Â newdata = self.read_nonblocking(internal_timeout) > - Â Â Â Â Â Â # Print it if necessary > - Â Â Â Â Â Â if print_func and newdata: > - Â Â Â Â Â Â Â Â map(print_func, newdata.splitlines()) > - Â Â Â Â Â Â data += newdata > - > - Â Â Â Â Â Â done = False > - Â Â Â Â Â Â # Look for patterns > - Â Â Â Â Â Â match = self.match_patterns(filter(data), patterns) > - Â Â Â Â Â Â if match != None: > - Â Â Â Â Â Â Â Â done = True > - Â Â Â Â Â Â # Check if child has died > - Â Â Â Â Â Â if self.poll() != None: > - Â Â Â Â Â Â Â Â logging.debug("Process terminated with status %d", self.poll()) > - Â Â Â Â Â Â Â Â done = True > - Â Â Â Â Â Â # Are we done? > - Â Â Â Â Â Â if done: break > - > - Â Â Â Â # Print some debugging info > - Â Â Â Â if match == None and self.poll() != 0: > - Â Â Â Â Â Â logging.debug("Timeout elapsed or process terminated. Output: %s", > - Â Â Â Â Â Â Â Â Â Â Â Â Â format_str_for_message(data.strip())) > - > - Â Â Â Â return (match, data) > - > - > - Â Â def get_last_word(self, str): > - Â Â Â Â """ > - Â Â Â Â Return the last word in str. > - > - Â Â Â Â @param str: String that will be analyzed. > - Â Â Â Â """ > - Â Â Â Â if str: > - Â Â Â Â Â Â return str.split()[-1] > - Â Â Â Â else: > - Â Â Â Â Â Â return "" > - > - > - Â Â def get_last_line(self, str): > - Â Â Â Â """ > - Â Â Â Â Return the last non-empty line in str. > - > - Â Â Â Â @param str: String that will be analyzed. > - Â Â Â Â """ > - Â Â Â Â last_line = "" > - Â Â Â Â for line in str.splitlines(): > - Â Â Â Â Â Â if line != "": > - Â Â Â Â Â Â Â Â last_line = line > - Â Â Â Â return last_line > - > - > - Â Â def read_until_last_word_matches(self, patterns, timeout=30.0, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â internal_timeout=1.0, print_func=None): > - Â Â Â Â """ > - Â Â Â Â Read using read_nonblocking until the last word of the output matches > - Â Â Â Â one of the patterns (using match_patterns), or until timeout expires. > - > - Â Â Â Â @param patterns: A list of strings (regular expression patterns) > - Â Â Â Â @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: A tuple containing the match index (or None if no match was > - Â Â Â Â Â Â Â Â found) and the data read so far. > - Â Â Â Â """ > - Â Â Â Â return self.read_until_output_matches(patterns, self.get_last_word, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â timeout, internal_timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â print_func) > - > - > - Â Â def read_until_last_line_matches(self, patterns, timeout=30.0, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â internal_timeout=1.0, print_func=None): > - Â Â Â Â """ > - Â Â Â Â Read using read_nonblocking until the last non-empty line of the output > - Â Â Â Â matches one of the patterns (using match_patterns), or until timeout > - Â Â Â Â expires. Return a tuple containing the match index (or None if no match > - Â Â Â Â was found) and the data read so far. > - > - Â Â Â Â @brief: Read using read_nonblocking until the last non-empty line > - Â Â Â Â Â Â Â Â matches a pattern. > - > - Â Â Â Â @param patterns: A list of strings (regular expression patterns) > - Â Â Â Â @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 self.read_until_output_matches(patterns, self.get_last_line, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â timeout, internal_timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â print_func) > - > - > - Â Â def set_prompt(self, prompt): > - Â Â Â Â """ > - Â Â Â Â Set the prompt attribute for later use by read_up_to_prompt. > - > - Â Â Â Â @param: String that describes the prompt contents. > - Â Â Â Â """ > - Â Â Â Â self.prompt = prompt > - > - > - Â Â def read_up_to_prompt(self, timeout=30.0, internal_timeout=1.0, > - Â Â Â Â Â Â Â Â Â Â Â Â Â print_func=None): > - Â Â Â Â """ > - Â Â Â Â Read using read_nonblocking until the last non-empty line of the output > - Â Â Â Â matches the prompt regular expression set by set_prompt, or until > - Â Â Â Â timeout expires. > - > - Â Â Â Â @brief: Read using read_nonblocking until the last non-empty line > - Â Â Â Â Â Â Â Â matches the prompt. > - > - Â Â Â Â @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: A tuple containing True/False indicating whether the prompt > - Â Â Â Â Â Â Â Â was found, and the data read so far. > - Â Â Â Â """ > - Â Â Â Â (match, output) = self.read_until_last_line_matches([self.prompt], > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â internal_timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â print_func) > - Â Â Â Â if match == None: > - Â Â Â Â Â Â return (False, output) > - Â Â Â Â else: > - Â Â Â Â Â Â return (True, output) > - > - > - Â Â def set_status_test_command(self, status_test_command): > - Â Â Â Â """ > - Â Â Â Â Set the command to be sent in order to get the last exit status. > - > - Â Â Â Â @param status_test_command: Command that will be sent to get the last > - Â Â Â Â Â Â Â Â exit status. > - Â Â Â Â """ > - Â Â Â Â self.status_test_command = status_test_command > - > - > - Â Â def get_command_status_output(self, command, timeout=30.0, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â internal_timeout=1.0, print_func=None): > - Â Â Â Â """ > - Â Â Â Â Send a command and return its exit status and output. > - > - Â Â Â Â @param command: Command to send > - Â Â Â Â @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: A tuple (status, output) where status is the exit status or > - Â Â Â Â Â Â Â Â None if no exit status is available (e.g. timeout elapsed), and > - Â Â Â Â Â Â Â Â output is the output of command. > - Â Â Â Â """ > - Â Â Â Â # Print some debugging info > - Â Â Â Â logging.debug("Sending command: %s" % command) > - > - Â Â Â Â # Read everything that's waiting to be read > - Â Â Â Â self.read_nonblocking(0.1) > - > - Â Â Â Â # Send the command and get its output > - Â Â Â Â self.sendline(command) > - Â Â Â Â (match, output) = self.read_up_to_prompt(timeout, internal_timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â print_func) > - Â Â Â Â if not match: > - Â Â Â Â Â Â return (None, "\n".join(output.splitlines()[1:])) > - Â Â Â Â output = "\n".join(output.splitlines()[1:-1]) > - > - Â Â Â Â # Send the 'echo ...' command to get the last exit status > - Â Â Â Â self.sendline(self.status_test_command) > - Â Â Â Â (match, status) = self.read_up_to_prompt(10.0, internal_timeout) > - Â Â Â Â if not match: > - Â Â Â Â Â Â return (None, output) > - Â Â Â Â status = int("\n".join(status.splitlines()[1:-1]).strip()) > - > - Â Â Â Â # Print some debugging info > - Â Â Â Â if status != 0: > - Â Â Â Â Â Â logging.debug("Command failed; status: %d, output:%s", status, > - Â Â Â Â Â Â Â Â Â Â Â Â Â format_str_for_message(output.strip())) > - > - Â Â Â Â return (status, output) > - > - > - Â Â def get_command_status(self, command, timeout=30.0, internal_timeout=1.0, > - Â Â Â Â Â Â Â Â Â Â Â Â Â print_func=None): > - Â Â Â Â """ > - Â Â Â Â Send a command and return its exit status. > - > - Â Â Â Â @param command: Command to send > - Â Â Â Â @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: Exit status or None if no exit status is available (e.g. > - Â Â Â Â Â Â Â Â timeout elapsed). > - Â Â Â Â """ > - Â Â Â Â (status, output) = self.get_command_status_output(command, timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â internal_timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â print_func) > - Â Â Â Â return status > - > - > - Â Â def get_command_output(self, command, timeout=30.0, internal_timeout=1.0, > - Â Â Â Â Â Â Â Â Â Â Â Â Â print_func=None): > - Â Â Â Â """ > - Â Â Â Â Send a command and return its output. > - > - Â Â Â Â @param command: Command to send > - Â Â Â Â @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) > - Â Â Â Â """ > - Â Â Â Â (status, output) = self.get_command_status_output(command, timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â internal_timeout, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â print_func) > - Â Â Â Â return output > - > +# The following are functions used for SSH, SCP and Telnet communication with > +# guests. > > Â def remote_login(command, password, prompt, linesep="\n", timeout=10): > Â Â """ > @@ -810,97 +428,6 @@ def telnet(host, port, username, password, prompt, timeout=10): > Â Â return remote_login(command, password, prompt, "\r\n", timeout) > > > -# The following are functions used for running commands in the background. > - > -def track_process(sub, status_output=None, term_func=None, stdout_func=None, > - Â Â Â Â Â Â Â Â Â prefix=""): > - Â Â """ > - Â Â Read lines from the stdout pipe of the subprocess. Pass each line to > - Â Â stdout_func prefixed by prefix. Place the lines in status_output[1]. > - Â Â When the subprocess exits, call term_func. Place the exit status in > - Â Â status_output[0]. > - > - Â Â @brief Track a subprocess and report its output and termination. > - > - Â Â @param sub: An object returned by subprocess.Popen > - Â Â @param status_output: A list in which the exit status and output are to be > - Â Â Â Â Â Â stored. > - Â Â @param term_func: A function to call when the process terminates > - Â Â Â Â Â Â (should take no parameters) > - Â Â @param stdout_func: A function to call with each line of output from the > - Â Â Â Â Â Â subprocess (should take a string parameter) > - > - Â Â @param prefix -- a string to pre-pend to each line of the output, before > - Â Â Â Â Â Â passing it to stdout_func > - Â Â """ > - Â Â while True: > - Â Â Â Â # Read a single line from stdout > - Â Â Â Â text = sub.stdout.readline() > - Â Â Â Â # If the subprocess exited... > - Â Â Â Â if text == "": > - Â Â Â Â Â Â # Get exit code > - Â Â Â Â Â Â status = sub.wait() > - Â Â Â Â Â Â # Report it > - Â Â Â Â Â Â if status_output: > - Â Â Â Â Â Â Â Â status_output[0] = status > - Â Â Â Â Â Â # Call term_func > - Â Â Â Â Â Â if term_func: > - Â Â Â Â Â Â Â Â term_func() > - Â Â Â Â Â Â return > - Â Â Â Â # Report the text > - Â Â Â Â if status_output: > - Â Â Â Â Â Â status_output[1] += text > - Â Â Â Â # Call stdout_func with the returned text > - Â Â Â Â if stdout_func: > - Â Â Â Â Â Â text = prefix + text.strip() > - Â Â Â Â Â Â # We need to sanitize the text before passing it to the logging > - Â Â Â Â Â Â # system > - Â Â Â Â Â Â text = text.decode('utf-8', 'replace') > - Â Â Â Â Â Â stdout_func(text) > - > - > -def run_bg(command, term_func=None, stdout_func=None, prefix="", timeout=1.0): > - Â Â """ > - Â Â Run command as a subprocess. Call stdout_func with each line of output from > - Â Â the subprocess (prefixed by prefix). Call term_func when the subprocess > - Â Â terminates. If timeout expires and the subprocess is still running, return. > - > - Â Â @brief: Run a subprocess in the background and collect its output and > - Â Â Â Â Â Â exit status. > - > - Â Â @param command: The shell command to execute > - Â Â @param term_func: A function to call when the process terminates > - Â Â Â Â Â Â (should take no parameters) > - Â Â @param stdout_func: A function to call with each line of output from > - Â Â Â Â Â Â the subprocess (should take a string parameter) > - Â Â @param prefix: A string to pre-pend to each line of the output, before > - Â Â Â Â Â Â passing it to stdout_func > - Â Â @param timeout: Time duration (in seconds) to wait for the subprocess to > - Â Â Â Â Â Â terminate before returning > - > - Â Â @return: A 3-tuple containing the exit status (None if the subprocess is > - Â Â Â Â Â Â still running), the PID of the subprocess (None if the subprocess > - Â Â Â Â Â Â terminated), and the output collected so far. > - Â Â """ > - Â Â # Start the process > - Â Â sub = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, > - Â Â Â Â Â Â Â Â Â Â Â Â Â stderr=subprocess.STDOUT) > - Â Â # Start the tracking thread > - Â Â status_output = [None, ""] > - Â Â thread.start_new_thread(track_process, (sub, status_output, term_func, > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â stdout_func, prefix)) > - Â Â # Wait up to timeout secs for the process to exit > - Â Â end_time = time.time() + timeout > - Â Â while time.time() < end_time: > - Â Â Â Â # If the process exited, return > - Â Â Â Â if status_output[0] != None: > - Â Â Â Â Â Â return (status_output[0], None, status_output[1]) > - Â Â Â Â # Otherwise, sleep for a while > - Â Â Â Â time.sleep(0.1) > - Â Â # Report the PID and the output collected so far > - Â Â return (None, sub.pid, status_output[1]) > - > - > Â # The following are utility functions related to ports. > > Â def is_sshd_running(host, port, timeout=10.0): > -- > 1.5.4.1 > > _______________________________________________ > Autotest mailing list > Autotest@test.kernel.org > http://test.kernel.org/cgi-bin/mailman/listinfo/autotest >
diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py index fb587c5..9391874 100644 --- a/client/tests/kvm/kvm_utils.py +++ b/client/tests/kvm/kvm_utils.py @@ -227,390 +227,8 @@ def check_kvm_source_dir(source_dir): raise error.TestError("Unknown source dir layout, cannot proceed.") -# The following are a class and functions used for SSH, SCP and Telnet -# communication with guests. - -class kvm_spawn: - """ - This class is used for spawning and controlling a child process. - """ - - def __init__(self, command, linesep="\n"): - """ - Initialize the class and run command as a child process. - - @param command: Command that will be run. - @param linesep: Line separator for the given platform. - """ - self.exitstatus = None - self.linesep = linesep - (pid, fd) = pty.fork() - if pid == 0: - os.execv("/bin/sh", ["/bin/sh", "-c", command]) - else: - self.pid = pid - self.fd = fd - - - def set_linesep(self, linesep): - """ - Sets the line separator string (usually "\\n"). - - @param linesep: Line separator character. - """ - self.linesep = linesep - - - def is_responsive(self, timeout=5.0): - """ - Return True if the session is responsive. - - Send a newline to the child process (e.g. SSH or Telnet) and read some - output using read_nonblocking. - If all is OK, some output should be available (e.g. the shell prompt). - In that case return True. Otherwise return False. - - @param timeout: Timeout that will happen before we consider the - process unresponsive - """ - self.read_nonblocking(timeout=0.1) - self.sendline() - output = self.read_nonblocking(timeout=timeout) - if output.strip(): - return True - return False - - - def poll(self): - """ - If the process exited, return its exit status. Otherwise return None. - The exit status is stored for use in subsequent calls. - """ - if self.exitstatus != None: - return self.exitstatus - pid, status = os.waitpid(self.pid, os.WNOHANG) - if pid: - self.exitstatus = os.WEXITSTATUS(status) - return self.exitstatus - else: - return None - - - def close(self): - """ - Close the session (close the process filedescriptors and kills the - process ID), and return the exit status. - """ - try: - os.close(self.fd) - os.kill(self.pid, signal.SIGTERM) - except OSError: - pass - return self.poll() - - - def sendline(self, str=""): - """ - Sends a string followed by a line separator to the child process. - - @param str: String that will be sent to the child process. - """ - try: - os.write(self.fd, str + self.linesep) - except OSError: - pass - - - def read_nonblocking(self, timeout=1.0): - """ - Read from child until there is nothing to read for timeout seconds. - - @param timeout: Time (seconds) of wait before we give up reading from - the child process. - """ - data = "" - while True: - r, w, x = select.select([self.fd], [], [], timeout) - if self.fd in r: - try: - data += os.read(self.fd, 1024) - except OSError: - return data - else: - return data - - - def match_patterns(self, str, patterns): - """ - Match str against a list of patterns. - - Return the index of the first pattern that matches a substring of str. - None and empty strings in patterns are ignored. - If no match is found, return None. - - @param patterns: List of strings (regular expression patterns). - """ - for i in range(len(patterns)): - if not patterns[i]: - continue - exp = re.compile(patterns[i]) - if exp.search(str): - return i - - - def read_until_output_matches(self, patterns, filter=lambda(x):x, - timeout=30.0, internal_timeout=1.0, - 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 (or None if no match was - found) and the data read so far. - """ - match = None - data = "" - - end_time = time.time() + timeout - while time.time() < end_time: - # Read data from child - newdata = self.read_nonblocking(internal_timeout) - # Print it if necessary - if print_func and newdata: - map(print_func, newdata.splitlines()) - data += newdata - - done = False - # Look for patterns - match = self.match_patterns(filter(data), patterns) - if match != None: - done = True - # Check if child has died - if self.poll() != None: - logging.debug("Process terminated with status %d", self.poll()) - done = True - # Are we done? - if done: break - - # Print some debugging info - if match == None and self.poll() != 0: - logging.debug("Timeout elapsed or process terminated. Output: %s", - format_str_for_message(data.strip())) - - return (match, data) - - - def get_last_word(self, str): - """ - Return the last word in str. - - @param str: String that will be analyzed. - """ - if str: - return str.split()[-1] - else: - return "" - - - def get_last_line(self, str): - """ - Return the last non-empty line in str. - - @param str: String that will be analyzed. - """ - last_line = "" - for line in str.splitlines(): - if line != "": - last_line = line - return last_line - - - def read_until_last_word_matches(self, patterns, timeout=30.0, - internal_timeout=1.0, print_func=None): - """ - Read using read_nonblocking until the last word of the output matches - one of the patterns (using match_patterns), or until timeout expires. - - @param patterns: A list of strings (regular expression patterns) - @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: A tuple containing the match index (or None if no match was - found) and the data read so far. - """ - return self.read_until_output_matches(patterns, self.get_last_word, - timeout, internal_timeout, - print_func) - - - def read_until_last_line_matches(self, patterns, timeout=30.0, - internal_timeout=1.0, print_func=None): - """ - Read using read_nonblocking until the last non-empty line of the output - matches one of the patterns (using match_patterns), or until timeout - expires. Return a tuple containing the match index (or None if no match - was found) and the data read so far. - - @brief: Read using read_nonblocking until the last non-empty line - matches a pattern. - - @param patterns: A list of strings (regular expression patterns) - @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 self.read_until_output_matches(patterns, self.get_last_line, - timeout, internal_timeout, - print_func) - - - def set_prompt(self, prompt): - """ - Set the prompt attribute for later use by read_up_to_prompt. - - @param: String that describes the prompt contents. - """ - self.prompt = prompt - - - def read_up_to_prompt(self, timeout=30.0, internal_timeout=1.0, - print_func=None): - """ - Read using read_nonblocking until the last non-empty line of the output - matches the prompt regular expression set by set_prompt, or until - timeout expires. - - @brief: Read using read_nonblocking until the last non-empty line - matches the prompt. - - @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: A tuple containing True/False indicating whether the prompt - was found, and the data read so far. - """ - (match, output) = self.read_until_last_line_matches([self.prompt], - timeout, - internal_timeout, - print_func) - if match == None: - return (False, output) - else: - return (True, output) - - - def set_status_test_command(self, status_test_command): - """ - Set the command to be sent in order to get the last exit status. - - @param status_test_command: Command that will be sent to get the last - exit status. - """ - self.status_test_command = status_test_command - - - def get_command_status_output(self, command, timeout=30.0, - internal_timeout=1.0, print_func=None): - """ - Send a command and return its exit status and output. - - @param command: Command to send - @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: A tuple (status, output) where status is the exit status or - None if no exit status is available (e.g. timeout elapsed), and - output is the output of command. - """ - # Print some debugging info - logging.debug("Sending command: %s" % command) - - # Read everything that's waiting to be read - self.read_nonblocking(0.1) - - # Send the command and get its output - self.sendline(command) - (match, output) = self.read_up_to_prompt(timeout, internal_timeout, - print_func) - if not match: - return (None, "\n".join(output.splitlines()[1:])) - output = "\n".join(output.splitlines()[1:-1]) - - # Send the 'echo ...' command to get the last exit status - self.sendline(self.status_test_command) - (match, status) = self.read_up_to_prompt(10.0, internal_timeout) - if not match: - return (None, output) - status = int("\n".join(status.splitlines()[1:-1]).strip()) - - # Print some debugging info - if status != 0: - logging.debug("Command failed; status: %d, output:%s", status, - format_str_for_message(output.strip())) - - return (status, output) - - - def get_command_status(self, command, timeout=30.0, internal_timeout=1.0, - print_func=None): - """ - Send a command and return its exit status. - - @param command: Command to send - @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: Exit status or None if no exit status is available (e.g. - timeout elapsed). - """ - (status, output) = self.get_command_status_output(command, timeout, - internal_timeout, - print_func) - return status - - - def get_command_output(self, command, timeout=30.0, internal_timeout=1.0, - print_func=None): - """ - Send a command and return its output. - - @param command: Command to send - @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) - """ - (status, output) = self.get_command_status_output(command, timeout, - internal_timeout, - print_func) - return output - +# The following are functions used for SSH, SCP and Telnet communication with +# guests. def remote_login(command, password, prompt, linesep="\n", timeout=10): """ @@ -810,97 +428,6 @@ def telnet(host, port, username, password, prompt, timeout=10): return remote_login(command, password, prompt, "\r\n", timeout) -# The following are functions used for running commands in the background. - -def track_process(sub, status_output=None, term_func=None, stdout_func=None, - prefix=""): - """ - Read lines from the stdout pipe of the subprocess. Pass each line to - stdout_func prefixed by prefix. Place the lines in status_output[1]. - When the subprocess exits, call term_func. Place the exit status in - status_output[0]. - - @brief Track a subprocess and report its output and termination. - - @param sub: An object returned by subprocess.Popen - @param status_output: A list in which the exit status and output are to be - stored. - @param term_func: A function to call when the process terminates - (should take no parameters) - @param stdout_func: A function to call with each line of output from the - subprocess (should take a string parameter) - - @param prefix -- a string to pre-pend to each line of the output, before - passing it to stdout_func - """ - while True: - # Read a single line from stdout - text = sub.stdout.readline() - # If the subprocess exited... - if text == "": - # Get exit code - status = sub.wait() - # Report it - if status_output: - status_output[0] = status - # Call term_func - if term_func: - term_func() - return - # Report the text - if status_output: - status_output[1] += text - # Call stdout_func with the returned text - if stdout_func: - text = prefix + text.strip() - # We need to sanitize the text before passing it to the logging - # system - text = text.decode('utf-8', 'replace') - stdout_func(text) - - -def run_bg(command, term_func=None, stdout_func=None, prefix="", timeout=1.0): - """ - Run command as a subprocess. Call stdout_func with each line of output from - the subprocess (prefixed by prefix). Call term_func when the subprocess - terminates. If timeout expires and the subprocess is still running, return. - - @brief: Run a subprocess in the background and collect its output and - exit status. - - @param command: The shell command to execute - @param term_func: A function to call when the process terminates - (should take no parameters) - @param stdout_func: A function to call with each line of output from - the subprocess (should take a string parameter) - @param prefix: A string to pre-pend to each line of the output, before - passing it to stdout_func - @param timeout: Time duration (in seconds) to wait for the subprocess to - terminate before returning - - @return: A 3-tuple containing the exit status (None if the subprocess is - still running), the PID of the subprocess (None if the subprocess - terminated), and the output collected so far. - """ - # Start the process - sub = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - # Start the tracking thread - status_output = [None, ""] - thread.start_new_thread(track_process, (sub, status_output, term_func, - stdout_func, prefix)) - # Wait up to timeout secs for the process to exit - end_time = time.time() + timeout - while time.time() < end_time: - # If the process exited, return - if status_output[0] != None: - return (status_output[0], None, status_output[1]) - # Otherwise, sleep for a while - time.sleep(0.1) - # Report the PID and the output collected so far - return (None, sub.pid, status_output[1]) - - # The following are utility functions related to ports. def is_sshd_running(host, port, timeout=10.0):
These are now provided by kvm_subprocess.py. Signed-off-by: Michael Goldish <mgoldish@redhat.com> --- client/tests/kvm/kvm_utils.py | 477 +---------------------------------------- 1 files changed, 2 insertions(+), 475 deletions(-)