Paramiko shell - determine when shell is ready for next command? [duplicate] - python

This question already has answers here:
Reading command output with Paramiko invoke_shell/send/recv never finishes
(1 answer)
Execute multiple dependent commands individually with Paramiko and find out when each command finishes
(1 answer)
Closed 6 months ago.
I'm fairly new to Python, but trying to create a small script that will SSH into a server on my work and navigate through various menus. Normally I would do that with Putty client.
I did succeed in this using code below:
from socket import setdefaulttimeout
import time
import paramiko
from getpass import getpass
from prompt_toolkit import ANSI
# Connection parameters for SSH + create connection.
hostname = 'workhostname'
port = 22
user = input('User (server): ')
passwd = getpass('Password (server): ')
programlogin = input('User (hyperspace): ')
programpass = getpass('Password (hyperspace): ')
exportdir = "/home/" + user + "/PYTHONTEST1"
commandsequence = ["2", "1", programlogin, programpass, "", "6", "DEP", "", "1", "7", "6", "", "17030", "24650", "", "995", "1121042", "1121806", "", exportdir, "", ""]
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname,port=port,username=user,password=passwd)
# Create shell via paramiko.
chan = client.invoke_shell(term='xterm')
# Time.sleep for more than 5 seconds to make sure that the program initial screen pause of 5 seconds is passed.
# "This message will disapper in 5 seconds"
time.sleep(7)
# Loop through command sequence.
for command in commandsequence:
# Send command.
chan.send(command + '\r')
time.sleep(2.3)
print(chan.recv(4096).decode('ISO-8859-1')) # For debugging purposes - to check whats actually going on in the console
if command == programpass:
print("Command: PASSWORD HIDDEN completed")
else:
print("Command: " + command + " completed")
# Trying to create some loop to check if all bytes has been received from the channel. loops out, if not ready after 10 checks.
"""
counter = 0
while not chan.recv_ready():
print("Not ready")
time.sleep(1)
if counter < 10:
counter += 1
else:
break
"""
# Get all bytes + decode the data (so it is readable through print)
#s = chan.recv(4096).decode()
s = chan.recv(4096).decode('ISO-8859-1')
print(s)
client.close()
However this only works because I give the client enough time (time.sleep(2.3)) between each command. I have read somewhere that paramikos exec command is the only real reliable way to tell if the command was actually completed. However I don't think I will be able to use the exec command to navigate this "program" that I'm facing when doing the shell approach. I can use linux terminal commands like "hostname" to get that returned, but I have no idea how to start the program and navigate through it this way.
Will I somehow be able to tell, by reading the chan.recv() if I'm done receiving output from the server, instead of "blindly" trust some high timer? - Or what would the approach be?

Related

Paramiko recv_ready() returns false values

I am trying to execute a number of commands remotely using paramiko, however the recv_ready() does not return the correct value.
For example after a pwd \n command it will continuously report that the channel is not still ready (obviously false). For some commands it works properly e.g. ls.
Is there something wrong with what I am doing, or is there an issue with paramiko?
import paramiko
import re
import time
def sudo_ssh(hostname, usernameIn, passIn, cmd):
# Create an SSH client
client = paramiko.SSHClient()
# Make sure that we add the remote server's SSH key automatically
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Connect to the client
client.connect(hostname, username=usernameIn, password=passIn)
# Create a raw shell
channel = client.invoke_shell()
# Send the sudo command
for command in cmd:
print("CMD= " + command + "\n")
time.sleep(1)
# wait until channel is ready
while not channel.recv_ready() :
print("NOT READY " + str(channel.recv_ready()) + "\n \n")
time.sleep(1)
# Send the command
channel.send(command)
channel.send("\n")
# Wait a bit, if necessary
time.sleep(1)
# Flush the receive buffer
receive_buffer = channel.recv(4096)
# If promted send the sudo pass
if re.search(b".*\[sudo\].*", receive_buffer):
time.sleep(1)
print(" TYPING SUDO PASSWORD .... \n")
channel.send( "sudoPass" + "\n" )
receive_buffer = channel.recv(4096)
# Print the receive buffer, if necessary
print(receive_buffer)
print("Executed all of the commands. Now will exit \n")
client.close()
com = []
com.append("sudo ls")
com.append("cd /home/user/Downloads")
com.append("sleep 5")
com.append("ls")
com.append("pwd")
com.append("cd /opt/")
sudo_ssh("myhost.com", "user", "pass", com)
The recv_ready method is to check if the data of channel is ready to read or not i.e. data is buffered or not. It doesn't check if channel itself is ready, see - recv_ready().
So you should move the recv_ready() while loop just before the receive_buffer = channel.recv(4096) to make it work.

Paramiko - ssh to console server, having to hit return for script to continue

Just using my first paramiko script, we have an opengear console server, so I'm trying to automate setup of any device we plug into it.
The open gear listens for ssh connections on ports, for example a device in port 1 would be 3001. I am connecting to a device on port 8, which works and my script runs, but for some reason, after I get the "Interactive SSH session established" message, I need to hit return on the session to make it run (so I have a ssh session and the script does too, its shared).
It just waits there until I hit return, I've tried sending returns as you can see but they don't work, only a manual return works, which is odd because technically they are the same thing?
import paramiko
import time
def disable_paging(remote_conn):
'''Disable paging on a Cisco router'''
remote_conn.send("terminal length 0\n")
time.sleep(1)
# Clear the buffer on the screen
output = remote_conn.recv(1000)
return output
if __name__ == '__main__':
# VARIABLES THAT NEED CHANGED
ip = '192.168.1.10'
username = 'root'
password = 'XXXXXX'
port = 3008
# Create instance of SSHClient object
remote_conn_pre = paramiko.SSHClient()
# Automatically add untrusted hosts (make sure okay for security policy in your environment)
remote_conn_pre.set_missing_host_key_policy(
paramiko.AutoAddPolicy())
# initiate SSH connection
remote_conn_pre.connect(ip, username=username, password=password,port=port, look_for_keys=False, allow_agent=False)
print "SSH connection established to %s" % ip
# Use invoke_shell to establish an 'interactive session'
remote_conn = remote_conn_pre.invoke_shell()
print "Interactive SSH session established"
time.sleep(1)
remote_conn.send("\n")
# Strip the initial router prompt
#output = remote_conn.recv(1000)
# See what we have
#print output
# Turn off paging
#disable_paging(remote_conn)
# clear any config sessions
is_global = remote_conn.recv(1024)
if ")#" in is_global:
remote_conn.send("end\n")
time.sleep(2)
# if not in enable mode go to enable mode
is_enable = remote_conn.recv(1024)
if ">" in is_enable:
remote_conn.send("enable\n")
time.sleep(1)
remote_conn.send("conf t\n")
remote_conn.send("int g0/0/1\n")
remote_conn.send("ip address 192.168.1.21 255.255.255.0\n")
remote_conn.send("no shut\n")
remote_conn.send("end\n")
# Wait for the command to complete
time.sleep(2)
remote_conn.send("ping 192.168.1.1\n")
time.sleep(1)
output = remote_conn.recv(5000)
print output
I tried this and saw that
is_global = remote_conn.recv(1024)
hangs,
Are you sure '192.168.1.10' sends somthing to be received ?
Try setting a timeout
remote_conn.settimeout(3)
3 seconds for example, do it after this line:
remote_conn = remote_conn_pre.invoke_shell()
this way the recv func does not hang and continues when timeout expires
works for me
first send some command "ls -ltr\n" and then call sleep
remote_conn.send("ls -ltr\n")
time.sleep(1)
Try running your command in a debugger and find out what line is waiting for input. You might also try sending \r or \r\n instead if just \n. Remember the enter key is really ^M
You might also try turning on detailed logging.
import logging
# ...
logging.getLogger("paramiko").setLevel(logging.DEBUG)
ive found another module (netmiko) which does exactly what i want and does all these checks. ive since abandoned trying to do it myself when someone else has already done it better.
use Netmiko! :)

How do i debug this USB-Serial connection?

I am trying to talk to a Stanford Research Systems SR760 spectrum analyzer on my mac (10.7.5) via Serial, using a Serial-to-USB adapter to connect to my laptop. I am using the Prolific USB-serial driver. Not sure which but I installed it recently. It probably is the PL2303 one.
Using Python, here's some sample code
import time
import serial
# configure the serial connections (the parameters differs on the device you
# are connecting to)
ser = serial.Serial(
port='/dev/cu.PL2303-0000201A',
baudrate=19200,
parity=serial.PARITY_NONE,
bytesize=serial.EIGHTBITS,
stopbits=serial.STOPBITS_ONE,
rtscts=0,
dsrdtr=0,
timeout=2,
)
if ser.isOpen():
ser.flushInput()
ser.flushOutput()
print """Enter your commands below.\r\nInsert "exit" to leave the
application."""
while 1:
# get keyboard input
input = raw_input(">> ")
if input == 'exit':
ser.close()
exit()
else:
ser.write(input + '\r')
out = ''
# let's wait one second before reading output (let's give device
# time to answer)
lines = 0
while 1:
time.sleep(1)
out = out + ser.readline()
lines = lines + 1
if lines > 5:
break
print "read data: " + out
Using the SR760's manual, I send it: *IDN?, a basic "identify" command. I expect for something to pop up in my terminal, nothing does. It just times out. However, if I look at the send queue on the SR760, it will show the identity string, and in fact responds to a bunch of different commands. I'm just not getting anything on my computer and that is the problem. I know it is supposed to work that way because my colleague wrote code that words on his computer (a windows laptop).
How do I even start debugging this? I've tweaked the timeout, and confirmed the sr760 had the same parameters I was expecting.

Monitor console output via ssh in python

I'm trying to find a means of monitoring the output to the console of a remove server over ssh, and from within Python.
Paramiko and Fabric python modules provide a good means of getting an ssh connection and executing specific commands on the remote server and getting the output from these commands.
However I don't want to execute anything I just want to "screen scrape" so to speak all the output being spitted out to the console on that machine.
Can Paramiko be used for this purpose, or does anyone know of another Python utility that can achieve this ?
Ok so I've managed to get this working using SSHClient.invoke_shell(), and monitoring it's output. Solaris hardware all come with ILOM (Integrated Lights Out Manager) configured, which is very useful getting a serial console on a machine.
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("9.9.9.9", 22, "username", "password")
channel = client.invoke_shell()
channel.settimeout(0.0)
while True:
r, w, e = select.select([channel], [], [])
try:
console_data = ""
while channel.recv_ready():
console_data += channel.recv(1024)
if len(console_data) == 0:
print "\n*** EOF\n"
break
# Search console_data for console prompt
# If found, start a serial console
if re.search("->", console_data):
channel.send("start -script SP/Console")
elif re.search("y/n", console_data):
channel.send("y\n")
elif re.search("SOME STRING ON CONSOLE", console_data):
print "Action completed"
break
except socket.timeout:
pass
channel.close()
client.close()
Above code connects to Service port on ILOM and waits for "->" prompt, once received it starts the serial console via "start -script SP/Console", and then anwsers "y" to continue prompt.
Now we have serial console and can monitor all output to this serial console, when some predefined string is output to the console I can exit.

Multiple Python telnet write and read commands without timer?

while True:
command = raw_input("=> ")
if command == 'Exit':
tn.write(command + "\r\n")
time.sleep(1)
tn.close()
break
tn.write(command + "\r\n")
time.sleep(2)
print tn.read_very_eager()
I've established a connection to the Telnet and I'm passing through basic commands. I want to avoid a 1 or 2 second timer between each write command because I don't want 30 write commands to take up to a minute. If I remove 'time.sleep,' I can't read the output in time for the next command. Can anyone help?

Categories