multiple commands by logging into SSH - python

I am trying to log in to the server and give multiple commands from the input file. Here input file is web.txt (contains 'bash', 'df-g' as examples). I am sucessfully able to login to server, but not able to run the commands. I don't know what I am doing wrong here. Can anyone help me please.
import paramiko
web_list = []
def create_web_list():
file = open("web.txt", "r", encoding='utf-8')
for value in file.readlines():
web_list.append(value.strip( ))
return web_list
ip = 'x.x.x.x'
username = 'username'
password = 'password'
def web_device(web_list):
SESSION = paramiko.SSHClient()
SESSION.set_missing_host_key_policy(paramiko.AutoAddPolicy)
SESSION.connect(ip,port=22,username=username,password=password,look_for_keys=False,allow_agent=False)
print("Connection Sucessful")
for cmd in web_list:
stdin,stdout,stderr=SESSION.exec_command(cmd)
outlines=stdout.readlines()
resp=''.join(outlines)
print(resp)
SESSION.close()
if __name__ == "__main__":
web_device(create_web_list())

Please specify either you want output in one go or you want output for each command separately? if you want with one go then please find below:
Executing multiple commands on paramiko SSHClient, you can place all commands in one line with ; separator like:
client.exec_command('ls -l; cwd; whoiam') etc
so please read line from file accordingly and execute commands with one go instead using a loop.
For Individual command execution case use below:
with open("web.txt", "r", encoding='utf-8') as f:
return web_list.append(f.strip( ))
and print output in utf format like '\n'.join(outlines)

Related

How to send an additional arg in paramiko connect like "ssh -t -l user P.P.P.P D.D.D.D" for an interactive shell? [duplicate]

I have some Paramiko code where I use the invoke_shell method to request an interactive ssh shell session on a remote server. Method is outlined here: invoke_shell()
Here's a summary of the pertinent code:
sshClient = paramiko.SSHClient()
sshClient.connect('127.0.0.1', username='matt', password='password')
channel = sshClient.get_transport().open_session()
channel.get_pty()
channel.invoke_shell()
while True:
command = raw_input('$ ')
if command == 'exit':
break
channel.send(command + "\n")
while True:
if channel.recv_ready():
output = channel.recv(1024)
print output
else:
time.sleep(0.5)
if not(channel.recv_ready()):
break
sshClient.close()
My question is: is there a better way to interact with the shell? The above works, but it's ugly with the two prompts (the matt#kali:~$ and the $ from raw_input), as shown in the screenshot of a test run with the interactive shell. I guess I need help writing to the stdin for the shell? Sorry, I don't code much. Thanks in advance!
I imported a file, interactive.py, found on Paramiko's GitHub. After importing it, I just had to change my code to this:
try:
import interactive
except ImportError:
from . import interactive
...
...
channel.invoke_shell()
interactive.interactive_shell(channel)
sshClient.close()
You can try disabling echo after invoking the remote shell:
channel.invoke_shell()
channel.send("stty -echo\n")
while True:
command = raw_input() # no need for `$ ' anymore
... ...

Python Pexpect full output is not saved (How to deal with the "--More--" prompt?)

I am using Pexpect to run a command remotely on a server and saving the output in a file. However, it does not save the whole output as it's truncated due to --More-- . Is there a way to avoid --More--, so that the whole output is saved in the output file?
I have tried using child.setwinsize(1000,1000) but it didn't solve the issue.
Current code:
import pexpect
import time
child = pexpect.spawn('ssh username#ip_address')
time.sleep(1)
child.sendline('password')
time.sleep(1)
child.logfile = open("output.txt", "w")
child.sendline('command')
child.expect(pexpect.EOF)
print child.before, child.after
child.close
Not sure what command you're running but usually you can press SPACE when you see the --More-- prompt. For example:
import pexpect, sys
child = pexpect.spawn('more /etc/services')
child.logfile_read = sys.stdout
patterns = ['--More--', pexpect.EOF]
while True:
ret = child.expect(patterns)
if ret == 0:
child.send(' ')
elif ret == 1:
break
I found one more answer- just execute below command before actual command.
terminal length 0
After that suppose I entered some command like show ip interface. Then, This will show whole output. You don't need to press enter again and again. As,
child.sendline('terminal length 0')
child.expect('# ')
child.sendline('show ip interface') #write your command here
child.expect('# ')

How to redirect output of ssh.exec_command to a file in Python paramiko module?

I want to run a python script say test.py on a Linux target machine (which has a python interpreter) and capture the output of the command in a text file as the part of another python script invoke.py using paramiko module.
The statement in the script
stdin, stdout, sterr = ssh.exec_command("python invoke.py > log.txt")
generates a blank file log.txt.
Please suggest corrections / alternate way to do this. to write the output to the file correctly.
test.py when run locally outputs sane text (which is expected to be logged in log.txt).
There are some relevant posts here and here, but no one deals with output of python script
instead of calling client.exec_command() you can use client.open_channel() and use channel session's recv() and recv_stderr() streams to read write stdout/std err:
def sshExecute(hostname, username, password, command, logpath = None):
buffSize = 2048
port = 22
client = paramiko.Transport((hostname, port))
client.connect(username=username, password=password)
if logpath == None:
logpath = "./"
timestamp = int(time.time())
hostname_prefix = "host-%s-%s"%(hostname.replace(".","-"),timestamp)
stdout_data_filename = os.path.join(logpath,"%s.out"%(hostname_prefix))
stderr_data_filename = os.path.join(logpath,"%s.err"%(hostname_prefix))
stdout_data = open(stdout_data_filename,"w")
stderr_data = open(stderr_data_filename,"w")
sshSession = client.open_channel(kind='session')
sshSession.exec_command(command)
while True:
if sshSession.recv_ready():
stdout_data.write(sshSession.recv(buffSize))
if sshSession.recv_stderr_ready():
stderr_data.write(sshSession.recv_stderr(buffSize))
if sshSession.exit_status_ready():
break
stdout_data.close()
stderr_data.close()
sshSession.close()
client.close()
return sshSession.recv_exit_status()
Hope this fully working function helps you

Need little assistance with pexpect module

Need assistance with the pexpect module
I have written a simple code which would clone a git repository from a server using ssh.
I'm facing couple of problems.
The password is shown in plain text.
I dont know a proper way to exit the program after the download. it throws out the following error...
Traceback (most recent call last):
File "ToDelete3.py", line 65, in <module>
# # if i == 1:
File "ToDelete3.py", line 36, in getRepository
i = p.expect([ssh_key,'password:',pexpect.EOF])
File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1492, in interact
self.__interact_copy(escape_character, input_filter, output_filter)
File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1520, in __interact_copy
data = self.__interact_read(self.child_fd)
File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1510, in __interact_read
return os.read(fd, 1000)
OSError: [Errno 5] Input/output error
the code that I have written so far is :
command = 'git clone ssh://username#someserver/something.git'
ssh_key = 'Are you sure you want to continue connecting'
def gracefulExit():
print 'Password Incorrect !!!'
os._exit(1)
def getRepository():
p = pexpect.spawn(command,maxread=10000,timeout = 100)
p.logfile = sys.stdout # logs out the command
i = p.expect([ssh_key,'password:',pexpect.EOF])
if i == 0:
print 'Inside sshkey'
p.sendline('yes')
i = p.expect([ssh_key,'password:',pexpect.EOF])
if i == 1:
try:
p.sendline('mypassword') # this mypassword is shown in clear text on the console
p.interact()
p.logfile = sys.stdout
p.expect(pexpect.EOF)
except Exception,e:
print str(e)
gracefulExit()
if i == 2:
print 'Inside EOF block'
if p.isalive():
print '******************************************************'
print ' Closing the process of Download !!! '
print '******************************************************\n\n'
p.close()
Any inputs is highly appreciated..
Thanks.
-Vijay
There are few errors in the program:
p.interact()
This is used when we want to get back the control after having automatically supplied the password using pexpect module. You don't need to use that since you are automating the whole repository check out.
Also a few things can be improved, after passing the password, set a infinite timeout since it may take a while to copy a git repository.
p.expect(pexpect.EOF, timeout=None)
After that you can read all the execution output with the following command
output_lines = p.before
output_lines_list = output_lines.split('\r\n')
for line in output_lines: print line
you can also use the above to log the output to a file by directly writing to it
Using p.logifile = sys.stdout is not good since it will record pexpect operation from start including passing of password.
After this there is no need to close, you are not running a interactive program. Remove all these lines:
if i == 2:
print 'Inside EOF block'
if p.isalive():
print '******************************************************'
print ' Closing the process of Download !!! '
print '******************************************************\n\n'
p.close()
The issue is that some where you have to store the password and use it with p.sendline. How ever, you store password, it is going to be insecure. You can also take the input at the start for the password, this way you will not be storing the password within your program but that defeats automation. I don't see a way out but for taking password input, you can do:
import getpass
getpass.getpass("please provide your password")
To get rid of the password being echo'd to stdout, use the following when redirecting output -
p.logfile_read = sys.stdout # logs out the command
I have tried this myself and seems to be working. Here is the reference for this revelation.

Python, redirecting the stream of Popen to a python function

I'm new to python programming.
I have this problem: I have a list of text files (both compressed and not) and I need to :
- connect to the server and open them
- after the opening of the file, I need to take his content and pass it to another python function that I wrote
def readLogs (fileName):
f = open (fileName, 'r')
inStream = f.read()
counter = 0
inStream = re.split('\n', inStream) # Create a 'list of lines'
out = "" # Will contain the output
logInConst = "" # log In Construction
curLine = "" # Line that I am working on
for nextLine in inStream:
logInConst += curLine
curLine = nextLine
# check if it is a start of a new log && check if the previous log is 'ready'
if newLogRegExp.match(curLine) and logInConst != "":
counter = counter + 1
out = logInConst
logInConst = ""
yield out
yield logInConst + curLine
def checkFile (regExp, fileName):
generatore = readLogs(fileName)
listOfMatches=[]
for i in generatore: #I'm now cycling through the logs
# regExp must be a COMPILE regular expression
if regExp.search(i):
listOfMatches.append(i)
return listOfMatches
in order to elaborate the info contained in those files.
The function has the aim of write in just 1 line the logs that are stored in those files using 3 lines ... The function is working fine on files read from my local machine but I cannot figure out how to connect to a remote server and create these one-line logs without storing the content of each file into a string and then working with the string ... The command that I use to connect to the remote machine is :
connection_out = Popen(['ssh', retList[0], 'cd '+retList[2]+'; cat'+fileName], stdout=PIPE).communicate()[0]
retList[0] and retList[2] are the user#remote and the folder name that I have to access
Thanks to all in advance !
UPDATE:
My problem is that I have to establish an ssh connection first :
pr1=Popen(['ssh', 'siatc#lgssp101', '*~/XYZ/AAAAA/log_archive/00/MSG_090308_162648.gz*' ], stdout=PIPE).communicate()[0]
All the files that I need to open are stored in a list, fileList[], part of them are compressed (.gz) and part are just text files !! I have tried all the procedures that u showed before bot nothing worked ... I think that I mus modify the third argument of the Popen function but I cannot figure out how to do it ! Is there anyone that can help me ???
You do not have to split the stream/file into lines yourself. Just iterate:
for ln in f:
# work on line in ln
This should work equally well for files (using open() for file()) and pipes (using Popen). Use the stdout property of the popen object to access the pipe connected to stdout of the subprocess
Example
from subprocess import Popen, PIPE
pp = Popen('dir', shell=True, stdout=PIPE)
for ln in pp.stdout:
print '#',ln
Remove InStream and just use the file object.
So that your code would read:
for nextLine in f.readlines():
.
.
.
Ber has it right.
To clarify, the default iteration behavior of a file object is to return the next line. so "for nextLine in f" will give you the same results as "for nextLine in f.readlines()".
See the file object documentation for details: http://docs.python.org/library/stdtypes.html#bltin-file-objects
If you want to do something via ssh, why not use the Python SSH module?
Try this page, best info on popen I have found so far....
http://jimmyg.org/blog/2009/working-with-python-subprocess.html

Categories