• Python MySSH 实现剧本执行器


    通过封装Paramiko这个SSH模块,我们可以实现远程批量管理Linux主机,在上一篇文章中我们封装过一个MySSH类,这个类可以执行命令上传下载文件等,我们在这个类的基础上,实现一个简单的任务执行功能。

    • 执行方式
    • 程序会在Json文件中解析参数,并将参数与所对应的主机进行关联,对不同的主机组执行不同的命令,实现批量脚本执行。

    实现批量命令执行: 首先利用封装好的MySSH类为基础,实现一个批量命令执行器,该工具通过命令行参数传递执行不同的操作。

    import os,json,sys
    from MySSH import MySSH
    
    def ping(group):
        with open("config.json" , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            ptr = config_load.get(group)
            print("-" * 120)
            print("{0:15} \t {1:6} \t {2:5}".format("IP地址", "用户名", "状态"))
            print("-" * 120)
    
            for x in ptr:
                ssh = MySSH(x[0],x[1],x[2],22)
                ssh.Init()
                ref = ssh.GetPing()
                if ref == True:
                    print("{0:15} \t {1:6} \t {2:5}".format(x[0],x[1],"已连接"))
                else:
                    print("{0:15} \t {1:6} \t {2:5}".format(x[0], x[1], "未连接"))
            print("\n")
    
    def run(group,command):
        with open("config.json" , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            ptr = config_load.get(group)
            for x in ptr:
                ssh = MySSH(x[0],x[1],x[2],22)
                ssh.Init()
                ref = ssh.BatchCMD(command)
                print("\n")
                print("-" * 120)
                print("执行IP: {0:15} ".format(x[0]))
                print("-" * 120)
                print(ref)
    
    def memory(group):
        with open("config.json" , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            ptr = config_load.get(group)
            print("-" * 120)
            print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format("IP地址", "总内存", "剩余内存", "利用率(百分比)"))
            print("-" * 120)
    
            for x in ptr:
                ssh = MySSH(x[0],x[1],x[2],22)
                ssh.Init()
                ref = ssh.GetAllMemSpace()
                if ref != None:
                    print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format(x[0],ref["Total"],ref["Free"],ref["Percentage"]))
    
    def disk(group):
        with open("config.json" , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            ptr = config_load.get(group)
    
            for x in ptr:
                ssh = MySSH(x[0],x[1],x[2],22)
                ssh.Init()
                print("-" * 120)
                print("IP地址: {0:15} \t".format(x[0]))
                print("-" * 120)
    
                ref = ssh.GetAllDiskSpace()
                if len(ref) !=0:
                    for k,v in ref.items():
                        print("磁盘路径: {0:30} \t 磁盘利用率: {1:8}".format(k,v))
    
    def cpu(group):
        with open("config.json" , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            ptr = config_load.get(group)
            print("-" * 120)
            print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format("IP地址", "用户态", "内核态", "空闲率(百分比)"))
            print("-" * 120)
    
            for x in ptr:
                ssh = MySSH(x[0],x[1],x[2],22)
                ssh.Init()
                ref = ssh.GetCPUPercentage()
                if len(ref)!=0:
                    print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format(x[0], ref["us"], ref["sys"], ref["idea"]))
    
    def load_avg(group):
        with open("config.json" , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            ptr = config_load.get(group)
            print("-" * 120)
            print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format("IP地址", "一分钟负载", "五分钟负载", "十五分钟负载"))
            print("-" * 120)
    
            for x in ptr:
                ssh = MySSH(x[0],x[1],x[2],22)
                ssh.Init()
                ref = ssh.GetLoadAVG()
                if len(ref)!=0:
                    print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format(x[0], ref["1avg"], ref["5avg"], ref["15avg"]))
    
    def checkproc(group,proc):
        with open("config.json" , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            ptr = config_load.get(group)
            print("-" * 120)
            print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format("IP地址", "PID号","CPU占用率", "内存占用率"))
            print("-" * 120)
    
            for x in ptr:
                ssh = MySSH(x[0],x[1],x[2],22)
                ssh.Init()
                ref = ssh.CheckProcessName(proc)
                if len(ref):
                    print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format(x[0], ref["PID"], ref["CPU"], ref["Mem"]))
                else:
                    print("{0:15} \t {1:7} \t {2:7} \t {3:5} \t".format(x[0], 0, 0, 0))
    
    def put_group(group,src,dst):
        with open("config.json" , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            ptr = config_load.get(group)
            print("-" * 120)
            print("{0:15} \t {1:7} \t {2:7} \t ".format("IP地址", "源文件","传输到"))
            print("-" * 120)
    
            for x in ptr:
                ssh = MySSH(x[0],x[1],x[2],22)
                ssh.Init()
                ref = ssh.PutLocalFile(src,dst)
                if ref:
                    print("{0:15} \t {1:7} \t {2:7} \t ".format(x[0], src,dst))
    
    if __name__ == '__main__':
        while True:
            try:
                cmd = str(input("[LyShark Shell] # ")).split()
                cmd_len = len(cmd)
                if (cmd == ""):
                    continue
                elif (cmd[0] == "exit"):
                    exit(1)
    
                # ping --group=aix
                elif (cmd[0] == "ping"):
                    if (cmd_len - 1 >= 1):
                        arg = cmd[1].split("=")[1]
                        ping(arg)
    
                # run --group=aix --cmd=ls
                elif (cmd[0] == "run"):
                    if (cmd_len - 1 >= 2):
                        arg1 = cmd[1].split("=")[1]
                        arg2 = cmd[2].split("=")[1]
                        run(arg1,arg2)
    
                # memory --group=aix
                elif (cmd[0] =="memory"):
                    if (cmd_len - 1 >= 1):
                        arg1 = cmd[1].split("=")[1]
                        memory(arg1)
    
                # disk --group=aix
                elif (cmd[0] =="disk"):
                    if (cmd_len - 1 >= 1):
                        arg1 = cmd[1].split("=")[1]
                        disk(arg1)
    
                # cpu --group=aix
                elif (cmd[0] =="cpu"):
                    if (cmd_len - 1 >= 1):
                        arg1 = cmd[1].split("=")[1]
                        cpu(arg1)
    
                # load --group=aix
                elif (cmd[0] =="load"):
                    if (cmd_len - 1 >= 1):
                        arg1 = cmd[1].split("=")[1]
                        load_avg(arg1)
    
                # checkproc --group=aix --process=bash
                elif (cmd[0] =="checkproc"):
                    if (cmd_len - 1 >= 1):
                        arg1 = cmd[1].split("=")[1]
                        arg2 = cmd[2].split("=")[1]
                        checkproc(arg1,arg2)
    
                # put_group --group=aix --src=./aaa.txt --dst=/tmp/aaa.txt
                elif (cmd[0] =="put_group"):
                    if (cmd_len - 1 >= 3):
                        arg1 = cmd[1].split("=")[1]
                        arg2 = cmd[2].split("=")[1]
                        arg3 = cmd[3].split("=")[1]
                        put_group(arg1,arg2,arg3)
                else:
                    print("[-] error version 1.0")
            except Exception:
                continue
    

    解析文件config.json配置如下所示,每个组中包括一定数量的机器。

    {
      "aix":
      [
        ["127.0.0.1","root","1233"],
        ["127.0.0.1","root","123456"]
    
      ],
      "suse":
      [
        ["127.0.0.1","root","123123123"]
      ],
    }
    

    程序运行后会进入交互Shell环境,我们可以根据需要执行不同的key获取数据。

    此外脚本还支持如下参数.

    • 运行命令: run --group=aix --cmd=ls
    • 内存检查: memory --group=aix
    • 磁盘检查: disk --group=aix
    • CPU检查: cpu --group=aix
    • 负载检查: load --group=aix
    • 进程检查: checkproc --group=aix --process=bash
    • 文件上传: put_group --group=aix --src=./aaa.txt --dst=/tmp/aaa.txt

    剧本执行器,这部分内容为扩展部分,我们定义两个函数,函数DisplayAllRule用来获取特定目录下的特定剧本,而RunRule函数则用于解析这个剧本并执行剧本中的命令集合。

    import MySSH
    import os,json,sys
    
    # 获取特定目录下所有的剧本
    def DisplayAllRule():
        print("{0:15} \t {1:10} \t {2:10} \t {3:15} \t {4:5} \t {5:30}".
              format("名称","应用平台","端口","主机组","命令条数","描述信息"))
    
        for switch in all_files:
            # 首先判断文件结尾是否为Json
            if( switch.endswith(".json") == True):
                all_switch_dir = rootdir + switch
                try:
                    # 判断文件内部是否符合JSON规范
                    with open(all_switch_dir , "r" ,encoding="utf-8") as read_file:
                        # 判断是否存在指定字段来识别规范
                        load = json.loads(read_file.read())
                        if load.get("framework") != None and load.get("task_sequence") != None:
                            print("{0:15} \t {1:10} \t {2:10} \t {3:15} \t {4:5} \t\t {5:30}".
                                  format(switch,load.get("framework"),load.get("default_port"),load.get("Group"),len(load.get("task_sequence")),load.get("describe")))
                except ValueError:
                    pass
    
    # 执行命令行
    def RunRule(rule_name):
        # 先打开配置恩建并读取到数据
        with open(config_dir , "r" ,encoding="utf-8") as read_config_ptr:
            config_load = json.loads(read_config_ptr.read())
            # 接着读取选中剧本
            with open(rule_dir,"r",encoding="utf-8") as read_rule_ptr:
                rule_load = json.loads(read_rule_ptr.read())
                # 先找到组名称,并以组名称查询组内主机数
                ref = config_load.get(rule_load.get("Group"))
                if ref != None:
                    # 加载剧本中的任务命令
                    task_sequence = rule_load.get("task_sequence")
    
                    # 循环执行针对组内主机
                    for addr in ref:
                        print("-" * 130 , "\n针对地址执行: {}\n".format(addr[0]),"-" * 130)
                        # 每个主机需要执行的命令
                        for cmd in task_sequence:
                            ssh = MySSH.MySSH(addr[0],addr[1],addr[2],int(rule_load.get("default_port")))
                            ssh.Init()
                            if cmd[0] == "PUT" and len(cmd) >= 3:
                                if ssh.PutLocalFile(cmd[1],cmd[2]):
                                    print("命令序列: {0} {1}".format("PUT",cmd[2]))
                                else:
                                    break
                            else:
                                ret = ssh.BatchCMD_NotRef(cmd[0])
                                print("命令序列: {0}".format(cmd[0]))
                else:
                    print("[-] 主机组不存在,无法继续执行.")
                    exit(0)
    
    if __name__ == "__main__":
        arg = sys.argv
        if arg[1] == "display":
            DisplayAllRule()
        elif arg[1] == "run":
            RunRule(arg[2])
    

    文件规划put_file目录用于存放需要上传的文件,rule目录用来存放执行剧本内容,我们先来看一个编译安装Apache服务器的剧本写法。

    {
      "framework": "Linux",
      "default_port": "22",
      "describe": "编译安装Apache组件",
      "Group": "MyWebServer",
      "task_sequence":
      [
        ["iptables -F"],
        ["setenforce 0"],
        ["yum -y install gcc make pcre-devel openssl-devel expat-devel bzip2"],
    
        ["PUT","./put_file/httpd-2.4.46.tar.gz","/tmp/apache.tar.gz"],
        ["PUT","./put_file/apr-1.7.0.tar.bz2","/tmp/apr-1.7.0.tar.bz2"],
        ["PUT","./put_file/apr-util-1.6.1.tar.bz2","/tmp/apr-util-1.6.1.tar.bz2"],
    
        ["tar -xzf /tmp/apache.tar.gz -C /tmp/"],
        ["tar -xf /tmp/apr-1.7.0.tar.bz2 -C /tmp/"],
        ["tar -xf /tmp/apr-util-1.6.1.tar.bz2 -C /tmp/"],
    
        ["mv /tmp/apr-util-1.6.1 /tmp/httpd-2.4.46/srclib/apr-util"],
        ["mv /tmp/apr-1.7.0 /tmp/httpd-2.4.46/srclib/apr"],
    
        ["/tmp/httpd-2.4.46/configure --prefix=/tmp/httpd --with-zlib -with-included-apr"],
        ["make && make install"],
    
        ["echo 'hello lyshark' > /tmp/httpd/htdocs/index.html"],
        ["/tmp/httpd/bin/httpd"]
      ]
    }
    

    如上剧本中的Group字段则是需要执行编译安装的所属组,该组内存放执行地址,来看一下组的规划。

    {
      "MyWebServer":
        [
          ["192.168.191.4","root","1233"],
          ["192.168.191.5","root","1233"],
          ["192.168.191.6","root","1233"]
        ]
    }
    

    我们首先可以执行main.py display命令,获取当前设备中的所有剧本信息。

    在需要执行时输入main.py run test.json尾部加上剧本名字即可。

  • 相关阅读:
    Shiro自定义密码匹配认证
    logback 发送邮件和自定义发送邮件;java类发送邮件
    webVR全景图多种方案实现(pannellum,aframe,Krpano,three,jquery-vrview)
    前端接受后端文件流并下载的几种方法
    回流(reflow)与重绘(repaint)
    JS数组去重的几种常见方法
    React 生命周期
    浅谈React工作原理
    如何在Vue项目中使用vw实现移动端适配
    移动端web整理 移动端问题总结,移动web遇到的那些坑
  • 原文地址:https://www.cnblogs.com/LyShark/p/15539500.html
Copyright © 2020-2023  润新知