python multiprocessing paramiko ssh connections

烂漫一生 提交于 2021-02-08 09:55:48

问题


I am writing a script to connect to a bunch of cisco routers and run commands on them, hosts and commands are put into a text file and then read from the script. Below is the code i got, when i don't use the pool.map everything works good, but when trying to use the pool.map to spawn more process, i keep getting errors.

#!/usr/bin/python

#Import modules
from multiprocessing.pool import ThreadPool
import sys, os
import paramiko
import time
import getpass
import socket


def unpack_call(callable_arguments):
callable, arguments = callable_arguments
return callable(*arguments)


def conn(host, commands):

   # Create instance of SSH client object
   remote_conn_pre = paramiko.SSHClient()

   # Automatically add untrusted hosts
   remote_conn_pre.set_missing_host_key_policy(paramiko.AutoAddPolicy())

   try:
      # Pass host to connect to device via SSH
      remote_conn_pre.connect(host, username=username, password=password, look_for_keys=False, allow_agent=False, timeout=5)
      print "Working on %s" % host
      remote_conn = remote_conn_pre.invoke_shell()
      output = remote_conn.recv(1000)

      disable_paging(remote_conn)
      remote_conn.send("enable")
      remote_conn.send("\n")
      remote_conn.send(password)
      remote_conn.send("\n")

      output = command(commands, remote_conn,host)
      remote_conn.close()
      print "Completed %s" % host
   except (paramiko.SSHException, socket.error) as se:
      print "Error connecting to %s and reason is %s" % (host, se)
      time.sleep(1)

def disable_paging(remote_conn):
    ''' Disable Paging on Cisco '''
    remote_conn.send("term len 0\n")
    time.sleep(1)

    # Clear the buffer on the screen
    output = remote_conn.recv(1000)

    return output



def command(commands,remote_conn,host):

   # Open commands.txt file for reading
   c   = open(commands, "r")
   fil = open("session_%s.txt" % host, "w")

   for l in c:
      remote_conn.send(l)
      time.sleep(1)
      output = remote_conn.recv(50000)
      fil.write(output)

   fil.close()


if __name__ == "__main__":

   # Get login credentials before starting script
   username = raw_input("Username: ")
   password = getpass.getpass("Password: ")

   host     = sys.argv[1]
   commands = sys.argv[2]

   hostnames = []
   h = open("hosts.txt", "r")
   for hos in h:
   #    conn(hos.strip(),commands)
        hostnames.append(hos.strip())
   h.close()

   pool = ThreadPool(5)
   pool.map(unpack_call, [(conn, (hostname,commands)) for hostname in hostnames])
   pool.close()
   pool.join()

UPDATE: After updating code i am now getting this error

  Traceback (most recent call last):

  File "getinfoTH.py", line 91, in <module>

    pool.map(unpack_call, [(conn, (hostnames,commands)) for hostname in hostnames])

  File "/usr/lib64/python2.7/multiprocessing/pool.py", line 250, in map

    return self.map_async(func, iterable, chunksize).get()

  File "/usr/lib64/python2.7/multiprocessing/pool.py", line 554, in get

    raise self._value

TypeError: getaddrinfo() argument 1 must be string or None

UPDATE: used map instead of pool.map and below is the stack trace

Traceback (most recent call last):

  File "getinfo.py", line 93, in <module>

    map(unpack_call, [(conn, (hostnames,commands)) for hostname in hostnames])

  File "getinfo.py", line 15, in unpack_call

    return callable(*arguments)

  File "getinfo.py", line 32, in conn

    remote_conn_pre.connect(host, username=username, password=password, look_for_keys=False, allow_agent=False, timeout=5)

  File "/usr/lib/python2.7/site-packages/paramiko/client.py", line 296, in connect

    to_try = list(self._families_and_addresses(hostname, port))

  File "/usr/lib/python2.7/site-packages/paramiko/client.py", line 200, in _families_and_addresses

    addrinfos = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM)

TypeError: getaddrinfo() argument 1 must be string or None

回答1:


You are passing commands (a str) as chunksize (an int).

# your code
pool.map(conn,hostnames,commands)
# multiprocessing documentation
pool.map(func, iterable, chunksize)

Note that unlike map, Pool.map takes only one iterable. You must either change your function to take only one argument, or add a wrapper to unpack arguments:

def unpack_call(callable_arguments):
    callable, arguments = callable_arguments
    return callable(*arguments)

...

pool.map(unpack_call, [(conn, (hostname,commands)) for hostname in hostnames])
#        ^              ^     ^ arguments
#        |              | command
#        | unpack helper


来源:https://stackoverflow.com/questions/52525896/python-multiprocessing-paramiko-ssh-connections

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!