def start(self, command, shell, env, timeout=None): self.channel = self.context.create_session() if self.using_pty: # Set initial size to match local size cols, rows = pty_size() self.channel.get_pty(width=cols, height=rows) # If platform supports, also respond to SIGWINCH (window change) by # sending the sshd a window-change message to update if hasattr(signal, "SIGWINCH"): signal.signal(signal.SIGWINCH, self.handle_window_change) if env: # TODO: honor SendEnv from ssh_config (but if we do, _should_ we # honor it even when prefixing? That would depart from OpenSSH # somewhat (albeit as a "what we can do that it cannot" feature...) if self.inline_env: # TODO: escaping, if we can find a FOOLPROOF THIRD PARTY METHOD # for doing so! # TODO: switch to using a higher-level generic command # prefixing functionality, when implemented. parameters = " ".join( ["{}={}".format(k, v) for k, v in sorted(env.items())]) # NOTE: we can assume 'export' and '&&' relatively safely, as # sshd always brings some shell into play, even if it's just # /bin/sh. command = "export {} && {}".format(parameters, command) else: self.channel.update_environment(env) self.channel.exec_command(command)
def start(self, command, shell, env): self.channel = self.context.create_session() if self.using_pty: rows, cols = pty_size() self.channel.get_pty(width=rows, height=cols) if env: # TODO: honor SendEnv from ssh_config (but if we do, _should_ we # honor it even when prefixing? That would depart from OpenSSH # somewhat (albeit as a "what we can do that it cannot" feature...) if self.inline_env: # TODO: escaping, if we can find a FOOLPROOF THIRD PARTY METHOD # for doing so! # TODO: switch to using a higher-level generic command # prefixing functionality, when implemented. parameters = " ".join( ["{}={}".format(k, v) for k, v in sorted(env.items())]) # NOTE: we can assume 'export' and '&&' relatively safely, as # sshd always brings some shell into play, even if it's just # /bin/sh. command = "export {} && {}".format(parameters, command) else: self.channel.update_environment(env) # TODO: pass in timeout= here when invoke grows timeout functionality # in Runner/Local. self.channel.exec_command(command)
def handle_window_change(self, signum, frame): """ Respond to a `signal.SIGWINCH` (as a standard signal handler). Sends a window resize command via Paramiko channel method. """ self.channel.resize_pty(*pty_size())
def pty_True_uses_paramiko_get_pty(self, remote): chan = remote.expect() c = _Connection('host') r = Remote(context=c) r.run(CMD, pty=True) cols, rows = pty_size() chan.get_pty.assert_called_with(width=cols, height=rows)
def start(self, command, shell, env): self.channel = self.context.create_session() if self.using_pty: rows, cols = pty_size() self.channel.get_pty(width=rows, height=cols) if env: # TODO: honor SendEnv from ssh_config (but if we do, _should_ we # honor it even when prefixing? That would depart from OpenSSH # somewhat (albeit as a "what we can do that it cannot" feature...) if self.inline_env: # TODO: escaping, if we can find a FOOLPROOF THIRD PARTY METHOD # for doing so! # TODO: switch to using a higher-level generic command # prefixing functionality, when implemented. parameters = " ".join( ["{}={}".format(k, v) for k, v in sorted(env.items())] ) # NOTE: we can assume 'export' and '&&' relatively safely, as # sshd always brings some shell into play, even if it's just # /bin/sh. command = "export {} && {}".format(parameters, command) else: self.channel.update_environment(env) # TODO: pass in timeout= here when invoke grows timeout functionality # in Runner/Local. self.channel.exec_command(command)
def simple_command_with_pty(self): """ Run command under PTY on localhost """ # Most Unix systems should have stty, which asplodes when not run # under a pty, and prints useful info otherwise result = Connection("localhost").run("stty size", hide=True, pty=True) found = result.stdout.strip().split() cols, rows = pty_size() assert tuple(map(int, found)), rows == cols # PTYs use \r\n, not \n, line separation assert "\r\n" in result.stdout assert result.pty is True
def start(self, command, shell, env): self.channel = self.context.create_session() if self.using_pty: rows, cols = pty_size() self.channel.get_pty(width=rows, height=cols) # TODO: consider adding an option to conditionally turn this # update_environment call into a command-string prefixing behavior # instead (e.g. when one isn't able/willing to update remote server's # AcceptEnv setting). OR: rely on higher-level generic command # prefixing functionality, when implemented. # TODO: honor SendEnv from ssh_config self.channel.update_environment(env) # TODO: pass in timeout= here when invoke grows timeout functionality # in Runner/Local. self.channel.exec_command(command)
def simple_command_with_pty(self): """ Run command under PTY on localhost """ # Most Unix systems should have stty, which asplodes when not run # under a pty, and prints useful info otherwise result = Connection("localhost").run( "stty size", hide=True, pty=True ) found = result.stdout.strip().split() cols, rows = pty_size() assert tuple(map(int, found)), rows == cols # PTYs use \r\n, not \n, line separation assert "\r\n" in result.stdout assert result.pty is True
def simple_command_with_pty(self): """ Run command under PTY on localhost """ # Most Unix systems should have stty, which asplodes when not run # under a pty, and prints useful info otherwise result = Connection('localhost').run( 'stty size', hide=True, pty=True, ) found = result.stdout.strip().split() cols, rows = pty_size() eq_(tuple(map(int, found)), (rows, cols)) # PTYs use \r\n, not \n, line separation ok_("\r\n" in result.stdout) eq_(result.pty, True)
def window_change_handler_uses_resize_pty(self): runner = _runner() runner.channel = Mock() runner.handle_window_change(None, None) cols, rows = pty_size() runner.channel.resize_pty.assert_called_once_with(cols, rows)
def uses_paramiko_get_pty_with_local_size(self, remote): chan = remote.expect() _runner().run(CMD, pty=True) cols, rows = pty_size() chan.get_pty.assert_called_with(width=cols, height=rows)
def pty_True_uses_paramiko_get_pty(self, remote): chan = remote.expect() _runner().run(CMD, pty=True) cols, rows = pty_size() chan.get_pty.assert_called_with(width=cols, height=rows)