Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write to stdin (returned from exec_command) in paramiko?

I am trying to write to a custom program's stdin with paramiko. Here is a minimal (non-)working example:

~/stdin_to_file.py:

#! /usr/bin/python

import time, sys
f = open('/home/me/LOG','w')
while True:
    sys.stdin.flush()
    data = sys.stdin.read()
    f.write(data+'\n\n')
    f.flush()
    time.sleep(0.01)

Then I do these commands in IPython:

import paramiko
s = paramiko.client.SSHClient 
s.load_system_host_keys()
s.connect('myserver')
stdin, stdout, stderr = s.exec_command('/home/me/stdin_to_file.py')
stdin.write('Hello!')
stdin.flush()

Unfortunately, nothing then appears in ~/LOG. However, if I do

$ ~/stdin_to_file.py < some_other_file

The contents of some_other_file appear in ~/LOG.

Can anyone suggest where I've gone wrong? It seems like I'm doing the logical thing. None of these work either:

stdin.channel.send('hi')
using the get_pty parameter
sending the output of cat - to stdin_to_file.py
like image 962
Mark C. Avatar asked Feb 01 '18 02:02

Mark C.


People also ask

How do I get output from Paramiko?

You can get the output the command by using stdout. read() (returns a string) or stdout. readlines() (returns a list of lines).

What is Paramiko SSHClient ()?

SSHClient. A high-level representation of a session with an SSH server. This class wraps Transport , Channel , and SFTPClient to take care of most aspects of authenticating and opening channels. A typical use case is: client = SSHClient() client.

How do I use Paramiko in Python?

So, we have created a client object “ssh” of “SSHClient” with the paramiko package. This object calls the automatic policy function of adding unknown keys to perform SSH to remote host servers via the paramiko package. The same object is used to connect the client machine with the host server via the host credentials.

What can you do with Paramiko?

Paramiko helps you automate repetitive system administration tasks on remote servers. More advanced Paramiko programs send the lines of a script one at a time. It does this rather than transacting all of a command, such as df or last , synchronously to completion.


1 Answers

sys.stdin.read() will keep reading until EOF so in your paramiko script you need to close the stdin (returned from exec_command()). But how?

1. stdin.close() would not work.

According to Paramiko's doc (v1.16):

Warning: To correctly emulate the file object created from a socket’s makefile() method, a Channel and its ChannelFile should be able to be closed or garbage-collected independently. Currently, closing the ChannelFile does nothing but flush the buffer.

2. stdin.channel.close() also has problem.

Since stdin, stdout and stderr all share one single channel, stdin.channel.close() will also close stdout and stderr which is not expected.

3. stdin.channel.shutdown_write()

The correct solution is to use stdin.channel.shutdown_write() which disallows writing to the channel but still allows reading from the channel so stdout.read() and stderr.read() would still work.


See following example to see the difference between stdin.channel.close() and stdin.channel.shutdown_write().

[STEP 101] # cat foo.py
import paramiko, sys, time

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy() )
ssh.connect(hostname='127.0.0.1', username='root', password='password')
cmd = "sh -c 'read v; sleep 1; echo $v'"
stdin, stdout, stderr = ssh.exec_command(cmd)
if sys.argv[1] == 'close':
    stdin.write('hello world\n')
    stdin.flush()
    stdin.channel.close()
elif sys.argv[1] == 'shutdown_write':
    stdin.channel.send('hello world\n')
    stdin.channel.shutdown_write()
else:
    raise Exception()
sys.stdout.write(stdout.read() )
[STEP 102] # python foo.py close           # It outputs nothing.
[STEP 103] # python foo.py shutdown_write  # This works fine.
hello world
[STEP 104] #
like image 189
pynexj Avatar answered Oct 15 '22 21:10

pynexj