KVM test: Remove kvm_spawn and run_bg() from kvm_utils.py
These are now provided by kvm_subprocess.py.
Signed-off-by: Michael Goldish <mgoldish@redhat.com>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@3432 592f7852-d20e-0410-864c-8624ca9c26a4
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 @@
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 @@
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):