Question

I have a class that creates the connection. I can connect and execute 1 command before the channel is closed. On another system i have i can execute multiple commands and the channel does not close. Obviously its a config issue with the systems i am trying to connect to.

class connect:

    newconnection = ''

    def __init__(self,username,password): 
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            ssh.connect('somehost', username=username,password=password,port=2222,timeout=5)
        except:
            print "Count not connect"
            sys.exit()
        self.newconnection = ssh

    def con(self):
        return self.newconnection

Then i use 'ls' command just to print some output

sshconnection = connect('someuser','somepassword').con()


stdin, stdout, stderr = sshconnection.exec_command("ls -lsa")

print stdout.readlines() 
print stdout 

stdin, stdout, stderr = sshconnection.exec_command("ls -lsa")

print stdout.readlines() 
print stdout 

sshconnection.close()
sys.exit()

After the first exec_command runs it prints the expected output of the dir list. When i print stdout after the first exec_command it looks like the channel is closed

<paramiko.ChannelFile from <paramiko.Channel 1 (closed) -> <paramiko.Transport at 0x2400f10L (cipher aes128-ctr, 128 bits) (active; 0 open channel(s))>>> 

Like i said on another system i am able to keep running commands and the connection doesn't close. Is there a way i can keep this open? or a better way i can see the reason why it closes?

edit: So it looks like you can only run 1 command per SSHClient.exec_command... so i decided to get_transport().open_session() and then run a command. The first one always works. The second one always fails and the scripts just hangs

Was it helpful?

Solution

With just paramiko after the exec_command executes the channel is closed and the ssh returns an auth prompt.

Seems its not possible with just paramiko, try fabric or another tool.

** fabric did not work out too.

OTHER TIPS

Please see the following referece as it provides a way to do this in Paramiko:

How do you execute multiple commands in a single session in Paramiko? (Python)

it's possible with netmiko (tested on windows). this example is written for connecting to cisco devices but the principle is adaptable for others as well.

import netmiko
from netmiko import ConnectHandler
import json

def connect_enable_silent(ip_address,ios_command):
    with open ("credentials.txt") as line:
        line_1 = json.load(line)
        for k,v in line_1.items():
            router=(k,v)
            try:
                ssh = ConnectHandler(**router[1],device_type="cisco_ios",ip=ip_address)
                ssh.enable()
            except netmiko.ssh_exception.NetMikoAuthenticationException:
                #incorrect credentials
                continue
            except netmiko.ssh_exception.NetMikoTimeoutException:
                #oddly enough if it can log in but not able to authenticate to enable mode the ssh.enable() command does not give an authentication error
                #but a time-out error instead
                try:
                    ssh = ConnectHandler(username = router[1]['username'],password = router[1]['password'],device_type="cisco_ios", ip=ip_address)
                except netmiko.ssh_exception.NetMikoTimeoutException:
                    # connection timed out (ssh not enabled on device, try telnet)
                    continue
                except Exception:
                    continue
                else:
                    output = ssh.send_command(ios_command)
                    ssh.disconnect()
                    if "at '^' marker." in output:
                        #trying to run a command that requires enble mode but not authenticated to enable mode
                        continue
                    return output
            except Exception:
                continue
            else:
                output = ssh.send_command(ios_command)
                ssh.disconnect()
                return output

output = connect_enable_silent(ip_address,ios_command)
for line in output.split('\n'):
    print(line)

Credentials text is meant to store different credentials in case you are planning to call this function to access multiple devices and not all of them using the same credentials. It is in the format:

{"credentials_1":{"username":"username_1","password":"password_1","secret":"secret_1"},
"credentials_2":{"username":"username_2","password":"password_2","secret":"secret_2"},
"credentials_3": {"username": "username_3", "password": "password_3"}
}

The exceptions can be changed to do different things, in my case i just needed it to not return an error and continue trying the next set, which is why most exceptions are silenced.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top