def open_shell(command=None): """ Invoke a fully interactive shell on the remote end. If ``command`` is given, it will be sent down the pipe before handing control over to the invoking user. This function is most useful for when you need to interact with a heavily shell-based command or series of commands, such as when debugging or when fully interactive recovery is required upon remote program failure. It should be considered an easy way to work an interactive shell session into the middle of a Fabric script and is *not* a drop-in replacement for `~fabric.operations.run`, which is also capable of interacting with the remote end (albeit only while its given command is executing) and has much stronger programmatic abilities such as error handling and stdout/stderr capture. Specifically, `~fabric.operations.open_shell` provides a better interactive experience than `~fabric.operations.run`, but use of a full remote shell prevents Fabric from determining whether programs run within the shell have failed, and pollutes the stdout/stderr stream with shell output such as login banners, prompts and echoed stdin. Thus, this function does not have a return value and will not trigger Fabric's failure handling if any remote programs result in errors. .. versionadded:: 1.0 """ _execute(channel=default_channel(), command=command, pty=True, combine_stderr=True, invoke_shell=True)
def _run_command(command, shell=True, pty=True, combine_stderr=True, sudo=False, user=None, quiet=False, stdout=None, stderr=None): """ Underpinnings of `run` and `sudo`. See their docstrings for more info. """ with quiet_manager() if quiet else _noop(): # Set up new var so original argument can be displayed verbatim later. given_command = command # Handle context manager modifications, and shell wrapping wrapped_command = _shell_wrap( _prefix_commands(_prefix_env_vars(command), 'remote'), shell, _sudo_prefix(user) if sudo else None ) # Execute info line which = 'sudo' if sudo else 'run' if output.debug: print("[%s] %s: %s" % (env.host_string, which, wrapped_command)) elif output.running or env.dry_run_remote: print("[%s] %s: %s" % (env.host_string, which, given_command)) if env.dry_run_remote: # Fake exeuction, assume command completed ok and returned 0 stdout, stderr, status = ("", "", 0) else: # Actual execution, stdin/stdout/stderr handling, and termination result_stdout, result_stderr, status = _execute(default_channel(), wrapped_command, pty, combine_stderr, stdout, stderr) # Assemble output string out = _AttributeString(result_stdout) err = _AttributeString(result_stderr) # Error handling out.failed = False if status != 0: out.failed = True msg = "%s() received nonzero return code %s while executing" % ( which, status ) if env.warn_only: msg += " '%s'!" % given_command else: msg += "!\n\nRequested: %s\nExecuted: %s" % ( given_command, wrapped_command ) error(message=msg, stdout=out, stderr=err) # Attach return code to output string so users who have set things to # warn only, can inspect the error code. out.return_code = status # Convenience mirror of .failed out.succeeded = not out.failed # Attach stderr for anyone interested in that. out.stderr = err return out
def _test_channel(self): chan = spawn(default_channel(), '/bin/sh') chan.send('ls') fd = chan.channel.makefile() res = fd.readline() while len(res): print ">>" + res print ">>" + str(len(res)) res = fd.readline()
def _run_host_command(command, shell=True, pty=True, combine_stderr=True): """ Run host wrapper command as root (Modified from fabric.operations._run_command to ignore prefixes, path(), cd(), and always use sudo.) """ # Set up new var so original argument can be displayed verbatim later. given_command = command # Handle context manager modifications, and shell wrapping wrapped_command = _shell_wrap( command, shell, _sudo_prefix(None) ) # Execute info line if output.debug: print("[%s] %s: %s" % (env.host_string, 'sudo', wrapped_command)) elif output.running: print("[%s] %s: %s" % (env.host_string, 'sudo', given_command)) # Actual execution, stdin/stdout/stderr handling, and termination stdout, stderr, status = _execute(default_channel(), wrapped_command, pty, combine_stderr) # Assemble output string out = _AttributeString(stdout) err = _AttributeString(stderr) # Error handling out.failed = False if status != 0: out.failed = True msg = "%s() received nonzero return code %s while executing" % ( 'sudo', status ) if env.warn_only: msg += " '%s'!" % given_command else: msg += "!\n\nRequested: %s\nExecuted: %s" % ( given_command, wrapped_command ) error(message=msg, stdout=out, stderr=err) # Attach return code to output string so users who have set things to # warn only, can inspect the error code. out.return_code = status # Convenience mirror of .failed out.succeeded = not out.failed # Attach stderr for anyone interested in that. out.stderr = err return out
def _run_command(command, shell=True, pty=True, combine_stderr=True, sudo=False, user=None): """ Underpinnings of `run` and `sudo`. See their docstrings for more info. """ # Set up new var so original argument can be displayed verbatim later. given_command = command # Handle context manager modifications, and shell wrapping wrapped_command = _shell_wrap( _prefix_commands(_prefix_env_vars(command), 'remote'), shell, _sudo_prefix(user) if sudo else None) # Execute info line which = 'sudo' if sudo else 'run' if output.debug: print("[%s] %s: %s" % (env.host_string, which, wrapped_command)) elif output.running: print("[%s] %s: %s" % (env.host_string, which, given_command)) # Actual execution, stdin/stdout/stderr handling, and termination stdout, stderr, status = _execute(default_channel(), wrapped_command, pty, combine_stderr) # Assemble output string out = _AttributeString(stdout) err = _AttributeString(stderr) # Error handling out.failed = False if status != 0: out.failed = True msg = "%s() received nonzero return code %s while executing" % (which, status) if env.warn_only: msg += " '%s'!" % given_command else: msg += "!\n\nRequested: %s\nExecuted: %s" % (given_command, wrapped_command) error(message=msg, stdout=out, stderr=err) # Attach return code to output string so users who have set things to # warn only, can inspect the error code. out.return_code = status # Convenience mirror of .failed out.succeeded = not out.failed # Attach stderr for anyone interested in that. out.stderr = err return out
def execute_cmd(options): channel = default_channel() timeout = options.command_timeout with char_buffered(sys.stdin): # Combine stdout and stderr to get around oddball mixing issues channel.set_combine_stderr(False) # Assume pty use, and allow overriding of this either via kwarg or env # var. (invoke_shell always wants a pty no matter what.) using_pty = True # Request pty with size params (default to 80x24, obtain real # parameters if on POSIX platform) channel.get_pty(width=80, height=24) channel.invoke_shell() while not channel.recv_ready(): time.sleep(0.01) workers = ( ThreadHandler('out', output_loop, channel, "recv", capture=None, stream=sys.stdout, timeout=timeout, cmd=options.command), ThreadHandler('err', output_loop, channel, "recv_stderr", capture=None, stream=sys.stderr, timeout=timeout), ThreadHandler('in', input_loop, channel, using_pty) ) while True: if channel.exit_status_ready(): break else: # Check for thread exceptions here so we can raise ASAP # (without chance of getting blocked by, or hidden by an # exception within, recv_exit_status()) for worker in workers: worker.raise_if_needed() try: time.sleep(ssh.io_sleep) except KeyboardInterrupt: channel.send('\x03') # Obtain exit code of remote program now that we're done. status = channel.recv_exit_status() # Wait for threads to exit so we aren't left with stale threads for worker in workers: worker.thread.join() worker.raise_if_needed() # Close channel channel.close() return status
def remote_pipe(local_command, remote_command, buf_size=1024): '''executes a local command and a remove command (with fabric), and sends the local's stdout to the remote's stdin''' local_p= subprocess.Popen(local_command, shell=True, stdout=subprocess.PIPE) channel= default_channel() #fabric function channel.exec_command( remote_command ) read_bytes= local_p.stdout.read(buf_size) while read_bytes: channel.send(read_bytes) local_ret= local_p.wait() channel.shutdown_write() remote_ret= recv_exit_status(self) if local_ret!=0 or remote_ret!=0: raise Exception("remote_pipe failed")
def __init__(self, command, address): pushy.transport.BaseTransport.__init__(self, address) # Join arguments into a string args = command for i in range(len(args)): if " " in args[i]: args[i] = "'%s'" % args[i] command = " ".join(args) self.__channel = default_channel() self.__channel.exec_command(command) self.stdin = WrappedChannelFile(self.__channel.makefile("wb"), 1) self.stdout = WrappedChannelFile(self.__channel.makefile("rb"), 0) self.stderr = self.__channel.makefile_stderr("rb")
def _run_command(command, shell=True, pty=True, combine_stderr=True, sudo=False, user=None): """ Underpinnings of `run` and `sudo`. See their docstrings for more info. """ # Set up new var so original argument can be displayed verbatim later. given_command = command # Handle context manager modifications, and shell wrapping wrapped_command = _shell_wrap( _prefix_commands(_prefix_env_vars(command), 'remote'), shell, _sudo_prefix(user) if sudo else None ) # Execute info line which = 'sudo' if sudo else 'run' if output.debug: print("[%s] %s: %s" % (env.host_string, which, wrapped_command)) elif output.running: print("[%s] %s: %s" % (env.host_string, which, given_command)) # Actual execution, stdin/stdout/stderr handling, and termination stdout, stderr, status = _execute(default_channel(), wrapped_command, pty, combine_stderr) # Assemble output string out = _AttributeString(stdout) err = _AttributeString(stderr) # Error handling out.failed = False if status != 0: out.failed = True msg = "%s() encountered an error (return code %s) while executing '%s'" % (which, status, command) _handle_failure(message=msg) # Attach return code to output string so users who have set things to # warn only, can inspect the error code. out.return_code = status # Convenience mirror of .failed out.succeeded = not out.failed # Attach stderr for anyone interested in that. out.stderr = err return out
def test_expect(self): # chan = spawn(self.socks) run("echo 'BEGIN'") chan = spawn(default_channel()) chan.expect(5, { EOF : lambda: chan.close(), TIMEOUT : lambda: self.assertEqual(False, "TIMEOUT"), 'Last' : None }) chan.send('uname -a\n') chan.expect(1, { EOF : lambda: chan.close(), TIMEOUT : lambda: self.assertEqual(False, "TIMEOUT1"), 'Linux' : None, }) # chan.interact() chan.close()
def remote_pipe(local_command, remote_command, buf_size=1024*1024): '''executes a local command and a remove command (with fabric), and sends the local's stdout to the remote's stdin''' local_p= subprocess.Popen(local_command, shell=True, stdout=subprocess.PIPE) channel= default_channel() #fabric function channel.set_combine_stderr(True) channel.settimeout(2) channel.exec_command( remote_command ) try: read_bytes= local_p.stdout.read(buf_size) while read_bytes: channel.sendall(read_bytes) read_bytes= local_p.stdout.read(buf_size) except socket.error: local_p.kill() #fail to send data, let's see the return codes and received data... local_ret= local_p.wait() received= channel.recv(buf_size) channel.shutdown_write() channel.shutdown_read() remote_ret= channel.recv_exit_status() if local_ret!=0 or remote_ret!=0: raise Exception("remote_pipe failed. Local retcode: {0} Remote retcode: {1} output: {2}".format(local_ret, remote_ret, received))
def _run_host_command(command, shell=True, pty=True, combine_stderr=True, quiet=False, warn_only=False, stdout=None, stderr=None, timeout=None): """ Run host wrapper command as root (Modified from fabric.operations._run_command to ignore prefixes, path(), cd(), and always use sudo.) """ manager = _noop if warn_only: manager = warn_only_manager # Quiet's behavior is a superset of warn_only's, so it wins. if quiet: manager = quiet_manager with manager(): # Set up new var so original argument can be displayed verbatim later. given_command = command # Handle context manager modifications, and shell wrapping wrapped_command = _shell_wrap( command, # !! removed _prefix_commands() & _prefix_env_vars() shell, _sudo_prefix(None) # !! always use sudo ) # Execute info line which = 'sudo' # !! always use sudo if output.debug: print(("[%s] %s: %s" % (env.host_string, which, wrapped_command))) elif output.running: print(("[%s] %s: %s" % (env.host_string, which, given_command))) # Actual execution, stdin/stdout/stderr handling, and termination result_stdout, result_stderr, status = _execute( channel=default_channel(), command=wrapped_command, pty=pty, combine_stderr=combine_stderr, invoke_shell=False, stdout=stdout, stderr=stderr, timeout=timeout) # Assemble output string out = _AttributeString(result_stdout) err = _AttributeString(result_stderr) # Error handling out.failed = False out.command = given_command out.real_command = wrapped_command if status not in env.ok_ret_codes: out.failed = True msg = "%s() received nonzero return code %s while executing" % ( which, status) if env.warn_only: msg += " '%s'!" % given_command else: msg += "!\n\nRequested: %s\nExecuted: %s" % (given_command, wrapped_command) error(message=msg, stdout=out, stderr=err) # Attach return code to output string so users who have set things to # warn only, can inspect the error code. out.return_code = status # Convenience mirror of .failed out.succeeded = not out.failed # Attach stderr for anyone interested in that. out.stderr = err return out
def _run_command(command, shell=True, pty=True, combine_stderr=True, sudo=False, user=None, quiet=False, warn_only=False, stdout=None, stderr=None, group=None, timeout=None, shell_escape=None): """ Underpinnings of `run` and `sudo`. See their docstrings for more info. """ manager = _noop if warn_only: manager = warn_only_manager # Quiet's behavior is a superset of warn_only's, so it wins. if quiet: manager = quiet_manager with manager(): # Set up new var so original argument can be displayed verbatim later. given_command = command # Check if shell_escape has been overridden in env if shell_escape is None: shell_escape = env.get('shell_escape', True) # Handle context manager modifications, and shell wrapping wrapped_command = _shell_wrap( _prefix_commands(_prefix_env_vars(command), 'remote'), shell_escape, shell, _sudo_prefix(user, group) if sudo else None ) # Execute info line which = 'sudo' if sudo else 'run' if output.debug: print("[%s] %s: %s" % (env.host_string, which, wrapped_command)) elif output.running: print("[%s] %s: %s" % (env.host_string, which, given_command)) # Actual execution, stdin/stdout/stderr handling, and termination result_stdout, result_stderr, status = _execute( channel=default_channel(), command=wrapped_command, pty=pty, combine_stderr=combine_stderr, invoke_shell=False, stdout=stdout, stderr=stderr, timeout=timeout) # Assemble output string out = _AttributeString(result_stdout) err = _AttributeString(result_stderr) # Error handling out.failed = False out.command = given_command out.real_command = wrapped_command if status not in env.ok_ret_codes: out.failed = True msg = "%s() received nonzero return code %s while executing" % ( which, status ) if env.warn_only: msg += " '%s'!" % given_command else: msg += "!\n\nRequested: %s\nExecuted: %s" % ( given_command, wrapped_command ) error(message=msg, stdout=out, stderr=err) # Attach return code to output string so users who have set things to # warn only, can inspect the error code. out.return_code = status # Convenience mirror of .failed out.succeeded = not out.failed # Attach stderr for anyone interested in that. out.stderr = err return out
def _run_host_command(command, shell=True, pty=True, combine_stderr=True, quiet=False, warn_only=False, stdout=None, stderr=None, timeout=None): """ Run host wrapper command as root (Modified from fabric.operations._run_command to ignore prefixes, path(), cd(), and always use sudo.) """ manager = _noop if warn_only: manager = warn_only_manager # Quiet's behavior is a superset of warn_only's, so it wins. if quiet: manager = quiet_manager with manager(): # Set up new var so original argument can be displayed verbatim later. given_command = command # Handle context manager modifications, and shell wrapping wrapped_command = _shell_wrap( command, # !! removed _prefix_commands() & _prefix_env_vars() shell, _sudo_prefix(None) # !! always use sudo ) # Execute info line which = 'sudo' # !! always use sudo if output.debug: print("[%s] %s: %s" % (env.host_string, which, wrapped_command)) elif output.running: print("[%s] %s: %s" % (env.host_string, which, given_command)) # Actual execution, stdin/stdout/stderr handling, and termination result_stdout, result_stderr, status = _execute( channel=default_channel(), command=wrapped_command, pty=pty, combine_stderr=combine_stderr, invoke_shell=False, stdout=stdout, stderr=stderr, timeout=timeout) # Assemble output string out = _AttributeString(result_stdout) err = _AttributeString(result_stderr) # Error handling out.failed = False out.command = given_command out.real_command = wrapped_command if status not in env.ok_ret_codes: out.failed = True msg = "%s() received nonzero return code %s while executing" % ( which, status ) if env.warn_only: msg += " '%s'!" % given_command else: msg += "!\n\nRequested: %s\nExecuted: %s" % ( given_command, wrapped_command ) error(message=msg, stdout=out, stderr=err) # Attach return code to output string so users who have set things to # warn only, can inspect the error code. out.return_code = status # Convenience mirror of .failed out.succeeded = not out.failed # Attach stderr for anyone interested in that. out.stderr = err return out