Paramiko how to specify Folder path - python

import paramiko
import os
import sys
ssh = paramiko.SSHClient()
paramiko.util.log_to_file('U:\\Temp\\paramiko.log')
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('172.18.24.234','/TestBTEC/',22,'btectest','M3j0Stanf0rd')
stdin, stdout, stderr = ssh.exec_command("mkdir abc")
stdout.readlines()
This is obviously throwing back errors. What is the proper way to set the home directory on the remote server for user btectest

Instead of setting you can also specify parent directory as userprofile as below
import os
abc_dir = os.path.join('%UserProfile%','abc')
cmd = "mkdir %s" % abc_dir
stdin, stdout, stderr = ssh.exec_command(cmd)

The parameters you are passing to SSHCient.connect() are incorrect (at least for paramiko 1.6+). Your connect() call should look like this:
ssh.connect('172.18.24.234', username='btectest', password='...')
or if you explicitly include the port:
ssh.connect('172.18.24.234', 22, 'btectest', '...')
Once connected, you should already be in the home directory of the user "btectest", as can be seen with this:
stdin, stdout, stderr = ssh.exec_command("pwd")
stdout.readlines()

Related

Retrive latest directory

import paramiko
ssh =paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='test.com',username='test',password='test123')
srcpath = ('/tmp/test/')
destpath = ('/tmp/file/')
transfer=ssh.open_sftp()
stdin, stdout, stderr = ssh.exec_command('cd /tmp/test/; ls -1t *txt* | head -1')
out = stdout.read().splitlines()
print out
error = stderr.read().splitlines()
print error
transfer.close()
ssh.close()
Above is my code, i tried to retrieve the latest directory on remote server. I am facing below error.
Error:
['bash: head: command not found']
is there any other way to retrieve latest directory ?
You actually don't need "head" nor "tail", just access the last line from python as follows.
This is your code little edited to catch the last line as last_line:
import paramiko
ssh =paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='test.com',username='test',password='test123')
srcpath = ('/tmp/test/')
destpath = ('/tmp/file/')
transfer=ssh.open_sftp()
stdin, stdout, stderr = ssh.exec_command('cd /tmp/test/; ls -1t *txt*')
out = stdout.read().splitlines()
last_line = out[-1] ## takes out the last line without need for tail command
print out
print last_line
error = stderr.read().splitlines()
print error
transfer.close()
ssh.close()

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
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] #

Use Paramiko's stdout as stdin with subprocess

How can I execute a command on a remote server in Python and pipe the stdout to a local command? To do ssh host 'echo test' | cat in Python, I have tried
import paramiko
import subprocess
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('host', username='user')
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('echo test')
proc = subprocess.Popen(['cat'], stdin=ssh_stdout)
outs, errs = proc.communicate()
print(outs)
but I get the exception 'ChannelFile' object has no attribute 'fileno'. It seems that Paramiko's ssh_stdout can't be used as stdin with subprocess.Popen.
Yes, subprocess cannot redirect output on a "fake" file. It needs fileno which is defined only with "real" files (io.BytesIO() doesn't have it either).
I would do it manually like the following code demonstrates:
proc = subprocess.Popen(['cat'], stdin=subprocess.PIPE)
proc.stdin.write(ssh_stdout.read())
proc.stdin.close()
so you're telling Popen that the input is a pipe, and then you write ssh output data in the pipe (and close it so cat knows when it must end)
According to the docs, the ChannelFile object does not directly wrap an actual file descriptor (because of the decryption and demuxing and so on that occurs within SSH), so it can't directly be used as a file descriptor for Popen.
Something like
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('echo test')
proc = subprocess.Popen(['cat'], stdin=subprocess.PIPE)
while proc.poll() is not None: # (fixed)
buf = ssh_stdout.read(4096)
if not buf:
break
proc.stdin.write(buf)
might work; i.e. you read the SSH stdout stream manually, up to 4096 bytes at a time, and write them to the subprocess's stdin pipe.
I'm not sure how the code above will behave when the remote command exits, though, so YMMV.

source command does not take effect

I have a cluster of machines, and I write a Python script to change the hostname; the code follows.
What puzzles me is that the source command only takes effect on some machines, not all. After I repeat several times, then all hostname take effect [BTW: I can change the hostname in /etc/hostname, but the hostname service do not take effect.]
import paramiko
import time
import threading
import os
cmd0 = "sudo source /root/.bashrc"
cmd1 = "sudo service hostname stop"
cmd2 = "sudo service hostname start"
def executeit(ip):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, 22, "root")
ssh.exec_command(cmd0)
stdin, stdout, stderr = ssh.exec_command(cmd1)
out = stdout.readlines()
for o in out:
print(o)
time.sleep(1)
ssh.exec_command(cmd2)
ssh.close()
print("=======")
def main():
fr = open("info.txt", "r")
contents = fr.read().splitlines()
fr.close()
for ip in contents:
t = threading.Thread(target=executeit, args=(ip,))
t.start()
main()

Python Paramiko- Have stdin duplicate pointing to stdout so it can be seen in output

I am writing a python script with the paramiko module. It ssh's into a remote hosts, runs script, and automates/answers interactive prompts. It works pretty good so far. For the output, I would like to have both stdin, stdout, stderr streams pointing together(to stdout) so I can see them in stdout.readlines(). But as it is now, I am not seeing the stdin.write() calls I placed in the script. How can I get stdin.write() included in the output?
import paramiko
bar = "5555"
foofilename = ""
cont = "Y"
fname = '/foobar/file.txt'
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect( host, port=22, username=uname, password=pword)
stdin, stdout, stderr=ssh.exec_command("script.sh")
stdin.write(bar+"\n")
stdin.flush()
stdin.write(foofilename+"\n")
stdin.flush()
stdin.write(cont+"\n")
stdin.flush()
stdin.write(fname+"\n")
stdin.flush()
output = stdout.readlines()
for line in output:
print line.split("\n")

Categories