tl/dr: Is there a simple way to get a command's output during a telnet session with Python?
I am writing a Python script (using 3.4) to automate actions during a telnet session. I want to be able to telnet in, write to the command line to perform an action, and then return the output from that command. I have a method, but it seems like it could be improved upon, and it is not very dynamic.
My current method:
def telnet_in(ip):
"""Telnets into the device"""
tn = telnetlib.Telnet(ip)
tn.read_until(b"login: ")
tn.write(TEL_PASS)
tn.read_until(PROMPT) # Clear buffer of output
return tn
This will telnet into my device just fine for my setup. The next part I try to cat some information from the device:
def get_model(ip):
"""Returns the device's model"""
session = telnet_in(ip)
session.write(b"cat " + MODEL_DIR + b"model\r\n")
time.sleep(1) # Give it time to enter buffer
model = session.read_very_eager()
model = model[26:-4] # Clean up output to only return model
model = decode_byte_str(model) # Decode to str
telnet_exit(session)
return model
A few things I have noticed/tried:
- I have to use the byte str 'b' for when I use tn.write()
- I have to use \r as well.
Without those, I do not get a return or I get an error.
Additionally:
- The output I get from
model = session.read_very_eager()
will return the string that I used for my command as well as the prompt after the command's returned output. I have to trim the string down to size to just get the model str. - Given that I have to use 'b' for my strings, the string returned is also a byte string and needs to be decoded. I handle that with my decode_byte_str() just fine:
def decode_byte_str(byte_str):
"""Decodes a byte string using utf-8"""
return byte_str.decode("utf-8")
I am able to get the string in the end that I am looking for, but it seems to be such a convoluted way to just get a returned string. Also, this method is not dynamic, and I have to write individual functions for each info that I want to obtain, given that I have to trim the strings to a certain size. Certainly, I could just "pass" the size that needs to be trimmed, but that is additional work that really shouldn't be needed. Further, if I want to write a function that takes a variable that the user inputs, then I wouldn't know the exact amount to trim before the output. I suppose I could get the length of the str, and then pass that length in, but again that further complicates what should be a simple task.
So, my question is: Is there a simple way to get the command's output during a telnet session with Python? Also, I am not married to using telnetlib. If there is a better lib or method then I am open to those as well.
Thanks in advance!
EDIT: Here is my updated version, if anyone wants to use it until we can find an easier/better way:
def telnet_in(ip):
"""Telnets into a device"""
tn = telnetlib.Telnet(ip)
tn.read_until(b"login: ")
tn.write(TEL_PASS)
tn.read_until(PROMPT) # Clear buffer of output
return tn
def telnet_exit(session):
"""Exits a telnet session"""
session.write(b"exit\r\n")
def _encode_str(in_str):
"""Encodes a string to a byte string"""
return bytes(in_str, encoding="utf-8")
def _decode_byte_str(byte_str):
"""Decodes a byte string using utf-8"""
return byte_str.decode("utf-8")
def _get_cmd_output(session, cmd_str):
"""Returns output from a command"""
cmd_str_len = len(cmd_str)
bcmd_str = _encode_str(cmd_str) # Encode str to byte str
session.write(bcmd_str)
time.sleep(0.1) # Give it time to enter buffer
cmd_out = session.read_very_eager()
cmd_out = cmd_out[cmd_str_len:PROMPT_LEN] # Trim output to only return command's returned output
cmd_out = _decode_byte_str(cmd_out) # Decode to a str
return cmd_out
def get_model(ip):
"""Returns the device's model"""
session = telnet_in(ip)
cat_model = "cat " + INFO_DIR + "model\r\n"
model = _get_cmd_output(session, cat_model)
telnet_exit(session)
return model
def get_device_id(ip):
"""Returns the device id"""
session = telnet_in(ip)
cat_device_id = "cat " + INFO_DIR + "device_id\r\n"
device_id = _get_cmd_output(session, cat_device_id)
telnet_exit(session)
return device_id
Works for my purposes. I still wonder if there is already some built-in lib that can already handle this stuff.