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],"已连接"))
            else:
                print("{0:15} \t {1:6} \t {2:5}".format(x[0],"未连接"))
        print("\n")

def run(group,command):
    with open("config.json",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],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",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],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",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],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","用户态","内核态","空闲率(百分比)"))
        print("-" * 120)

        for x in ptr:
            ssh = MySSH(x[0],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","一分钟负载","五分钟负载","十五分钟负载"))
        print("-" * 120)

        for x in ptr:
            ssh = MySSH(x[0],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","PID号","CPU占用率","内存占用率"))
        print("-" * 120)

        for x in ptr:
            ssh = MySSH(x[0],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))

def put_group(group,src,dst):
    with open("config.json",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],22)
            ssh.Init()
            ref = ssh.PutLocalFile(src,dst)
            if ref:
                print("{0:15} \t {1:7} \t {2:7} \t ".format(x[0],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","123456"]

  ],"suse":
  [
    ["127.0.0.1","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,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,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,encoding="utf-8") as read_config_ptr:
        config_load = json.loads(read_config_ptr.read())
        # 接着读取选中剧本
        with open(rule_dir,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_file/apr-1.7.0.tar.bz2","/tmp/apr-1.7.0.tar.bz2"],"./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",["192.168.191.5",["192.168.191.6","1233"]
    ]
}

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

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

原文地址:https://www.cnblogs.com/LyShark

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Python中的函数(二) 在上一篇文章中提到了Python中函数的定义和使用,在这篇文章里我们来讨论下关于函数的一些更深的话题。在学习C语言函数的时候,遇到的问题主要有形参实参的区别、参数的传递和改变、变量的作用域。同样在Python中,关于对函数的理解和使用也存在这些问题。下面来逐一讲解。一.函
Python中的字符串 可能大多数人在学习C语言的时候,最先接触的数据类型就是字符串,因为大多教程都是以"Hello world"这个程序作为入门程序,这个程序中要打印的"Hello world"就是字符串。如果你做过自然语言处理方面的研究,并且用Python
Python 面向对象编程(一) 虽然Python是解释性语言,但是它是面向对象的,能够进行对象编程。下面就来了解一下如何在Python中进行对象编程。一.如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法。 类是对现实世界中一些事物的封装,
Python面向对象编程(二) 在前面一篇文章中谈到了类的基本定义和使用方法,这只体现了面向对象编程的三大特点之一:封装。下面就来了解一下另外两大特征:继承和多态。 在Python中,如果需要的话,可以让一个类去继承一个类,被继承的类称为父类或者超类、也可以称作基类,继承的类称为子类。并且Pytho
Python中的函数(一) 接触过C语言的朋友对函数这个词肯定非常熟悉,无论在哪门编程语言当中,函数(当然在某些语言里称作方法,意义是相同的)都扮演着至关重要的角色。今天就来了解一下Python中的函数用法。一.函数的定义 在某些编程语言当中,函数声明和函数定义是区分开的(在这些编程语言当中函数声明
在windows下如何快速搭建web.py开发框架 用Python进行web开发的话有很多框架供选择,比如最出名的Django,tornado等,除了这些框架之外,有一个轻量级的框架使用起来也是非常方便和顺手,就是web.py。它由一名黑客所创建,但是不幸的是这位创建者于2013年自杀了。据说现在由
将Sublime Text 2搭建成一个好用的IDE 说起编辑器,可能大部分人要推荐的是Vim和Emacs,本人用过Vim,功能确实强大,但是不是很习惯,之前一直有朋友推荐SUblime Text 2这款编辑器,然后这段时间就试了一下,就深深地喜欢上这款编辑器了...
Python中的模块 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt这个函数,必须用语句"#include<math.h>"引入math.h这个头文件,否则是无法正常进行调用的。那么在Python中,如果要引用一些内置的函数,该怎么处理呢?在Python中
Python的基础语法 在对Python有了基础的认识之后,下面来了解一下Python的基础语法,看看它和C语言、java之间的基础语法差异。一.变量、表达式和语句 Python中的语句也称作命令,比如print "hello python"这就是一条语句。 表达式,顾名思义,是
Eclipse+PyDevʽjango+Mysql搭建Python web开发环境 Python的web框架有很多,目前主流的有Django、Tornado、Web.py等,最流行的要属Django了,也是被大家最看好的框架之一。下面就来讲讲如何搭建Django的开发环境。一.准备工作 需要下载的
在windows下安装配置Ulipad 今天推荐一款轻便的文本编辑器Ulipad,用来写一些小的Python脚本非常方便。 Ulipad下载地址: https://github.com/limodou/ulipad http://files.cnblogs.com/dolphin0520/u...
Python中的函数(三) 在前面两篇文章中已经探讨了函数的一些相关用法,下面一起来了解一下函数参数类型的问题。在C语言中,调用函数时必须依照函数定义时的参数个数以及类型来传递参数,否则将会发生错误,这个是严格进行规定的。然而在Python中函数参数定义和传递的方式相比而言就灵活多了。一.函数参数的
在Notepad++中搭配Python开发环境 Python在最近几年一度成为最流行的语言之一,不仅仅是因为它简洁明了,更在于它的功能之强大。它不仅能够完成一般脚本语言所能做的事情,还能很方便快捷地进行大规模的项目开发。在学习Python之前我们来看一下Python的历史由来,"Pytho
Python中的条件选择和循环语句 同C语言、Java一样,Python中也存在条件选择和循环语句,其风格和C语言、java的很类似,但是在写法和用法上还是有一些区别。今天就让我们一起来了解一下。一.条件选择语句 Python中条件选择语句的关键字为:if 、elif 、else这三个。其基本形式如
关于raw_input( )和sys.stdin.readline( )的区别 之前一直认为用raw_input( )和sys.stdin.readline( )来获取输入的效果完全相同,但是最近在写程序时有类似这样一段代码:import sysline = sys.stdin.readline()
初识Python 跟学习所有的编程语言一样,首先得了解这门语言的编程风格和最基础的语法。下面就让我们一起来了解一下Python的编程风格。1.逻辑行与物理行 在Python中有逻辑行和物理行这个概念,物理行是指在编辑器中实际看到的一行,逻辑行是指一条Python语句。在Python中提倡一个物理行只
当我们的代码是有访问网络相关的操作时,比如http请求或者访问远程数据库,经常可能会发生一些错误,有些错误可能重新去发送请求就会成功,本文分析常见可能需要重试的场景,并最后给出python代码实现。
1.经典迭代器 2.将Sentence中的__iter__改成生成器函数 改成生成器后用法不变,但更加简洁。 3.惰性实现 当列表比较大,占内存较大时,我们可以采用惰性实现,每次只读取一个元素到内存。 或者使用更简洁的生成器表达式 4.yield from itertools模块含有大量生成器函数可
本文介绍简单介绍socket的常用函数,并以python-kafka中的源码socketpair为例,来讲解python socket的运用
python实践中经常出现编码相关的异常,大多网上找资料而没有理解原理,导致一次次重复错误。本文对常用Unicode、UTF-8、GB2312编码的原理进行介绍,接着介绍了python字符类型unicode和str以及常见编解码错误UnicodeEncodeError和UnicodeDEcodeEr