《云计算全栈》-python篇:利用多线程实现ssh并发访问

5 案例5:利用多线程实现ssh并发访问
5.1 问题

编写一个remote_comm.py脚本,实现以下功能:

在文件中取出所有远程主机IP地址
在shell命令行中接受远程服务器IP地址文件、远程服务器密码以及在远程主机上执行的命令
通过多线程实现在所有的远程服务器上并发执行命令

5.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:安装paramiko

paramiko 遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接,可以实现远程文件的上传,下载或通过ssh远程执行命令。

[root@localhost ~]# pip3 install paramiko
...
...
Successfully installed bcrypt-3.1.4 paramiko-2.4.1 pyasn1-0.4.4 pynacl-1.2.1
You are using pip version 9.0.1, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

测试是否安装成功

>>> import paramiko
>>>

步骤二:编写脚本

[root@localhost day11]# vim remote_comm.py
#!/usr/bin/env python3
import sys
import getpass
import paramiko
import threading
import os
#创建函数实现远程连接主机、服务器密码以及在远程主机上执行的命令的功能
def remote_comm(host, pwd, command):
#创建用于连接ssh服务器的实例
    ssh = paramiko.SSHClient()
#设置自动添加主机密钥
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#连接ssh服务器,添加连接的主机、用户名、密码填好
    ssh.connect(hostname=host, username='root', password=pwd)
#在ssh服务器上执行指定命令,返回3项类文件对象,分别是,输入、输出、错误
    stdin, stdout, stderr = ssh.exec_command(command)
#读取输出
    out = stdout.read()
#读取错误
    error = stderr.read()
#如果有输出
    if out:
#打印主机输出内容
        print('[%s] OUT:\n%s' % (host, out.decode('utf8')))
#如果有错误
    if error:
#打印主机错误信息
        print('[%s] ERROR:\n%s' % (host, error.decode('utf8')))
#程序结束
    ssh.close()
if __name__ == '__main__':
#设定sys.argv长度,确保remote_comm函数中参数数量
    if len(sys.argv) != 3:
        print('Usage: %s ipaddr_file "command"' % sys.argv[0])
        exit(1)
#判断命令行上输入如果不是文件,确保输入的是文件  
    if not os.path.isfile(sys.argv[1]):
        print('No such file:', sys.argv[1])
        exit(2)
#fname为存储远程主机ip的文件,用sys.argv方法,可以在执行脚本时再输入文件名,更为灵活
    fname = sys.argv[1]
#command为在远程主机上执行的命令,用sys.argv方法,可以在执行脚本时再输入相应命令,command为remote_comm函数第三个参数
    command = sys.argv[2]
#通过getpass输入远程服务器密码,pwd为remote_comm函数第二个参数
    pwd = getpass.getpass()
#打开存有远程主机ip的文件
    with open(fname) as fobj:
#将遍历文件将ip以列表形式存入ips,line.strip()可以去掉每行ip后\n
        ips = [line.strip() for line in fobj]
#循环遍历列表,获取ip地址,ip为remote_comm函数第一个参数
    for ip in ips:
#将读取到的ip地址作为remote_comm函数实际参数传递给函数,ips中有几个ip地址循环几次
#创建多线程
        t = threading.Thread(target=remote_comm, args=(ip, pwd, command))
#启用多线程
        t.start()

步骤三:测试脚本执行

#参数给少了效果如下:
[root@localhost day11]# python3 remote_comm.py server_addr.txt
Usage: remote_comm.py ipaddr_file “command”
#参数给多了效果如下:
[root@localhost day11]# python3 remote_comm.py server_addr.txt id zhangsan
Usage: remote_comm.py ipaddr_file “command”
#正常显示如下:
[root@localhost day11]# python3 remote_comm.py server_addr.txt “id zhangsan”
Password:
[192.168.4.2] OUT:
uid=1001(zhangsan) gid=1001(zhangsan) 组=1001(zhangsan)
[192.168.4.3] OUT:
uid=1001(zhangsan) gid=1001(zhangsan) 组=1001(zhangsan)
[root@localhost day11]# python3 remote_comm.py server_addr.txt “echo redhat | passwd –stdin root”
Password:
[192.168.4.3] OUT:
更改用户root的密码:
passwd:所有的身份验证令牌已经成功更新。
[192.168.4.2] OUT:
更改用户root的密码:
passwd:所有的身份验证令牌已经成功更新。
#此时密码已经变成redhat
[root@localhost day11]# python3 remote_comm.py server_addr.txt “id zhangsan”
Password:
[192.168.4.2] OUT:
uid=1001(zhangsan) gid=1001(zhangsan) 组=1001(zhangsan)
[192.168.4.3] OUT:
uid=1001(zhangsan) gid=1001(zhangsan) 组=1001(zhangsan)

你可能感兴趣的:(linux自动化运维开发实战)