python 主机宝

需求:开发一个主机批量管理系统,要求按saltstack方式执行命令

 1 #!/usr/bin/env python3.5
 2 # -*- coding:utf8 -*-
 3 import os,sys,pickle,logging
 4 BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 5 sys.path.append(BASEDIR)
 6 from conf import setting
 7 from core import file_handler
 8 from core import db_handler
 9 from core import host_handler
10 """
11 ************************************
12 此为主机宝主运行程序
13 ************************************
14 """
15 logging.basicConfig(level=logging.INFO, filename=os.path.join(BASEDIR,'log/ssh.log'), filemode='a',
16                     format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
17 log = logging.getLogger(__name__)
18 def login():
19     count = 0
20     flage = False
21     while count < 3:
22         count += 1
23         user_input = input("请输入用户名:").strip()
24         pass_input = input("请输入密码:").strip()
25         db = db_handler.handler(setting.DATABASE,user_input)
26         if os.path.isfile(db):
27             f = open(db,"rb")
28             data = pickle.loads(f.read())
29             f.close()
30             if user_input == data["name"] and data["lock"] !=1:
31                 if pass_input == data["password"]:
32                     flage = True
33                     log.info("用户[%s]登陆成功!"%user_input)
34                     break
35                 else:
36                     print("用户名或密码错误!")
37                     if count > 2:
38                         with open(db,"wb") as f:
39                             data["lock"] = 1
40                             pickle.dump(data,f)
41                             log.info("用户[%s]被锁定!"%user_input)
42                             print("用户[%s]已被锁定!"%user_input)
43             else:
44                 print("用户[%s]已被锁定!"%user_input)
45                 exit()
46     if flage == True:
47         print("用户[%s]登陆成功!"%user_input)
48         men()
49     else:
50         exit()
51 def men():
52     print("欢迎进入主机宝管理系统!")
53     host_men = """
54                   1、显示主机与所属组
55                   2、增加组
56                   3、增加主机
57                   4、修改主机
58                   5、删除主机
59                   6、执行命令
60                   7、退出管理系统
61    """
62     host_dic ={
63         "1":{"option":"显示主机与所属组","action":file_handler.show},
64         "2":{"option":"增加组","action":file_handler.add_group},
65         "3":{"option":"增加主机","action":file_handler.add_host},
66         "4":{"option":"修改主机","action":file_handler.mod_host},
67         "5":{"option":"删除主机","action":file_handler.host_delete},
68         "6":{"option":"执行命令","action":host_handler.exciton},
69         "7":{"option":"退出管理系统","action":exit}
70     }
71     exit_flag =False
72     while not exit_flag:
73         print(host_men)
74         option = input("请按键选择:").strip()
75         if option in host_dic:
76             func = host_dic[option].get("action")
77             func()
78 
79 
80 def run():
81     login()
main
 1 #!/usr/bin/env python3.5
 2 # -*- coding:utf8 -*-
 3 import os,sys,re
 4 BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 5 sys.path.append(BASEDIR)
 6 import logging,importlib
 7 # 初始化日志格式及对象
 8 logging.basicConfig(level=logging.INFO, filename=os.path.join(BASEDIR,'log/ssh.log'), filemode='a',
 9                     format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
10 log = logging.getLogger(__name__)
11 # 调用执行模块
12 def module_excute(moudle_name,func_name,arg):
13     try:
14         # 导入要执行的模块
15         module = importlib.import_module("salt.salt_{}".format(moudle_name))
16         # 判断函数名是否包含在模块里
17         if hasattr(module,func_name):
18             func = getattr(module,func_name)
19             func(arg)
20             print("***" * 20)
21         else:
22             print("不存在")
23     except Exception as e :
24         log.info("input:{},error:{}".format(moudle_name,e))
25 def exciton():
26     usage = """
27     salt "*" cmd.run "excute_cmd1,excute_cmd2..."          :"所有主机执行命令"
28     salt -g "group" cmd.run "excute_cmd1,excute_cmd2..."   :"指定组执行命令"
29     salt -h "ip_host" cmd.run "excute_cmd1,excute_cmd2..." :"指定主机IP执行命令"
30     salt "*" file.put "filename"                           :"所有主机上传文件"
31     salt "*" file.get "filename"                           :"所有主机下载文件"
32     exit                                                   :"退出"
33      """
34     print("欢迎进入主机命令执行系统!")
35     user_cmd = input("请输入要执行的命令>>>:").strip()
36     if user_cmd.startswith("salt"):  # 判断是否以salt开始
37         user_cmd_list = user_cmd.split()  #以空格分割成列表
38         # 过滤掉特殊字符
39         user_arg_list = list(map(lambda x:re.sub(r'[\"\']',"",x),user_cmd_list))
40         # 匹配含点的模块名字
41         p = re.compile(r'[a-zA-Z_]+\.[a-zA-Z_]+')
42         flag =False
43         count = 0
44         for i in user_arg_list:
45             if p.match(i):
46                 flag = True
47                 count +=1
48                 moudle_func = i  # 获取模块名
49                 break   # 只匹配第一个含点的模块名
50         # 只有命令里含*。*格式时,继续
51         if flag and count == 1:
52             cmd_list = user_arg_list[user_arg_list.index(moudle_func)+1:]  # 获取原列表在此命令(*.*)之后的所有命令变成命令列表
53             obj_list = user_arg_list[user_arg_list.index("salt")+1:user_arg_list.index(moudle_func)]  # 获取以salt开头模块函数结尾之前的所有内空转到列表
54             arg = (obj_list,cmd_list) # 将操作对象列表和指令列表放到元组中
55             moudle_name = moudle_func.split(".")[0]  # 获取模块名
56             func_name = moudle_func.split(".")[1]  # 获取函数名
57             module_excute(moudle_name,func_name,arg)
58             exciton()
59         else:
60             print("命令输入错误!请按以下格式输入:")
61             print(usage)
62             exciton()
63     elif user_cmd =="exit":
64         exit()
65     else:
66         print("命令输入错误!请按以下格式输入:")
67         print(usage)
68         exciton()
host_handle
#!/usr/bin/env python3.5
# -*- coding:utf8 -*-
import os,sys,pickle,re,logging
BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASEDIR)
from conf import setting
from core import db_handler
from core import host_handler
db_path = db_handler.handler(setting.DATABASE,"host")
if os.path.exists(db_path):with open(db_path, "rb") as f:data = pickle.loads(f.read())
else:data =[]
# 初始化日志格式及对象
logging.basicConfig(level=logging.INFO, filename=os.path.join(BASEDIR,'log/ssh.log'), filemode='a',format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
log = logging.getLogger(__name__)
def check_ip(ip):for data_ip in data:for ip_data in data_ip:for iptest in data_ip[ip_data]:if ip in iptest["ip"]:return Trueelse:return False
def check_group(group):for gc in data:if group in gc.keys():return Trueelse:return False
def add_group():add_input = input("请输入要增加的组:").strip()list_data = []for y_data in data:for k in y_data:list_data.append(k)if add_input not in list_data:new_group = {"%s"%add_input:[]}data.append(new_group)with open(db_path,"wb") as fw:pickle.dump(data,fw)log.info("增加组%s成功!"%add_input)print("增加组%s成功!"%add_input)else:log.error("增加组%s失败!已存在该组!"%add_input)print("增加组%s失败!已存在该组!"%add_input)
def show():for y_data in data:for k in y_data:for i in y_data[k]:print("主机IP:[%s],所属组为:[%s]"%(i["ip"],k))
def add_host():"""增加主机:return:"""try:host_add = input("请输入主机IP:").strip()host_port = int(input("请输入端口号:"))host_user = input("请输入登陆主机用户名:").strip()host_pwd = input("请输入登陆主机密码:").strip()#  判断是否为IPif re.match(r"((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$",host_add):if  host_port != "" and len(host_user) != 0 and len(host_pwd)!= 0:host_group = input("请输入主机所属组:").strip()for g in data:if host_group  in g.keys():for g_data in data:if host_group in g_data.keys():g_data[host_group].append({"ip":"%s"%host_add,"port":"%s"%host_port,"username":"%s"%host_user,"password":"%s"%host_pwd})with open(db_path,"wb") as fw:pickle.dump(data,fw)log.info("增加主机[%s]成功!"%host_add)print("增加主机[%s]成功!"%host_add)breakelse:log.error("增加主机[%s]失败,组[%]不存在!"%(host_add,host_group))print("增加主机[%s]失败,组[%]不存在!!"%(host_add,host_group))return add_host()else:return add_host()else:log.error("你输入的不是IP地址:%s" %host_add)print("你输入的不是IP地址:%s" %host_add)except Exception as ex:log.error("增加主机异常%s"%ex)print("增加主机异常")
def mod_host():"""修改主机所属组:return:"""IP_modi = input("请输入要变更的IP:").strip()ip_check = check_ip(IP_modi)if ip_check:gg = input("请输入转入的组名称:").strip()gg_check = check_group(gg)if gg_check:# 获取该IP 原所属组名称for data_gg in data:for i_gg in data_gg:for i,ip_data in enumerate(data_gg[i_gg]):if IP_modi == ip_data["ip"]:g = i_ggcount = iip = ip_dataif gg == g:log.info("该IP主机:{},原已属于该组:{}".format(IP_modi,gg))print("该IP主机:{},原已属于该组:{}".format(IP_modi,gg))else:for x_data in data:for xi_gg in x_data:# 确定转入组相符if xi_gg == gg:x_data[xi_gg].append(ip)# 删除原来所属组IP主机elif xi_gg == g:x_data[xi_gg].remove(ip)with open(db_path,"wb") as fw:pickle.dump(data,fw)log.info("修改主机[%s]成功,新组名称为%s!"%(IP_modi,gg))print("修改主机[%s]成功,新组名称为%s!"%(IP_modi,gg))else:log.error("不存在此IP主机{}".format(IP_modi))print("不存在此IP主机{}".format(IP_modi))
def cmd_handle(arg):"""解析命令,并返回主机IP列表:param arg::return:"""if arg[0] == "*":ip_list = []for g in data:for gg in g:for ip in g[gg]:ip_list.append(ip["ip"])ip_list = list(set(ip_list)) # 去除重复IPreturn ip_listelif arg[0] == "-h":ip_list=[]ip_group = arg[1:]for data_ip in data:for ip in ip_group:for ip_data in data_ip:for iptest in data_ip[ip_data]:if ip in iptest["ip"]:ip_list.append(ip)ip_list =list(set(ip_list))return ip_listelif arg[0] == "-g":ip_list = []group_list =arg[1:]for group in group_list:for g in data:if group in g.keys():for ip in g[group]:ip_list.append(ip["ip"])ip_list = list(set(ip_list)) # 去除重复的IPreturn ip_listelse:ip_list =[]return ""
def ip_user(ip):"""获取主机连接账号信息:param ip::return:"""ip_info = []for data_ip in data:for ip_data in data_ip:for iptest in data_ip[ip_data]:if ip in iptest["ip"]:ip_info = [iptest["ip"],iptest["port"],iptest["username"],iptest["password"]]return ip_info
def host_delete():try:host_add = input("请要删除主机IP:").strip()#  判断是否为IPif re.match(r"((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$",host_add):flag = check_ip(host_add)if flag:for g in data:for g_data in g:for index,host in enumerate(g[g_data]):if host_add in host["ip"]:print(g[g_data][index])del g[g_data][index]with open(db_path,"wb") as fw:pickle.dump(data,fw)log.info("删除主机[%s]成功!"%host_add)print("删除主机[%s]成功!"%host_add)else:log.error("删除主机[%s]失败!"%host_add)print("删除主机[%s]失败!"%host_add)return add_host()else:log.error("你输入的不是IP地址:%s" %host_add)print("你输入的不是IP地址:%s" %host_add)except Exception as ex:log.error("删除主机异常%s"%ex)print("删除主机异常")
file_handle
 1 #! /usr/bin/env python3.5
 2 # -*- coding:utf-8 -*-
 3 import os,sys,logging,pickle,paramiko
 4 from multiprocessing import Pool
 5 from core import file_handler
 6 BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 7 sys.path.append(BASEDIR)
 8 # 初始化日志格式及对象
 9 logging.basicConfig(level=logging.INFO, filename=os.path.join(BASEDIR,'log/ssh.log'), filemode='a',
10                     format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
11 log = logging.getLogger(__name__)
12 def cmd_func(i,cmd):
13     ip_info = file_handler.ip_user(i)
14     if len(ip_info) != 0:
15         ip = ip_info[0]
16         port = int(ip_info[1])
17         username = ip_info[2]
18         passowrd = ip_info[3]
19         try:
20             # 创建SSH对象
21             ssh = paramiko.SSHClient()
22             # 允许连接不在know_hosts文件中的主机进行连接
23             ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
24             # 连接服务器
25             ssh.connect(hostname=ip,port=port,username=username,password=passowrd)
26             # 执行命令
27             resu = []
28             for excute_cmd in cmd:
29                 stdin, stdout, stderr = ssh.exec_command(excute_cmd)
30                 # 获取结果
31                 result= list(filter(lambda x:x is not None,[stdout.read(),stderr.read()]))[0]
32                 resu.append(result)
33             # 关闭连接
34             ssh.close()
35             log.info("主机:{},执行命令{}成功!".format(ip,cmd))
36             for x,result in enumerate(resu):                print("主机:{},执行命令:{},结果如下:\n\n{}".format(ip,cmd[x],result.decode()))
37         except Exception as e:
38             print("连接主机{}出错".format(ip))
39             log.error("连接主机{}出错:{}".format(ip,e))
40     else:
41         log.error("没有可用主机可以进行连接")
42         print("没有可用主机可以进行连接")
43 def run(arg):
44     "命令执行方法"
45     if len(arg) != 2:  # 如果arg 没有两个参数
46         log.info("参数出错,此处需要两个参数{}".format(arg))
47         print("参数出错,此处需要两个参数{}".format(arg))
48     else:
49         #  从元组里拆分出对象列表与指令列表
50         obj_list ,cmd_list =  arg
51         cmd = " ".join(cmd_list)  # 组合命令
52         cmd = cmd.split(",") # 以逗号分割重组命令
53         ip_list = file_handler.cmd_handle(obj_list)  # 获取所有的IP列表
54         if len(ip_list) >= 1:
55             pool = Pool(5)
56             for i in ip_list:
57                 # cmd_func(i,cmd)
58                 pool.apply_async(cmd_func,args=(i,cmd))
59             pool.close()
60             pool.join()
61         else:
62             log.info("你当前输入的IP地址不存在,请先增加!")
63             print("你当前输入的IP地址不存在,请先增加!")
64             file_handler.add_host()
salt_cmd
 1 #! /usr/bin/env python3.5
 2 # -*- coding:utf-8 -*-
 3 import os,sys,logging,pickle,paramiko
 4 BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 5 sys.path.append(BASEDIR)
 6 from multiprocessing import Pool
 7 from core import file_handler
 8 from conf import setting
 9 # 初始化日志格式及对象
10 logging.basicConfig(level=logging.INFO, filename=os.path.join(BASEDIR,'log/ssh.log'), filemode='a',
11                     format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
12 log = logging.getLogger(__name__)
13 def file(i,path_x,path_y,obj):
14     ip_info = file_handler.ip_user(i)
15     if len(ip_info) != 0:
16         ip = ip_info[0]
17         port = int(ip_info[1])
18         username = ip_info[2]
19         passowrd = ip_info[3]
20         try:
21             transport = paramiko.Transport((ip, port))
22             transport.connect(username=username, password=passowrd)
23         except paramiko.ssh_exception.AuthenticationException as e:
24             # 接收认证错误并返回给结果
25             log.error("主机:%s,用户名或密码错误,%s"%(ip,e))
26             print("主机:%s,用户名或密码错误"%ip)
27         except paramiko.ssh_exception.SSHException as e:
28             # 接收连接错误并返回给结果
29             log.error("主机:%s,连接失败:%s"%(ip,e))
30             print("主机:%s,连接失败"%ip)
31         else:
32             sftp = paramiko.SFTPClient.from_transport(transport)
33             try:
34                 if obj == "get":
35                     if os.path.isdir(os.path.dirname(path_y)):
36                         sftp.get(path_x,path_y)
37                     else:
38                         os.makedirs(os.path.dirname(path_y))
39                         sftp.get(path_x,path_y)
40                 elif obj == "put":
41                     sftp.put(path_x,path_y)
42             except Exception as e:
43                 log.error("主机:%s,操作失败:%s"%(ip,e))
44                 print("主机:%s,操作失败"%ip)
45             else:
46                 log.info("主机:%s,文件操作成功!"%ip)
47                 print("主机:%s,文件操作成功!"%ip)
48             transport.close()
49     else:
50         log.error("没有可用主机可以进行连接")
51 def get(arg):
52     "命令执行方法"
53     if len(arg) != 2:  # 如果arg 没有两个参数
54         log.info("参数出错,此处需要两个参数{}".format(arg))
55     else:
56         #  从元组里拆分出对象列表与指令列表
57         obj_list ,file_name =  arg
58         cmd = " ".join(file_name)
59         remote_path =os.path.join(setting.FILEPATH["remote_path"],cmd) # 组合远程主机目录
60         ip_list = file_handler.cmd_handle(obj_list)  # 获取所有的IP列表
61         if len(ip_list) >= 1:
62             pool = Pool(5)
63             for i in ip_list:
64                 local_path =os.path.join(setting.FILEPATH["loca_path"],i) #组合以IP命令的本地目录
65                 local_path = os.path.join(local_path,cmd)
66                 pool.apply_async(file,args=(i,remote_path,local_path,"get"))
67             pool.close()
68             pool.join()
69         else:
70             log.info("IP地址为空!可能是输入的IP不合法或没有增加进去")
71 
72 def put(arg):
73     "命令执行方法"
74     if len(arg) != 2:  # 如果arg 没有两个参数
75         log.info("参数出错,此处需要两个参数{}".format(arg))
76     else:
77         #  从元组里拆分出对象列表与指令列表
78         obj_list ,file_name =  arg
79         cmd = " ".join(file_name)
80         local_path =os.path.join(setting.FILEPATH["loca_path"],cmd) # 组合本地目录
81         if os.path.isfile(local_path):
82             remote_path =os.path.join(setting.FILEPATH["remote_path"],cmd) # 组合远程主机目录
83             ip_list = file_handler.cmd_handle(obj_list)  # 获取所有的IP列表
84             if len(ip_list) >= 1:
85                 pool = Pool(5)
86                 for i in ip_list:
87                     pool.apply_async(file,args=(i,local_path,remote_path,"put"))
88                 pool.close()
89                 pool.join()
90             else:
91                 log.error("IP地址为空!可能是输入的IP不合法或没有增加进去")
92         else:
93             log.error("文件%s不存在"%local_path)
salt_file

 

转载于:https://www.cnblogs.com/IPYQ/p/5597963.html


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部