一、作业需求
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")