通过封装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 displa
y命令,获取当前设备中的所有剧本信息。
在需要执行时输入main.py run test.json
尾部加上剧本名字即可。
原文地址:https://www.cnblogs.com/LyShark
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。