老男孩Day10作业:主机管理程序
一、作业需求:
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 = {
'':self.new_host, #创建主机模块
'':self.delect_host, #删除主机模块
'':self.auto_host, #激活主机模块
'':self.action_host, #控制主机模块
'':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
老男孩Day10作业:主机管理程序的更多相关文章
- python10作业思路及源码:类Fabric主机管理程序开发(仅供参考)
类Fabric主机管理程序开发 一,作业要求 1, 运行程序列出主机组或者主机列表(已完成) 2,选择指定主机或主机组(已完成) 3,选择主机或主机组传送文件(上传/下载)(已完成) 4,充分使用多线 ...
- python作业类Fabric主机管理程序开发(第九周)
作业需求: 1. 运行程序列出主机组或者主机列表 2. 选择指定主机或主机组 3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载) 4. 充分使用多线程或多进程 5. 不同主机的用户名密码 ...
- python第五十二天---第九周作业 类 Fabric 主机管理程序
类 Fabric 主机管理程序开发:1. 运行程序列出主机组或者主机列表2. 选择指定主机或主机组3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载)4. 充分使用多线程或多进程5. 不同 ...
- python 学习分享-实战篇类 Fabric 主机管理程序开发
# 类 Fabric 主机管理程序开发: # 1. 运行程序列出主机组或者主机列表 # 2. 选择指定主机或主机组 # 3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载) # 4. 充分 ...
- 类 Fabric 主机管理程序开发
类 Fabric 主机管理程序开发:1. 运行程序列出主机组或者主机列表2. 选择指定主机或主机组3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载4. 充分使用多线程或多进程5. 不同主 ...
- 老男孩Day12作业:RabbitMQ-RPC版主机管理程序
一.作业需求 1.可以对指定机器异步的执行多个命令 例子: 请输入操作指令>>>:run ipconfig --host 127.0.0.0 in the call tack ...
- Day10作业及默写
1,继续整理函数相关知识点,写博客. 2,写函数,接收n个数字,求这些参数数字的和.(动态传参) def func(*number): sum=0 for num in number: sum+=nu ...
- 老男孩Day17作业:后台管理平台编辑表格
一.作业需求: 后台管理平台 ,编辑表格: 1. 非编辑模式: 可对每行进行选择: 反选: 取消选择 2. 编辑模式: 进入编辑模式时如果行被选中,则被选中的行万变为可编辑状态,未选中的不改变 退出编 ...
- 老男孩Day16作业:登录、注册、后台管理页面(动态)
一.作业需求: 1.后台管理主界面(左边菜单框.(全选.反选)框.返回顶部按钮) 2.老男孩登录.注册页面 二.博客地址:https://www.cnblogs.com/catepython/p/93 ...
随机推荐
- How to Change Master Page @ Run-time
This tip will give complete knowledge of how to change master page, render controls and accessing it ...
- linux中memset的正确用法
linux中memset的正确用法 [起因]希望对各种类型的数组进行初始化,避免野值 [函数头文件] 提示:在linux中可以在terminal中输入 "man memset"进行 ...
- grep家族
grep家族由命令grep.egrep和fgrep组成. grep:在文件中全局查找指定的正则表达式,并且打印所有包含该表达式的行.egrep和fgrep是grep的变体.egrep:grep的扩展, ...
- sqlplus客户端出现乱码
查询oracle server端的字符集 select userenv('language') from dual; 修改客户端 cmd是gbk编码 环境变量 NLS_LANG 值:SIMPLIFIE ...
- Spring Bean定义的三种方式
<!--Spring容器启动配置(web.xml文件)--> <context-param> <param-name>contextConfigLocation&l ...
- 证明3|n(n+1)(2n+1)
[证明3|n(n+1)(2n+1)] n(n+1)(2n+1) => n(n+1)(n+2+n-1) => n(n+1)(n+2) + n(n+1)(n-1) 因为n(n+1)(n+2). ...
- MyBatis之 逆向工程生成代码
逆向工程: 所谓mybatis逆向工程,就是mybatis会根据我们设计好的数据表,自动生成pojo.mapper以及mapper.xml. 工程简单案例: 1,新建一个java项目,把需要使用的ja ...
- google/dense_hash_map
这个库使用时需要注意的地方: 1.在插入数据之前,需要先调用set_empty_key()设置一个空Key,Key的值可以为任意符合类型的.但请注意之后插入的Key不能和空Key相同,否则会abort ...
- 【HDU5391】Zball in Tina Town
[题目大意] 一个球初始体积为1,一天天变大,第一天变大1倍,第二天变大2倍,第n天变大n倍.问当第 n-1天的时候,体积变为多少.注意答案对n取模. [题解] 根据威尔逊定理:(n-1)! mod ...
- 把dataTable表批量的写入数据库
connectionStr:链接字符串:dataTableName数据库中的表:sourceDataTable dataTable的名称 public static void SqlBulkCopyB ...