Created
June 8, 2018 02:29
-
-
Save adisbladis/d294be83f8035015b5421fff179e6665 to your computer and use it in GitHub Desktop.
Paramiko example with proper stderr/stdout behaviour
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import contextlib | |
import functools | |
import paramiko | |
import select | |
import sys | |
import os | |
if __name__ == '__main__': | |
host = '172.28.10.2' | |
username = 'adisbladis' | |
shell_script = f''' | |
set -euxo pipefail | |
echo COOL | |
''' | |
client = paramiko.SSHClient() | |
# Contextlib can be "abused" to implement | |
# defer-like behaviour | |
with contextlib.ExitStack() as stack: | |
def defer(fn, *args, **kwargs): | |
partial = functools.partial(fn, *args, **kwargs) | |
stack.callback(partial) | |
client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |
client.connect(host, username=username) | |
defer(client.close) | |
session = client.get_transport().open_session() | |
forward = paramiko.agent.AgentRequestHandler(session) | |
stdin, stdout, stderr = client.exec_command('exec bash') | |
defer(stdin.close) | |
defer(stdout.close) | |
defer(stderr.close) | |
stdin.write(shell_script) | |
stdin.close() | |
# Stdout/stderr are multiplexed over the same channel | |
chan = stdout.channel | |
# Close channel in outgoing direction | |
# Cannot write any more data after this | |
chan.shutdown_write() | |
# Flush fds before exit | |
defer(sys.stdout.buffer.flush) | |
defer(sys.stderr.buffer.flush) | |
# Emulate select() over stdout/stderr | |
read_size = 1024 | |
while not chan.exit_status_ready(): | |
if chan.recv_ready(): | |
b = chan.recv(read_size) | |
while b: | |
sys.stdout.buffer.write(b) | |
b = chan.recv(read_size) | |
if chan.recv_stderr_ready(): | |
b = chan.recv_stderr(read_size) | |
while b: | |
sys.stderr.buffer.write(b) | |
b = chan.recv_stderr(read_size) | |
exit(chan.recv_exit_status()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment