热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

老男孩Day10作业:主机管理程序

一、作业需求:1,运行程序列出主机组或者主机列表2,选择指定主机或主机组3,选择主机或主机组传送文件(上传/下载)4,充分使用多线程或多进程5,不同主机的用户名,密码,端口可以不同6,可向主机或主机

一、作业需求:

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 = '''\033[33;1m
                                            请确认录入信息:\n%s:
                    友情提示:请务必确保信息填写无误否则将无法正常进行管理登录操作!!!
            \033[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('\033[32;1m信息载入完成\033[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('\033[32;1m当前已存在主机名列表如下:\033[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('\033[31;1m输入超出索引范围\033[0m')
                else:
                    print('\033[31;1m当前主机索引不能在删除\033[0m')
            else:
                print('\033[31;1m请输入有效索引\033[0m')
        else:
            print('\033[31;1m当前已存在主机名列表为空请先创建主机\033[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 = """\033[32;1m
                    警告!程序准备开启多线程模式激活主机,请确保:
                    1,远程服务器处于开启状态
                    2,DNS或本地hosts映射能够解析远程服务器主机名
            \033[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("\033[33;1m是否开始确认激活主机(y/n)?:\033[0m")
                if choose == 'n':
                    print('\033[31;1m已取消激活\033[0m')
                    return
                elif choose == 'y':
                    for item in dic_list:
                        #print(item,dic_list)
                        print('\033[38;0m程序开始激活主机请稍后...\033[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('\033[31;1m输入有误请重新输入\033[0m')
                    continue
            else:
                print('\033[31;1m当前已激活主机为空请先创建主机\033[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('\033[31;1m主机: %s 连接尝试失败:%s\033[0m'%(dic['username'],e))
            dic['status'] = 2
            self.update_dic(dic)
        else:
            stdin, stdou, stdeer = ssh.exec_command('who')
            result = stdou.read()
            print('\033[32;1m主机: %s 连接尝试成功:\033[0m\n%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("\033[38;1m请输入你想控制的主机索引(可多选,输入n=返回上级):\033[0m").strip()
                    if choose == 'n':
                        print('\033[31;1m取消控制主机\033[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("\033[31;1m有一个索引超出范围\033[0m")
                                choose_list.clear()
                                return
                    else:
                        print('\033[31;1m请输入有效索引\033[0m')
                        return
                else:
                    print('\033[31;1m当前已存在主机名列表为空请先激活主机\033[0m')

                self.action(choose_list)
                return
        else:
            print('\033[31;1m当前已激活主机为空请先创建主机\033[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 = '''\033[33;1m
                            help帮助提示:
                    1.程序的Home目录是本地文件目录
                    2,输入put向远程主机上传文件
                    3,输入get向远程主机下载文件
                    4,输入其他直接向远程主机发布命令
        '''
        while True:
            print(mesg)
            if len(choose_list) != 0:
                print('\033[32;1m您正在操控%s台主机,如下:\033[0m'%(len(choose_list)))
                for index,info in enumerate(choose_list):
                    print('%s-主机名:%s'% (index+1, info['hostname']))
                    command = input("\033[38;1m请输入你想执行的命令(输入n=返回上级,输入任意键进入cmd模式)>>:\033[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('\033[37;1m请输入需上传文件名(例:xxx.txt)输入n返回上级菜单>>>:\033[0m')
                if filename == 'n':
                    print('\033[31;1m取消上传文件\033[0m')
                    return
                file_path = os.path.join(home_path,filename)
                if os.path.isfile(file_path):
                    remote = input("\033[37;1m你想将文件保存到远程服务器路径(例如:/etc/)>>>:\033[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('\033[31;1m文件没有找到,请重新输入!\033[0m')
                    continue
            else:
                print('\033[31;1m未找到指定用户目录\033[0m')
                time.sleep(1)
                print('\033[31;1m正在创建请稍后...\033[0m')
                time.sleep(1)
                os.mkdir(home_path)
                print('\033[32;1m用户目录创建成功!!!\033[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("\033[37;1m请输入想要下载的远程服务器文件绝对路径(例如:/etc/hosts/):\033[0m")
            remote_file = input("\033[37;1m请输入想要下载的远程服务器文件名(例如:xxx.txt):\033[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('\033[31;1m未找到指定用户目录\033[0m')
            time.sleep(1)
            print('\033[31;1m正在创建请稍后...\033[0m')
            time.sleep(1)
            os.mkdir(home_path)
            print('\033[32;1m用户目录创建成功!!!\033[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('\033[31;1m主机名:[%s]文件上传失败...失败原因:\n%s\033[0m'%(dic['hostname'],e))
        else:
            print('\033[32;1m主机名:[%s]文件上传成功\033[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('\033[31;1m主机名:[%s]文件下载失败...失败原因:\n%s\033[0m' % (dic['hostname'], e))
        else:
            print('\033[32;1m主机名:[%s]文件下载成功\033[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('\033[31;1m主机: %s 连接尝试失败:%s\033[0m' % (dic['hostname'], e))
        else:
            while True:
                command = input("\033[38;1m请输入你想执行的命令(输入n=返回上级)>>:\033[0m")
                if command == 'n':
                    return
                else:
                    stdin, stdou, stdeer = ssh.exec_command(command)
                    erro = stdeer.read()
                    output =stdou.read()
                    if len(erro) !=0:
                        print("\033[31;1m主机:%s 执行%s命令时出错:%s\033[0m"%(dic['hostname'],command,(erro.decode())))
                        #return False
                    else:
                        if len(output.decode()) == 0:
                            print('该命令无返回结果')
                        else:
                            print("\033[32;1m主机:%s 执行[%s]命令结果如下:\033[0m\n%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
}
admin_kyo.json

 


推荐阅读
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 解决.net项目中未注册“microsoft.ACE.oledb.12.0”提供程序的方法
    在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报错“未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序”。本文提供了解决这个问题的方法,包括错误描述和代码示例。通过注册提供程序和修改连接字符串,可以成功读取excel文件信息。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • 本文介绍了如何在Azure应用服务实例上获取.NetCore 3.0+的支持。作者分享了自己在将代码升级为使用.NET Core 3.0时遇到的问题,并提供了解决方法。文章还介绍了在部署过程中使用Kudu构建的方法,并指出了可能出现的错误。此外,还介绍了开发者应用服务计划和免费产品应用服务计划在不同地区的运行情况。最后,文章指出了当前的.NET SDK不支持目标为.NET Core 3.0的问题,并提供了解决方案。 ... [详细]
  • python3 nmap函数简介及使用方法
    本文介绍了python3 nmap函数的简介及使用方法,python-nmap是一个使用nmap进行端口扫描的python库,它可以生成nmap扫描报告,并帮助系统管理员进行自动化扫描任务和生成报告。同时,它也支持nmap脚本输出。文章详细介绍了python-nmap的几个py文件的功能和用途,包括__init__.py、nmap.py和test.py。__init__.py主要导入基本信息,nmap.py用于调用nmap的功能进行扫描,test.py用于测试是否可以利用nmap的扫描功能。 ... [详细]
  • 大坑|左上角_pycharm连接服务器同步写代码(图文详细过程)
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了pycharm连接服务器同步写代码(图文详细过程)相关的知识,希望对你有一定的参考价值。pycharm连接服务 ... [详细]
  • 关于python调试大法的信息
    本文目录一览:1、pdbpython调试怎么用 ... [详细]
  • Jenkins的分布式构建,在Jenkins的配置中叫做节点,分布式构建能够让同一套代码或项目在不同的环境(如:Windows和Linux系统)中编译、部署等。将jenkins项目 ... [详细]
  • FTP服务ftp的报错及用户管理
    ftp服务常见报错530报错认证失败(密码错误或者服务端拒绝)550服务本身未开启553文件系统不可写(权限问题)500服 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 从U ... [详细]
author-avatar
新疆盛苑烟酒特产_485
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有