主机管理程序


一、作业需求:

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
原文地址:https://www.cnblogs.com/gaodi2345/p/11412822.html