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 True
    else:
        return False
def check_group(group):
    for gc in data:
        if group in gc.keys():
            return True
    else:
        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()
        #  判断是否为IP
        if 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)
                            break
                else:
                    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_gg
                            count = i
                            ip = ip_data
            if 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)) # 去除重复IP
        return ip_list
    elif 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_list
    elif 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)) # 去除重复的IP
        return ip_list

    else:
        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()
        #  判断是否为IP
        if 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

 

posted @ 2016-06-19 13:55  水·域  阅读(370)  评论(0编辑  收藏  举报