东瑜

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

目前,很多的工作都是批量的操作Linux主机。通过python脚本,封装Linux的shell命令。保证批量操作,简易优化工作。

Python批量操作主机

安装paramiko模块

ssh是一个协议,OpenSSH是其中一个开源实现,paramiko是Python的一个库,实现了SSHv2协议(底层使用cryptography)。有了Paramiko以后,我们就可以在Python代码中直接使用SSH协议对远程服务器执行操作,而不是通过ssh命令对远程服务器进行操作。

由于paramiko属于第三方库,安装方式如下:

G:\Py>pip install paramiko

远程ssh控制主机

import paramiko
from concurrent.futures import ThreadPoolExecutor
 
class SSHParamiko(object):
 
    err = "argument passwd or rsafile can not be None"
 
    def __init__(self, host, port, user, passwd=None, rsafile=None):
        self.h = host
        self.p = port
        self.u = user
        self.w = passwd
        self.rsa = rsafile
 
    def _connect(self):
        if self.w:
            return self.pwd_connect()
        elif self.rsa:
            return self.rsa_connect()
        else:
            raise ConnectionError(self.err)
 
    def pwd_connect(self):
        conn = paramiko.SSHClient()
        conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        conn.connect(self.h, self.p, self.u, self.w)
        return conn
 
    def rsa_connect(self):
        pkey = paramiko.RSAKey.from_private_key_file(self.rsa)
        conn = paramiko.SSHClient()
        conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        conn.connect(hostname=self.h, port=self.p, username=self.u, pkey=pkey)
        return conn
 
    def run_cmd(self, cmd):
        conn = self._connect()
        stdin, stdout, stderr = conn.exec_command(cmd)
        code = stdout.channel.recv_exit_status()
        stdout, stderr = stdout.read(), stderr.read()
        conn.close()
        if not stderr:
            return code, stdout.decode()
        else:
            return code, stderr.decode()
 

class AllRun(object):
    def __init__(self, ssh_objs, cmds, max_worker=50):
        self.objs = [o for o in ssh_objs]
        self.cmds = [c for c in cmds]
        self.max_worker = max_worker  # 最大并发线程数
 
        self.success_hosts = []       # 存放成功机器数目
        self.failed_hosts = []        # 存放失败的机器IP
        self.mode = None
        self.func = None
 
    def serial_exec(self, obj):
        """单台机器上串行执行命令,并返回结果至字典"""
        result = list()
        for c in self.cmds:
            r = obj.run_cmd(c)
            result.append([c, r])
        return obj, result
 
    def concurrent_run(self):
        """并发执行"""
        future = ThreadPoolExecutor(self.max_worker)
        for obj in self.objs:
            try:
                future.submit(self.serial_exec, obj).add_done_callback(self.callback)
            except Exception as err:
                print(err)
        future.shutdown(wait=True)
 
    def callback(self, future_obj):
        """回调函数,处理返回结果"""
        ssh_obj, rlist = future_obj.result()
        print("{} execute detail:".format(ssh_obj.h))
        is_success = True
        for item in rlist:
            cmd, [code, res] = item
            info = f"{cmd} | code => {code}\nResult:\n{res}"
            print(info)
        if is_success:
            self.success_hosts.append(ssh_obj.h)
            if ssh_obj.h in self.failed_hosts:
                self.failed_hosts.remove(ssh_obj.h)
 
    def overview(self):
        """展示总的执行结果"""
        for i in self.success_hosts:
            print(i)
        print("-" * 30)
        for j in self.failed_hosts:
            print(j)
        info = "Success hosts {}; Failed hosts {}."
        s, f = len(self.success_hosts), len(self.failed_hosts)
        info = info.format(s, f)
        print(info)
        
if __name__ == '__main__':
#   测试环境
    ip_204 = SSHParamiko("172.17.xx.204", 22, "root", "xx")
    ip_200 = SSHParamiko("172.17.xx.200", 22, "root", "xx")
    ip_202 = SSHParamiko("172.17.xx.202", 22, "root", "xx")
#   种子环境
    ip_200_30 = SSHParamiko("172.30.xx.30", 9900, "root", "xx")
    cmds =["df -h"]
#    all_ip = AllRun([ip_204, ip_200,ip_202], cmds)
    seed_ip = AllRun([ip_200_30], cmds)
    seed_ip.concurrent_run()
    seed_ip.overview()
    print("--------------------------------------------------------------")
    res = ip_200_30.run_cmd("df -h")
    print(res[0])
    print(res[1])  

另存为batch01.py,执行结果如下:

G:\Py>python batch01.py
172.30.200.30 execute detail:
df -h | code => 0
Result:
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        30G  3.4G   25G  13% /
tmpfs           7.8G     0  7.8G   0% /dev/shm
/dev/sda1       190M   52M  129M  29% /boot
/dev/sdb1       197G   20G  168G  11% /opt

172.30.200.30
------------------------------
Success hosts 1; Failed hosts 0.
--------------------------------------------------------------
0
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        30G  3.4G   25G  13% /
tmpfs           7.8G     0  7.8G   0% /dev/shm
/dev/sda1       190M   52M  129M  29% /boot
/dev/sdb1       197G   20G  168G  11% /opt

posted on 2020-03-15 15:28  东瑜  阅读(564)  评论(0编辑  收藏  举报
\\页脚html代码