• 主机管理程序



    一、作业需求:

    1, 运行程序列出主机组或者主机列表

    2,选择指定主机或主机组

    3,选择主机或主机组传送文件(上传/下载)

    4,充分使用多线程或多进程

    5,不同主机的用户名,密码,端口可以不同

    6,可向主机或主机组批量发布命令

    7,可一次性执行多条操作命令

    二、

    一、作业需求:
    1, 运行程序列出主机组或者主机列表(已完成)
    2,选择指定主机或主机组(已完成)
    3,选择主机或主机组传送文件(上传/下载)(已完成)
    4,充分使用多线程或多进程(已完成)
    5,不同主机的用户名,密码,端口可以不同(已完成)
    6,可向主机或主机组批量发布命令(已完成)
    7,可一次性执行多条操作命令(已完成)
    二、博客地址:http://www.cnblogs.com/catepython/p/8872274.html
    三、运行环境
    操作系统:Win10
    Python:3.6.4rcl
    Pycharm:2017.3.4
    四、功能实现
    1)实现所有基本需求
    2)充分利用了面向对象式编程
    五、测试
    1)文件名为空判断
    2)用户信息判断
    3)指令格式化判断
    4)上传/下载到指定路径判断
    5)文件名/用户目录有效判断
    六、备注
    readme

    三、流程图

    四、目录架构

    五、核心代码

     bin目录--程序开始

    #-*-coding:utf-8 -*-
    # Author: D.Gray
    from core import main
    start = main.MyFabric()
    start.run()
    start

    conf目录

    #-*-coding:utf-8 -*-
    # Author: D.Gray
    import os
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    #print(BASE_DIR)
    
    HOST_NAME_PATH = os.path.join(BASE_DIR,'db')
    #print(HOST_NAME_PATH)
    
    HOME_PATH = os.path.join(BASE_DIR,'home')
    setting

    core目录

    #-*-coding:utf-8 -*-
    # Author: D.Gray
    import os,sys,paramiko,threading,time,json
    from conf import setting
    import re
    class MyFabric(object):
    def __init__(self):
    self.run = self.run()
    def run(self):
    '''
    主界面运行函数
    :return:
    '''
    text = """
    欢迎来到Fabric主机管理界面
    1.创建主机
    2.删除主机
    3.自动激活所有主机
    4.开始远程操控
    5.退出程序
    """
    while True:
    print(text)
    choose = input("请输入您的选择>>>:").strip()
    #print(type(choose))
    self.dic = {
    '1':self.new_host, #创建主机模块
    '2':self.delect_host, #删除主机模块
    '3':self.auto_host, #激活主机模块
    '4':self.action_host, #控制主机模块
    '5':self.exit
    }
    if choose in self.dic:
    self.dic[choose]()
    else:
    print("请输入有效操作")
    def new_host(self):
    '''
    创建主机模块函数
    :return:
    '''
    #print('in the new_host')
    db_path = setting.HOST_NAME_PATH
    while True:
    name = input('请输入登录名称(输入n=返回上级)>>>:').strip()
    name_path = os.path.join(db_path,'%s.json'%(name))
    #print(name_path)
    if os.path.exists(name_path):
    print('登录名称已存在')
    continue
    if name == 'n':
    return
    hostname = input('请输入主机名(输入n=返回上级)>>>:').strip()
    if hostname == 'n':
    return
    port = input('请输入端口号(输入n=返回上级)>>>:').strip()
    if port.isdigit():
    port = int(port)
    else:
    print('端口号必须是整数')
    return
    if port == 'n':
    return
    username = input('请输入用户名(输入n=返回上级)>>>:').strip()
    if username == 'n':
    return
    password = input('请输入密码(输入n=返回上级)>>>:').strip()
    if password == 'n':
    return
    newhost_dic = {
    "name":name, #用户文件名(主机链接名称)
    "hostname":hostname,
    "username":username,
    "port":port,
    "password":password,
    "status": 0, #0---未激活,1---已激活,2--激活失败
    
    }
    mesag = '''33[33;1m
    请确认录入信息:
    %s:
    友情提示:请务必确保信息填写无误否则将无法正常进行管理登录操作!!!
    33[0m'''%newhost_dic
    print(mesag)
    choose = input("开人确认录入信息(y/n)?:")
    if choose == 'n':
    print('信息确认失败将重新录入:')
    return
    elif choose == 'y':
    if os.path.isdir(name_path) == False: #判断用户文件是否已存在
    with open(name_path,'w') as fw:
    json.dump(newhost_dic,fw,indent=4) #使用json.dump()函数将用户信息格式化写入
    print('33[32;1m信息载入完成33[0m')
    break
    else:
    print('已存在改文件')
    else:
    print('输入有误请重新输入')
    def delect_host(self):
    '''
    删除主机模块函数
    :return:
    '''
    #print('in the delect_host')
    host_dic = self.add_host() #接收add_host()函数 {文件名:{用户字典信息}} 格式的返回值
    host_list = []
    print('33[32;1m当前已存在主机名列表如下:33[0m')
    for index,values in enumerate(host_dic.values()): #遍历用户字典信息
    host_list.append(values['hostname'])
    print('%s-主机名:%s' % (index + 1, values['hostname']))
    if len(host_list) != 0:
    choose = input("请输入你想删除的主机索引(输入n=返回上级):")
    if choose =='n':
    print('取消删除主机名')
    return
    if choose.isdigit():
    choose = int(choose)
    if len(host_list) != 0:
    if choose <= len(host_list):
    # host_name(文件名称)
    # list(host_dic.keys())[choose-1](用户输入索引对应的主机名,也就是key)
    host_name = list(host_dic.keys())[choose-1]
    db_path = os.path.join(setting.HOST_NAME_PATH, host_name)
    os.remove(db_path)
    print('删除成功')
    else:
    print('33[31;1m输入超出索引范围33[0m')
    else:
    print('33[31;1m当前主机索引不能在删除33[0m')
    else:
    print('33[31;1m请输入有效索引33[0m')
    else:
    print('33[31;1m当前已存在主机名列表为空请先创建主机33[0m')
    def add_host(self):
    '''
    获取db文件夹中json文件中的主机名
    :return:将已获取到的 {文件名:{用户字典信息}} 格式做为返回值
    '''
    names_list = [] #定义一个文件名列表
    dic_list = [] #定义一个文件字典列表
    db_dic = {} #定义一个db文件内容字典
    db_path = setting.HOST_NAME_PATH
    ol = os.listdir(db_path)
    for i in ol:
    if i.endswith('.json'): #只获取后缀名为.json文件的信息
    json_path = os.path.join(db_path,i)
    with open(json_path,'r') as f:
    fd = json.load(f)
    dic_list.append(fd)
    names_list.append(i)
    db_dic = dict(zip(names_list,dic_list))
    return db_dic
    def auto_host(self):
    '''
    激活所有主机模块(尝试主机连接)
    :return:
    '''
    #print('in the auto_host')
    text = """33[32;1m
    警告!程序准备开启多线程模式激活主机,请确保:
    1,远程服务器处于开启状态
    2,DNS或本地hosts映射能够解析远程服务器主机名
    33[0m"""
    while True:
    print(text)
    host_dic = self.add_host()
    host_list = []
    dic_list = []
    for index,values in enumerate(host_dic.values()):
    host_list.append(values['hostname'])
    dic_list.append(values)
    print('当前已存在主机名列表如下:')
    print('%s-主机名:%s' % (index + 1,values['hostname']))
    if len(host_list) != 0:
    choose = input("33[33;1m是否开始确认激活主机(y/n)?:33[0m")
    if choose == 'n':
    print('33[31;1m已取消激活33[0m')
    return
    elif choose == 'y':
    for item in dic_list:
    #print(item,dic_list)
    print('33[38;0m程序开始激活主机请稍后...33[0m')
    time.sleep(1)
    dic = item
    t = threading.Thread(target=self.auto_action,args=(dic,)) #调用激活执行模块
     t.setDaemon(True)
    t.start()
    while threading.active_count() != 1:
    pass
    print('当前活跃线程个数:',threading.activeCount())
    break
    else:
    print('33[31;1m输入有误请重新输入33[0m')
    continue
    else:
    print('33[31;1m当前已激活主机为空请先创建主机33[0m')
    return
    def auto_action(self,dic):
    '''
    激活执行模块函数
    :param dic:
    :return:
    '''
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
    ssh.connect(hostname=dic['hostname'],port=dic['port'],username=dic['username'],password=dic['password'])
    except Exception as e:
    print('33[31;1m主机: %s 连接尝试失败:%s33[0m'%(dic['username'],e))
    dic['status'] = 2
    self.update_dic(dic)
    else:
    stdin, stdou, stdeer = ssh.exec_command('who')
    result = stdou.read()
    print('33[32;1m主机: %s 连接尝试成功:33[0m
    %s'%(dic['username'],result.decode()))
    dic['status'] = 1
    self.update_dic(dic) #通过json.dump方法修改json文件中某一参数
    finally:
    ssh.close()
    def update_dic(self,dic):
    '''
    更改主机状态函数
    :param dic:
    :return:
    '''
    db_path = os.path.join(setting.HOST_NAME_PATH,'%s.json'%(dic['name']))
    with open(db_path,'w') as f:
    json.dump(dic,f,indent=4) #通过json.dump方法修改json文件中某一参数
    return True
    def action_host(self):
    '''
    从已激活主机中选择相应的主机来进行操控
    1、遍历出已激活主机列表
    2、从激活主机列表中选择相应的主机进行操控(可多选)
    3、将选择操控的主机添加至choose_lsit列表中并传参给action()函数
    :return:
    '''
    print('in the action_host')
    auto_dic = self.add_host()
    auto_list = [] #已激活主机列表
    choose_list = [] # 用户选择操控主机列表
    for info in auto_dic.values():
    if info['status'] == 1:
    auto_list.append(info)
    if len(auto_list) != 0:
    while True:
    for index,values in enumerate(auto_list):
    print('%s-主机名:%s 已激活'%(index+1,values['hostname']))
    if len(auto_list) != 0:
    choose = input("33[38;1m请输入你想控制的主机索引(可多选,输入n=返回上级):33[0m").strip()
    if choose == 'n':
    print('33[31;1m取消控制主机33[0m')
    return
    if choose.isdigit(): #限制索引只能是数字
    chooses = list(set(choose)) #去重多选
    for index in chooses:
    index = int(index)
    if index <= len(auto_list) and index !=0: #限制输入的索引在有效范围内
    choose_list.append(auto_list[index-1])
    else:
    print("33[31;1m有一个索引超出范围33[0m")
    choose_list.clear()
    return
    else:
    print('33[31;1m请输入有效索引33[0m')
    return
    else:
    print('33[31;1m当前已存在主机名列表为空请先激活主机33[0m')
    self.action(choose_list)
    return
    else:
    print('33[31;1m当前已激活主机为空请先创建主机33[0m')
    return
    def action(self,choose_list):
    '''
    1、接收action_host()函数传来的 已操控主机列表([{用户1字典信息},{用户2字典信息}])格式
    2、遍历用户字典信息
    3、判断用户选择操作情况, 如put---进入put上传文件函数、get---进入get下载文件函数、其他进入cmd命令行操作函数
    :param choose_list:
    :return:
    '''
    #print('in the action:',choose_list)
    mesg = '''33[33;1m
    help帮助提示:
    1.程序的Home目录是本地文件目录
    2,输入put向远程主机上传文件
    3,输入get向远程主机下载文件
    4,输入其他直接向远程主机发布命令
    '''
    while True:
    print(mesg)
    if len(choose_list) != 0:
    print('33[32;1m您正在操控%s台主机,如下:33[0m'%(len(choose_list)))
    for index,info in enumerate(choose_list):
    print('%s-主机名:%s'% (index+1, info['hostname']))
    command = input("33[38;1m请输入你想执行的命令(输入n=返回上级,输入任意键进入cmd模式)>>:33[0m")
    dic = info
    if command == 'n':
    return
    if hasattr(self,command):
    getattrs = getattr(self,command)
    getattrs(dic)
    else:
    print('准备向远程主机发布命令...请稍后')
    t = threading.Thread(target=self.execute_command,args=(dic,))
    t.setDaemon(True)
    t.start()
    while threading.active_count() != 1:
    pass
    print('当前活跃线程个数:', threading.activeCount())
    break
    def put(self,dic):
    '''
    上传文件函数
    1、判断home目录中是否存在用户文件夹
    2、输入需上传的文件名
    3、输入所需上传到服务器的地址路径
    4、调用put_action()函数开始上传文件
    :param dic:
    :return:
    '''
    print('准备上传文件!!!')
    home_path = os.path.join(setting.HOME_PATH,dic['name'])
    while True:
    if os.path.exists(home_path):
    filename = input('33[37;1m请输入需上传文件名(例:xxx.txt)输入n返回上级菜单>>>:33[0m')
    if filename == 'n':
    print('33[31;1m取消上传文件33[0m')
    return
    file_path = os.path.join(home_path,filename)
    if os.path.isfile(file_path):
    remote = input("33[37;1m你想将文件保存到远程服务器路径(例如:/etc/)>>>:33[0m")
    remote_path = os.path.join('%s/'%remote,filename)
    t = threading.Thread(target=self.put_action,args=(dic,file_path,remote_path,))
    t.setDaemon(True)
    print('程序准备开始上传文件!!!')
    time.sleep(1)
    t.start()
    while threading.activeCount() != 1:
    pass
    return
    # print('当前活跃线程个数:', threading.activeCount())
    else:
    print('33[31;1m文件没有找到,请重新输入!33[0m')
    continue
    else:
    print('33[31;1m未找到指定用户目录33[0m')
    time.sleep(1)
    print('33[31;1m正在创建请稍后...33[0m')
    time.sleep(1)
    os.mkdir(home_path)
    print('33[32;1m用户目录创建成功!!!33[0m')
    return
    def get(self,dic):
    '''
    下载文件
    1、判断home目录中是否存在用户文件夹
    2、输入服务端地址路径
    3、输入下载的文件名
    4、调用get_action()函数开始下载文件
    :param dic:接收action函数传来的用户字典信息
    :return:
    '''
    print('准备下载文件!!!')
    home_path = os.path.join(setting.HOME_PATH, dic['name']) #用户目录路径
    if os.path.exists(home_path):
    remote = input("33[37;1m请输入想要下载的远程服务器文件绝对路径(例如:/etc/hosts/):33[0m")
    remote_file = input("33[37;1m请输入想要下载的远程服务器文件名(例如:xxx.txt):33[0m")
    remote_path = os.path.join('%s/'%remote,remote_file) #拼接服务端路径
    t = threading.Thread(target=self.get_action,args=(dic,home_path,remote_path,remote_file,))
    t.setDaemon(True)
    t.start()
    while threading.activeCount() != 1:
    pass
    return
    else:
    print('33[31;1m未找到指定用户目录33[0m')
    time.sleep(1)
    print('33[31;1m正在创建请稍后...33[0m')
    time.sleep(1)
    os.mkdir(home_path)
    print('33[32;1m用户目录创建成功!!!33[0m')
    return
    def put_action(self,*args):
    '''
    上传文件执行函数
    :param args:
    :return:
    '''
    #print('in the put_action:',*args)
    dic = args[0] #主机用户字典信息
    file_path = args[1] #本地用户目录路径
    remote_path = args[2] #服务端路径
    transport = paramiko.Transport((dic['hostname'], int(dic['port'])))
    try:
    transport.connect(username=dic['username'],password=dic['password'])
    sftp = paramiko.SFTPClient.from_transport(transport)
    sftp.put(file_path,remote_path)
    except Exception as e:
    print('33[31;1m主机名:[%s]文件上传失败...失败原因:
    %s33[0m'%(dic['hostname'],e))
    else:
    print('33[32;1m主机名:[%s]文件上传成功33[0m' % (dic['hostname']))
    finally:
    transport.close()
    def get_action(self,*args):
    '''
    下载文件执行函数
    :param args:
    :return:
    '''
    #print('in the get_action:',*args)
    dic = args[0] #主机信息字典
    home_path = args[1] #本地目录路径
    remote_path = args[2] #服务器路径
    remote_file = args[3] #从服务器下载的文件名
    file_path = os.path.join(home_path,remote_file) #下载倒本地目录路径
    transport = paramiko.Transport((dic['hostname'],int(dic['port'])))
    try:
    transport.connect(username=dic['username'],password=dic['password'])
    sftp = paramiko.SFTPClient.from_transport(transport)
    sftp.get(remote_path,file_path)
    except Exception as e:
    print('33[31;1m主机名:[%s]文件下载失败...失败原因:
    %s33[0m' % (dic['hostname'], e))
    else:
    print('33[32;1m主机名:[%s]文件下载成功33[0m' % (dic['hostname']))
    finally:
    transport.close()
    def execute_command(self,dic):
    '''
    cmd模式
    :param dic:
    :return:
    '''
    #print('in the execute_command:%s '% (dic))
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy)
    try:
    ssh.connect(hostname=dic['hostname'],port=dic['port'],username=dic['username'],password=dic['password'])
    except Exception as e:
    print('33[31;1m主机: %s 连接尝试失败:%s33[0m' % (dic['hostname'], e))
    else:
    while True:
    command = input("33[38;1m请输入你想执行的命令(输入n=返回上级)>>:33[0m")
    if command == 'n':
    return
    else:
    stdin, stdou, stdeer = ssh.exec_command(command)
    erro = stdeer.read()
    output =stdou.read()
    if len(erro) !=0:
    print("33[31;1m主机:%s 执行%s命令时出错:%s33[0m"%(dic['hostname'],command,(erro.decode())))
    #return False
    else:
    if len(output.decode()) == 0:
    print('该命令无返回结果')
    else:
    print("33[32;1m主机:%s 执行[%s]命令结果如下:33[0m
    %s"
    % (dic['hostname'], command, (output.decode())))
    finally:
    ssh.close()
    def exit(self):
    #print('in the exit')
    exit('程序退出')
    main

    db目录

    {
    "name": "admin_kyo",
    "hostname": "192.168.111.128",
    "username": "admin_kyo",
    "port": 22,
    "password": "admin1988",
    "status": 1
    }
    student_view
  • 相关阅读:
    Code First 迁移
    使用C#创建Windows服务 并发布Windows 服务
    线程(Thread,ThreadPool)、Task、Parallel
    用《捕鱼达人》去理解C#中的多线程
    Visual Studio提示“无法启动IIS Express Web服务器”的解决方法 调试闪退
    防cc攻击策略
    多线程和异步的异同和使用场景
    JQuery Checkbox 获取多选值 Checkbox选中个数
    C# 说说lock到底锁谁?(1)
    C# 说说lock到底锁谁?(2)
  • 原文地址:https://www.cnblogs.com/gaodi2345/p/11412822.html
Copyright © 2020-2023  润新知