title: Implement timeout for paramiko with an interactive element
body: <p>This question is a followup to this question: <a href="https://stackoverflow.com/questions/15149093/using-paramiko-to-send-commands-to-an-open-shell-that-has-an-interactive-element">Using paramiko to send commands to an open shell that has an interactive element</a> so please read that before answering here.</p>
  
  <p>I'm successfully able to send data to the array's system shell, however I need help figuring out how to implement a timeout when the array is taking too long to run the script I've sent it. Paramiko's <code>exec_command</code> has a <code>timeout=</code> parameter, but that's not going to help here as the only command I'm sending is <code>"script"</code> which immediately returns and waits for input on the channel, and when I tried implementing it seems to break the rest of the function as nothing returns from the array.</p>
  
  <p>The array is then supposed to processes the script I've sent it and return the output via <code>stdout</code>, however if the array takes a long time I have no way of timing out the connection, and it holds up the rest of the script.</p>
  
  <p>Here's the code I have:</p>
  
  <pre><code>def run_script(self, script_name):
      """ Run a script on the remote array and return the stdout
      """
      try:
          common_functions_file = os.path.join(SCRIPT_DIR, 'zfs_common_functions.js')
          common_functions = open(common_functions_file).read().splitlines()
          # add common_functions to the top of the script
          script_contents = common_functions + open(script_name).read().splitlines()
          stdin, stdout, stderr = self._ssh.exec_command('script')
          for line in script_contents:
              # Skip lines with comments
              if re.match("^//", line):
                  continue
              stdin.write(line)
              stdin.write('\n')
          stdin.write('.\n')
          stdin.flush()
          error = stderr.readlines()
          if len(error) == 0:
              try:
                  output = ''.join(stdout.readlines())
                  if(re.search('aksh', output)):
                      logger.warn("ZFS Shell Error: %s" % output)
                      return None
                  return output
              except Exception as e:
                  logger.exception(e)
  
          else:
              logger.error(error)
              return None
      except paramiko.SSHException as e:
          logger.warn(
              "Couldn't execute script on array %s: %s" % (array.name, e))
  
      except AttributeError as e:
          logger.exception(e)
          raise
  
      except Exception:
          raise
  </code></pre>