I am working on a script to pull configs from Cisco devices in GNS3. Currently it is using a hard coded IP & port due to another separate issue but this is the code I am currently using.
import getpass
import telnetlib
print "Getting running-config 127.0.0.1:5002"
tn = telnetlib.Telnet("127.0.0.1","5002")
tn.write("terminal length 0\n")
tn.write("show run\n")
tn.write("exit\n")
readoutput = tn.read_until("exit")
saveoutput = open("C:\Programdata\switch.txt","w")
saveoutput.write(readoutput)
saveoutput.write("\n")
saveoutput.close
print tn.read_all()
If I comment out the readouput and saveoutput blocks of code the script runs through as fast as I would expect it to. However once I leave that code in there it just sits and hangs. I have put print() commands in to verify and it hangs on the readoutput line. I have tried both tn.read_all & tn.read_until (without and without a string parameter) and neither works.
Even though the readoutput is not working I know something is occurring because if I telnet into the switch with telnet 127.0.0.1 5002 in a command prompt it comes up without issue as well as being able to progress through my terminal commands.
Edit:
I did more testing with this today and found out through the use of a lot of sleep timers and printing to the terminal what was going on. As it turns out for some reason the telnet session is not actually pressing enter when it should. I tried changing the tn.write("text\n") to tn.write("text" + "\n")and even splitting that into two write commands, but none of it works. Below is a telnet session I opened after some failed attempts at making the script work. Note all the commands are just sitting there in line? If I change the readoutput to look for "xit" which is the text on the first line of the ios console, then it will find it in telnet and print everything in the telnet session to that point.
If anyone knows why "\n" is not actually hitting enter I would greatly appreciate the help as this should be my last major hurdle to making the program this script is a part of work.
The reason for this behaviour is because \n isn't actually carriage return (CR) - it's line feed (LF) in string, and different systems may have different EOL implementation (the most obvious example being Linux's \n versus Windows's \r\n). In case of Cisco IOS, it seems that \r is enough, although I can't currently verify it.
Try adding \r\n as this is default Telnet behaviour according to the spec, that should work.
All of your code is True and also both of :
tn.write("text\n")
tn.write("text" + "\n")
Is true. Just one missing is b :
Your code should be like this :
tn.write(b"en" + b"\n")
tn.write(b"terminal length 0\n")
tn.write(b"show run\n")
tn.write(b"exit\n")
Related
I'm pretty new to python and linux and I'm running into a problem...
So I'm trying to run the following code
(It is supposed to inform the person in front of the terminal, that the program is still running and then delete that line after 1 second):
import sys
while True:
# do something
sys.stdout.write("Still going...")
time.sleep(1)
sys.stdout.write("\r")
sys.stdout.flush()
This works perfectly fine on windows on python 3.8, but when i run it on my linux vps with python 3.6.9 via the "python3" command it doesn't flush the "\r", so the "Still going..." line only gets deleted and immediately reprinted the next time it reaches sys.stdout.write("Still going...").
If anyone has an idea what's going on here - please tell me
Any help is appreciated!
Windows, Mac OS and UNIXes code new lines with differents chars.
Windows uses \r\n
Mac OS uses \r
UNIXes use \n
if you want your program to be cross-platform, you should use os.linesep instead of an OS-specific linebreak
answering the comment:
Indeed on Windows, \r just return at the start of the line while \n actually starts a new line (see this StackExchange anwser for a nice explanation).
I assume that, on windows, it allows you to simply write on the same line until the program exits.
Sadly it could work at least with some terminals on UNIXes but not necessarily on every terminals...
As a work around, you could probably use the \b character which deletes the last caracter of the line, like the [backspace] key.
I have an issue that has been giving me a headache for a few days. I am using the Paramiko module with Python 2.7.10 and I'd like to issue multiple commands to a Brocade router, but only return output from one of the given commands like so:
#!/usr/bin/env python
import paramiko, time
router = 'r1.test.example.com'
password = 'password'
username = 'testuser'
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(router, username=username, password=password)
print('Successfully connected to %s' % router)
remote_conn = ssh.invoke_shell()
output = remote_conn.recv(1000)
# Disable paging on Brocade.
remote_conn.send('terminal length 0\n')
# Check interface status.
remote_conn.send('show interfaces ethernet 0/1\n') # I only want output from this command.
time.sleep(2)
output = remote_conn.recv(5000)
print(output)
If I were to print the full output it would contain everything issued to the router, but I only want to see output from the show interfaces ethernet 0/1\n command.
Can anyone help with this issue?
One final thing I would like to ask. I want to filter through the output variable and check for occurrences of strings like "up" or "down", but I can't seem to get it to work because everything in the output appears to be on new lines?
For example:
If I iterate over the output variable in a for loop I get all of the characters in the variable like so:
for line in output:
print(line)
I get an output like this:
t
e
r
m
i
n
a
l
l
e
n
g
t
h
0
Any way around this?
Again,
Thanks in advance for any help.
Best regards,
Aaron C.
After reading all of the comment I have made the following changes:
#!/usr/bin/env python
import paramiko, time
router = 'r2.test.example.com'
password = 'password'
username = 'testuser'
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(router, username=username, password=password)
print('Successfully connected to %s' % router)
remote_conn = ssh.invoke_shell()
output = remote_conn.recv(1000)
# Disable paging on Brocade.
remote_conn.send('terminal length 0\n')
time.sleep(2)
# Clearing output.
if remote_conn.recv_ready():
output = remote_conn.recv(1000)
# Check interface status.
remote_conn.send('show interfaces ethernet 4/1\n') # I only want output from this command.
time.sleep(2)
# Getting output I want.
if remote_conn.recv_ready():
output = remote_conn.recv(5000)
print(output)
# Test: Check if interface is up.
for line in output.split('\n'):
if 'line protocol is up' in line:
print(line)
Everything works great now.
Thank you for all the help.
Best regards,
Aaron C.
For your second question: Though I am not specialist of paramiko, I see that function recv, according to the doc, returns a string. If you apply a for loop on a string, you will get characters (and not lines as one might perhaps expect). The newline is caused by your use of the print function as explained on this page, at paragraph 6.3.
I haven't studied what paramiko suggests to do. But why don't you treat the full string as a single entity? For example, you could check the presence of "up" as:
if "up" in output:
Or, if that suits your needs better, you could split the string into lines and then do whatever test you want to do:
for line in output.split('\n'):
If you can, the exec_command() call provides a simpler mechanism to invoke a command. I have seen Cisco switches abruptly drop connections that try exec_command(), so that may not be usable with Brocade devices.
If you must go the invoke_shell() route, be sure to clear all pending output after connecting and after send('terminal length 0\n'), checking recv_ready() before calling recv() to avoid blocking on reading data that might not ever arrive. Since you are controlling an interactive shell, sleep() calls might be needed to allow the server adequate time to process and send data, or it might be necessary to poll the output string to confirm that your last command completed by recognizing the shell prompt string.
I need to Telnet into my router and issue a reboot command on it. And it has to be achieved with Python. Here's the code I've got:
import sys
import telnetlib
HOST = "192.168.1.254"
user = "Administrator"
password = "xxxxxxxx"
port = "23"
telnet = telnetlib.Telnet(HOST,port)
telnet.read_until(b"login: ")
telnet.write(admin.encode('ascii') + b"\n")
telnet.read_until(b"Password: ")
telnet.write(password.encode('ascii') + b"\n")
telnet.write(b"system reboot\n")
telnet.close()
When I'm initating it in command prompt it'd just stay blank, no errors whatsoever. It's as if it's loading something for so long, but the router would not reboot. The script sort of hangs.
Thanks for helping!
I faced the same issue today, 1.5 years after your question. In my case, the issue was resolved by removing the extra space, i.e.:
telnet.read_until(b"Password: ") # note the space before "
becomes:
telnet.read_until(b"Password:") # no space before "
It seems, the problem exists because of the extra space that is not output by telnet serve and thus read_until is not able to find the specified string.
To my mind, there is something wrong with string passed to router. They must not be byte (the b prefix is not needed). Try removing it. String encoding also seems strange.
read_all()" to read data from a cisco device.
some time it reads the data and sometime it won't read and gives empty string.
I tried below 2 commands but still it's not consitently reading data.
data=tn.read_until("exit")
data= tn.read_all()
please give some inputs i am new to python.
code i am using:
_command2='show chassis'
print 'Commands issued............'
#ISSUE COMMANDS VIA TELNET
tn.write("term len 0\r")
#tn.read_until(" ")
#tn.write(_command1+"\r")
tn.write(_command2+"\r")
tn.write("exit\r" )
print 'Read telnet data............'
#READ TELNET DATA
#data=tn.read_eager()
data=tn.read_until("exit")
#data= tn.read_all()
#print data
print 'Telnet data read successfully............'
I too faced the same problem..This would help:
tn = telnetlib.Telnet('64.0.0.1')
tn.write('ls \r\n')
data = ''
while data.find('#') == -1:
data = tn.read_very_eager()
print data
This snippet reads the info after a command being executed.
And reads till '#' prompt is shown.
Short answer:
Use time.sleep(1) in between write commands
Long answer:
When you enter a command on a Cisco IOS console, it blocks until the command completes. Any input you enter into the console while the command was running is piped into the running command, much like STDIN works on a bash shell. However in bash, if a commands doesn't explicitly read the input, upon the exit of the program bash takes the unconsumed input and interprets it as a shell command. So if you want to run two commands one after another, where the first command does not read from STDIN, you can enter the second command while first command is running, i.e. you don't have to wait for the first command to finish before you enter another command. This sort of a buffering mechanism makes telnet scripting easy and we have grown to expect this from mature shells. Apparently Cisco IOS lacks this feature, and so you have to make sure you don't enter your commands too soon. There are two ways I can think of, to go about it:
Wait for a fixed amount of time between commands. Usually 1 second is a safe bet for most commands.
Parse the output after each command until you find the prompt, then enter the next command, then parse again, and so on.
Use:
tn.read_very_eager()
instead of tn.read_all() - read_all waits until the connection is closed
#yogi 's answer is almost right.
but some details to be explained
data = ''
finish = '' #m1
while data.find(finish) == -1:
data += tn.read_very_eager() # m2
print data
m1: there is what your telnet server returns when command finished
m2: there should be +=, because some command results has several lines
I'm trying to automate the download of Argos data using Python's telnetlib, but I can't seem to figure out how to get it to download all of the output. Part of my problem may be that I don't really understand the seemingly asynchronous nature of the commands.
Here's the code:
tn = telnetlib.Telnet(host = HOST, timeout = 60)
with open("argos_prv_{0}-1.txt".format(now_str), 'w') as of:
tn.read_until("Username: ")
tn.write(user + "\n")
tn.read_until("Password: ")
tn.write(password + "\n")
tn.read_until("/")
# Here's the command I'm trying to get the results of:
tn.write("prv,,ds,{0:d},009919,009920\n".format(start_doy))
# At this point, it's presumably dumped it all
tn.read_until("ARGOS READY")
tn.read_until("/")
# Logging out
tn.write("lo\n")
lines = tn.read_all()
of.write(lines)
of.flush()
The code seems to run just fine, but when I look at the output file, it never has everything in it, cutting out at some random point. When I type the same commands in a real telnet session, it works just fine.
I get the sense it has something to do with trying to read_all() after logging out (tn.write("lo\n")), but when I look at the example documentation for telnetlib, it pretty much looks just like this.
Anyway, my question is: can anyone see what I'm doing wrong here? I want to grab the results of the prv,,ds command, but I'm only getting some of it using this particular code.
Thanks.
# At this point, it's presumably dumped it all
tn.read_until("ARGOS READY")
tn.read_until("/")
At a guess, this bit is sucking up the data and doing nothing with it. Think of it like a pair of pipes - you send stuff one way with write, and pull stuff back with read_*. If you've already sucked the stuff up, it won't still be waiting in the pipe when you do read_all later.
EDIT:
OK, you're seeing a different problem. Try this:
lines = tn.read_until("ARGOS READY")
lines += tn.read_until("/")
tn.write("lo\n")
# Write out lines to file.