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