一、作业需求
1. 运行程序列出主机组或者主机列表
2. 选择指定主机或主机组
3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载)
4. 充分使用多线程或多进程
5. 不同主机的用户名密码、端口可以不同
二、实现功能
1、创建主机
2、运行程序列出主机列表
3、选择指定主机或主机组
4、选择让主机或主机组执行命令或传输文件
5、充分使用多线程注意:新用户使用本程序1、创建主机------->需根据自己现已开启的主机创建主机,将主机信息以文件的形式保存下来;
2、连接主机------->根据用户创建的主机,读取db目录下使用主机信息,返回列表的形式,并逐一尝试连接,连接成功状态设为1,连接不成功状态设为0;
3、运行主机------->根据上一步确定的可以连接的主机,输出课连接主机列表,根据用户的选择和命令输入来操控主机
put上传文件的方法------>上传的本地文件需在localhost下,且只用输入文件名即可
文件保存的路径只用输入保存的目录和文件名“/Downloads/aaa”,程序会自动加上“/用户名”前缀路径
get上传文件的方法------>从远程主机下载的文件的路径只用输入目录和文件名“/Downloads/aaa”,程序会自动加上“/用户名”前缀路径
下载的文件默认保存在localhost下
三、目录说明
类Farbic主机管理程序/
|-- bin/
| |-- __init__.py
| |-- para_start.py #程序启动的主入口
|
|-- conf/
| |-- __init__.py
| |-- settings.py #配置文件
|
|-- db/ #主机数据目录
|
|-- lib/
| |-- __init__.py
| |-- common.py #公共方法程序
| |-- main.py #主程序
|
|-- localhost/ #模拟本地文件目录
| |-- aaa.jpg
|
|-- log/
| |-- log_sys.log #日志文件
|
|-- 流程图
|-- README.txt
四、流程图
五、程序代码
1、bin/para_start.py
import os,sys Base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(Base_dir) from lib.main import main_func if __name__ == '__main__': main_func()
2、conf/settings.py
import os Basedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) HOST_INFO = os.path.join(Basedir,"db") HOST_DIR = os.path.join(Basedir,"home") LOCAL_DIR = os.path.join(Basedir,"localhost") LOG_DIR = os.path.join(Basedir,"log")
3、lib/common.py
import logging,os,sys frame = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(frame) from conf import settings # def sys_logging(content,levelname): ''' 程序记录日志函数 :param content: 日志的内容 :param levelname: 日志的等级 :return: none ''' _filename = os.path.join(settings.LOG_DIR,"log_sys.log") log = logging.getLogger(_filename) logging.basicConfig(filename=_filename,level=logging.INFO,format='%(asctime)s-%(levelname)s-%(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') if levelname == 'debug': logging.debug(content) elif levelname == 'info': logging.info(content) elif levelname == 'warning': logging.warning(content) elif levelname == 'error': logging.error(content) elif levelname == 'critical': logging.critical(content) def show(msg,msg_type): ''' 程序不同信息打印的字体颜色 :param msg: 打印信息 :param msg_type: 打印信息的类型 :return: none ''' if msg_type == "info": show_msg = " 33[1;35m%s 33[0m"%msg elif msg_type == "error": show_msg = " 33[1;31m%s 33[0m"%msg elif msg_type == "msg": show_msg = " 33[1;37m%s 33[0m"%msg else: show_msg = " 33[1;32m%s 33[0m"%msg print(show_msg) sys_logging(msg, msg_type)
4、lib/main.py
import os,sys,pickle,threading,paramiko Far_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) lib_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(lib_dir) sys.path.append(Far_dir) from common import show from conf import settings def creat_host(): ''' creat a new host method :return: none ''' hostname = input("请输入主机名:>>>").strip() port = input("请输入主机端口号:>>>").strip() username = input("请输入登录用户名:>>>").strip() psd = input("请输入登录密码:>>>").strip() host_dic = { "hostname":hostname, "port":port, "username":username, "psd":psd, "status":0 } host_dir = settings.HOST_DIR+"/"+hostname if hostinfo_write(host_dic,hostname): show("主机创建成功","error") def host_connect(): ''' connect host method :return: none ''' hostinfo_list = hostinfo_read() if len(hostinfo_list) == 0: exit("当前暂无主机,请先创建主机") print(" 33[1;37m主机列表 33[0m".center(40,"-")) for dic in hostinfo_list: show(" 主机名:%s"%dic["hostname"],"msg") TH = threading.Thread(target=ssh_parse,args=(dic,)) TH.setDaemon(True) TH.start() TH.join() def ssh_parse(dic): ''' try to connect all host,if can't connect ,make it's status to 0 ,else to 1 :param dic: host info dic :return: none ''' ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh.connect(hostname=dic["hostname"],port=int(dic["port"]),username=dic["username"],password=dic["psd"]) except Exception as e: show("主机[%s]连接失败 原因:%s"%(dic["hostname"],e),"error") dic["status"] = 0 hostinfo_write(dic, dic["hostname"]) else: show("主机[%s]连接成功" % (dic["hostname"]), "a") dic["status"] = 1 hostinfo_write(dic,dic["hostname"]) ssh.close() def run_host(): ''' try to operate host :return: none ''' active_list = [] hostinfo_list = hostinfo_read() for dic in hostinfo_list: if dic["status"] == 1: active_list.append(dic) # print(active_list) if len(active_list) == 0: exit("当前无连接的主机,请先连接主机确保主机能正常连接") show("已连接的主机:","msg") for i,j in enumerate(active_list): show("%s:%s"%(i+1,j["hostname"]),"msg") choice = input("请输入您要操控的主机(输入“all”,所有主机同时运行):>>>").strip() if choice == "all": host_parse(active_list) else: list = [] list.append(active_list[int(choice)-1]) host_parse(list) def host_parse(list): ''' if host can be connected , user can input conmand ,and host will carry out the conmand :param list:all host info list :return:none ''' while True: command = input("请输入指令(help显示帮助信息,b返回):>>>").strip() if command == "help": help_info = '''-----------【help】----------- 1、输入“put”上传文件 2、输入“get”下载文件 3、输入“df”查看磁盘信息 4、输入“ls”查看文件或目录 5、输入“uname”查看系统信息 6、输入“ifconfig”查看网络信息 7、更多命令详见“http://www.cnblogs.com/japhi/p/7084042.html” ''' show(help_info, "msg") elif command == "put": dir = input("请输入您要上传的文件名(默认文件路径在---localhost):>>>").strip() local_dir = settings.LOCAL_DIR + "/" + dir if not os.path.exists(local_dir): show("文件名不存在", "error") dir0 = input("请输入您要保存的路径(例:/Downloads/bbb):>>>").strip() for dic in list: TH = threading.Thread(target=put_method, args=(dic, local_dir, dir0,)) TH.start() TH.join() elif command == "get": dir1 = input("请输入您要下载的远程主机文件路径(例:/temp/ccc):>>>").strip() res_list = dir1.split("/") local_dir = settings.LOCAL_DIR + "/" + res_list[len(res_list) - 1] # print(local_dir) for dic in list: TH = threading.Thread(target=get_method, args=(dic, dir1, local_dir,)) TH.start() TH.join() elif command == "b": break else: for dic in list: TH = threading.Thread(target=command_method, args=(dic, command,)) TH.start() TH.join() def put_method(dic,local_dir,dir): ''' upload file method :param dic: host info dic :param local_dir: the dir of local file :param dir: the dir of the file will be savede :return: none ''' try: nonlocal_dir = "/" + dic["username"] + dir print(nonlocal_dir) transport = paramiko.Transport((dic["hostname"], int(dic["port"]))) transport.connect(username=dic["username"], password=dic["psd"]) sftp = paramiko.SFTPClient.from_transport(transport) sftp.put(local_dir, nonlocal_dir) show("主机[%s]上传文件成功" % dic["hostname"], "info") except Exception as e: show("主机[%s]发生错误:%s" % (dic["hostname"], e), "error") def get_method(dic,dir, local_dir): ''' downloads file method :param dic: host info :param dir: the dir of file to be downloads :param local_dir: the dir of the file will be saved :return: none ''' try: nonlocal_dir = "/" + dic["username"] +dir transport = paramiko.Transport((dic["hostname"], int(dic["port"]))) transport.connect(username=dic["username"], password=dic["psd"]) sftp = paramiko.SFTPClient.from_transport(transport) sftp.get(nonlocal_dir, local_dir) show("主机[%s]下载文件成功"%dic["hostname"],"info") except Exception as e: show("主机[%s]发生错误:%s"%(dic["hostname"],e),"error") def command_method(dic,command): ''' carry out the command which user input :param dic: host info :param command: the conmand of user input :return: ''' try: # print(dic) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # print(hostname=dic["hostname"], port=int(dic["port"]), username=dic["username"], password=dic["psd"]) ssh.connect(hostname=dic["hostname"], port=int(dic["port"]), username=dic["username"], password=dic["psd"]) stdin, stdout, sterr = ssh.exec_command(command) result = stdout.read() print(result.decode()) except Exception as e: show("主机[%f]发生错误:%s"%(dic["hostname"],e),"error") def dir_read(dirname): ''' read the dir of db :param dirname: diename :return: files ''' for roots,dirs,files in os.walk(dirname): return files def hostinfo_write(host_dic,hostname): ''' write the host info into a file :param host_dic: host info dict :param hostname: host name :return: if sucessfully return true ''' hostfile = settings.HOST_INFO+"/"+hostname with open(hostfile,"wb") as f: f.write(pickle.dumps(host_dic)) return True def hostinfo_read(): ''' read the host info :return: host info list ''' hostinfo_list = [] for file in os.listdir(settings.HOST_INFO): filename = settings.HOST_INFO+"/"+file hostinfo_list.append(pickle.load(open(filename,"rb"))) # print(hostinfo_list) return hostinfo_list def main_func(): ''' main function :return: none ''' menu_dic = {"1":creat_host,"2":host_connect,"3":run_host} menu_info = '''-----欢迎来到Fabric主机管理界面----- 1、新建主机 2、连接主机 3、运行主机 4、退出程序 ''' while True: show(menu_info, "info") choice = input("您要干啥:>>>").strip() if choice.isdigit() and 0 < int(choice) <= len(menu_dic): menu_dic[choice]() elif choice == "4": show("退出程序", "error") break else: show("输入错误", "error")