1

I wrote a script a few years ago in Python 2.x and am trying to port it to run in 3.x

Here are the basics of what I am doing:
NetworkDevices is a file that contains host and access credentials for a list of devices.
DebugFile is an output file I dump stuff too as I go (depending on the debug level), so I can see when a device sent something I wasn't expecting.

NetworkDevices = open(WorkingDir + DeviceFilename,"r")
DebugFile      = open(WorkingDir + DebugFilename,"w",1)

Try
    # Create instance of SSHClient object
    ssh_pre = paramiko.SSHClient()
    # Automatically add untrusted hosts (make sure okay for security policy in your environment)
    ssh_pre.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # initiate SSH connection
    ssh_pre.connect(InputVars[0], username=InputVars[1], password=InputVars[2], timeout=10)
    # Use invoke_shell to establish an 'interactive session' 
    Conn = ssh_pre.invoke_shell()
except
    # SSH connection failed, lets try a telnet connection.
    Conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try: 
        # Open Telnet Connection to device
        Conn.connect((InputVars[0],23))
    except
        #Print some error message saying you couldn't connect, blah blah
    else 
        output = str(Conn.recv(10000))
else
    output = str(Conn.recv(10000))

# After I establish my connection via object Conn, I can always just pull more data from 
# the same connection object regardless of whether it's ssh or telnet.

if DebugVar > 3:
    DebugFile.write("Here is the initial response after connecting.\n")
    DebugFile.write("<<<1>>>\n"+output+"\n<<<1>>>\n")

Then do a bunch of stuff depending on what is to be collected, device type, etc.

The output I get is this:

Here is the initial response after connecting:
<<<1>>>
b'\r\nUShaBTC-DCTNW-CORE01#'
<<<1>>>

I am trying to get this:

Here is the initial response after connecting.
<<<1>>>
UShaBTC-DCTNW-CORE01#
<<<1>>>

I've tried using formatted string literals, but that keeps leading me down the path for using string slicing, which I am trying to avoid. It's a really simple thing I'm trying to do. Receive a "chunk" (to use a generic term) of data, look in that data for a certain string, keyword, or structure, then send something to the connection, and get another chunk of data.

Yes, what I'm looking for is in what I receive either way. I can still search on it, but at some point I need to write what I received out to a file that is readable, and I'm not having much luck doing that.

Hey one more question.... Apparently Python 3 doesn't support unbufferred file output. As I have shown I dump data to a debug file (depending on the debug level my script runs at). In a crash, it's pretty important to get the last bit of data that I received to figure out why it crashed, so I always wrote data received immediately with no buffering to my debug file, so I could figure out later where it crashed and why. Is there a way to write to a file in Python 3 without buffering? I dropped back to a buffer of 1 (instead of 0) so my script will run in Python 3.x, but I still might not see the last (1 byte I guess, haven't actually been able to find out what the units are for that buffer size).

Appreciate any help.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992

1 Answers1

0

Just call decode on the byte string:

output = Conn.recv(10000).decode('utf-8')

Though in general, you should not use SSHClient.invoke_shell. Use SSHClient.exec_command. See What is the difference between exec_command and send with invoke_shell() on Paramiko?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • Thank you Martin. I finally figured out I was trying to decode it after a type cast it to a str, which of course didn't work. Once I let the decode do the casting to str it works now. – Derek Small Apr 20 '21 at 18:46