0

i have read other Stackoverflow threads on this. Those are older posts, i would like to get the latest update.

Is it possible to send multiple commands over single channel in Paramiko ? or is it still not possible ?

If so, is there any other library which can do the same.

Example scenario, automating the Cisco router confi. : User need to first enter "Config t" before entering the other other commands. Its currently not possible in paramiko.

THanks.

Bala
  • 381
  • 3
  • 16
  • Sounds like you may need an interactive session, which paramiko does support - does the following question help? https://stackoverflow.com/questions/373639/running-interactive-commands-in-paramiko – DNA Mar 03 '14 at 08:58
  • Nope, i do not want an interactive session. Thanks. – Bala Mar 03 '14 at 11:37
  • Just to clarify, I do not mean a manual (human) interactive session - I mean automating an interactive command, which is what your example scenario is. I think this can be done in paramiko or pexpect. – DNA Mar 03 '14 at 11:45

4 Answers4

0

if you are planning to use the exec_command() method provided within the paramiko API , you would be limited to send only a single command at a time , as soon as the command has been executed the channel is closed.

The below excerpt from Paramiko API docs .

exec_command(self, command) source code Execute a command on the server. If the server allows it, the channel will then be directly connected to the stdin, stdout, and stderr of the command being executed.

When the command finishes executing, the channel will be closed and can't be reused. You must open a new channel if you wish to execute another command.

but since transport is also a form of socket , you can send commands without using the exec_command() method, using barebone socket programming.

Incase you have a defined set of commands then both pexpect and exscript can be used , where you read a set of commands form a file and send them across the channel.

durga
  • 404
  • 6
  • 12
0

See my answer here or this page

import threading, paramiko

strdata=''
fulldata=''

class ssh:
    shell = None
    client = None
    transport = None

    def __init__(self, address, username, password):
        print("Connecting to server on ip", str(address) + ".")
        self.client = paramiko.client.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
        self.client.connect(address, username=username, password=password, look_for_keys=False)
        self.transport = paramiko.Transport((address, 22))
        self.transport.connect(username=username, password=password)

        thread = threading.Thread(target=self.process)
        thread.daemon = True
        thread.start()

    def closeConnection(self):
        if(self.client != None):
            self.client.close()
            self.transport.close()

    def openShell(self):
        self.shell = self.client.invoke_shell()

    def sendShell(self, command):
        if(self.shell):
            self.shell.send(command + "\n")
        else:
            print("Shell not opened.")

    def process(self):
        global strdata, fulldata
        while True:
            # Print data when available
            if self.shell is not None and self.shell.recv_ready():
                alldata = self.shell.recv(1024)
                while self.shell.recv_ready():
                    alldata += self.shell.recv(1024)
                strdata = strdata + str(alldata)
                fulldata = fulldata + str(alldata)
                strdata = self.print_lines(strdata) # print all received data except last line

    def print_lines(self, data):
        last_line = data
        if '\n' in data:
            lines = data.splitlines()
            for i in range(0, len(lines)-1):
                print(lines[i])
            last_line = lines[len(lines) - 1]
            if data.endswith('\n'):
                print(last_line)
                last_line = ''
        return last_line


sshUsername = "SSH USERNAME"
sshPassword = "SSH PASSWORD"
sshServer = "SSH SERVER ADDRESS"


connection = ssh(sshServer, sshUsername, sshPassword)
connection.openShell()
connection.send_shell('cmd1')
connection.send_shell('cmd2')
connection.send_shell('cmd3')
time.sleep(10)
print(strdata)    # print the last line of received data
print('==========================')
print(fulldata)   # This contains the complete data received.
print('==========================')
connection.close_connection()
Nagabhushan S N
  • 6,407
  • 8
  • 44
  • 87
0

Have a look at parallel-ssh:

from pssh.pssh2_client import ParallelSSHClient

cmds = ['my cmd1', 'my cmd2']
hosts = ['myhost']
client = ParallelSSHClient(hosts)

for cmd in cmds:
    output = client.run_command(cmd)
    # Wait for completion
    client.join(output)

Single client, multiple commands over same SSH session and optionally multiple hosts in parallel - also non-blocking.

danny
  • 5,140
  • 1
  • 19
  • 31
  • This doesn't do what you think it does. This runs each command under a separate channel. – jacob May 06 '20 at 16:21
0

I find this simple to understand and use. Code provides 2 examples with singlehost and multihost. Also added example where you can login to a second user and continue your commands with that user.

More info can be found in here: https://parallel-ssh.readthedocs.io/en/latest/advanced.html?highlight=channel#interactive-shells

from pssh.clients import SSHClient
from pssh.exceptions import Timeout
from pssh.clients import ParallelSSHClient
from pssh.config import HostConfig

def singleHost():
    host_ = "10.3.0.10"
    pwd_ = "<pwd>"
    pwd_root = "<root pwd>"
    user_ = "<user>"


    client = SSHClient(host_, user=user_, password=pwd_, timeout=4, num_retries=1)

    #####
    shell = client.open_shell(read_timeout=2)
    shell.run("whoami")

    # login as new user example
    shell.run("su - root")
    shell.stdin.write(pwd_root + "\n")
    shell.stdin.flush()
    shell.run("pwd")

    try:
        # Reading Partial Shell Output, with 'timeout' > client.open_shell(read_timeout=2)
        for line in shell.stdout:
            print(line)
    except Timeout:
        pass
    shell.run("whoami")
    shell.run("cd ..")
    print(".......")
    try:
        # Reading Partial Shell Output, with 'timeout' > client.open_shell(read_timeout=2)
        for line in shell.stdout:
            print(line)
    except Timeout:
        pass
    shell.close()

def multiHost():
    pwd_ = "<pwd>"
    user_ = "<user>"

    workingIP_list = ["10.3.0.10", "10.3.0.10"]
    host_config_ = []
    # HostConfig is needed one per each 'workingIP_list'
    host_config_.append(HostConfig(user=user_, password=pwd_))
    host_config_.append(HostConfig(user=user_, password=pwd_))
    client_ = ParallelSSHClient(workingIP_list, host_config=host_config_, num_retries=1, timeout=3)

    # now you have an open shell
    shells = client_.open_shell(read_timeout=2)

    command = "pwd"
    client_.run_shell_commands(shells, command)

    try:
        # Reading Partial Shell Output, with 'timeout' > client_.open_shell(read_timeout=2)
        for line in shells[0].stdout:
            print(line)
    except Timeout:
        pass
    print(".......")
    command = "cd repo/"
    client_.run_shell_commands(shells, command)

    command = "pwd"
    client_.run_shell_commands(shells, command)

    #Joined on shells are closed and may not run any further commands.
    client_.join_shells(shells)


    for shell in shells:
        for line in shell.stdout:
            print(line)
        print(shell.exit_code)


if __name__ == '__main__':
    print("singleHost example:")
    singleHost()
    print("multiHost example:")
    multiHost()
First Last
  • 19
  • 5