菜单功能说明:支持层级深入;选定的父菜单和子集菜单同屏显示,用字母及数字区分;包含子菜单的后缀多..;菜单由执行脚本和菜单模板文件构成,实际执行功能通过配置调用外部脚本。
菜单演示:
*** 系统管理控制台 ***
1. 应用发布..
a. 生产环境..
b. 测试环境..
c. 发布..
2. 应用重启..
3. 服务管理..
4. 数据库同步..
#coding=utf-8
##20161219
##@jians
import os, sys
import json, yaml
import subprocess
class MenuNode(object):
def __init__(self, title):
self.title = title
self.cmd = None
self.directory = None
self.firstneibour = None
self.firstchild = None
def add_cmd(self, cmd):
self.cmd = cmd
def add_neibour(self, other_node):
self.firstneibour = other_node
def add_cwd(self, cwd):
self.directory = cwd
def add_child(self, first_child):
self.firstchild = first_child
def parseMenu(obj, last_node=None):
node = None
if type(obj) == type({}):
node = MenuNode(obj['title'])
if obj.has_key('cmd'):
node.add_cmd(obj['cmd'])
if obj.has_key('directory'):
node.add_cwd(obj['directory'])
if obj.has_key('child'):
parseMenu(obj['child'], node) #递归调用,并传入当前节点,作为之后的父节点或邻节点
if type(obj) == type([]):
for i in range(len(obj)):
if i == 0:
nd = parseMenu(obj[i])
last_node.add_child(nd)
else:
nd = parseMenu(obj[i])
last_node.add_neibour(nd)
last_node = nd
return node
def displayMenu(menu, key=None):
os.system('clear')
print(" *** 系统管理控制台 ***\n")
menu_map = {}
i = 1
while True:
menu_appd = '..'
if menu.cmd:
menu_appd = ''
menu_item_text = str(i) + '. ' + menu.title + menu_appd
menu_map[str(i)] = menu
i += 1
print("\t" + menu_item_text)
if menu == key:
j = 97
child = menu.firstchild
while True:
child_appd = '..'
if child.cmd:
child_appd = ''
menu_item_text = chr(j) + '. ' + child.title + child_appd
menu_map[chr(j)] = child
j += 1
print("\t" + ' ' + menu_item_text +"\n")
if child.firstneibour:
child = child.firstneibour
else:
break
if menu.firstneibour:
menu = menu.firstneibour
print(" ")
else:
break
return menu_map
if __name__ == '__main__':
dirname = os.path.dirname(sys.argv[0])
abspath = os.path.abspath(dirname)
with open(os.path.join(abspath,'menu.yml'), 'r') as f:
j = yaml.load(f)
menu_struct = parseMenu(j)
menu_saved = [] ##历史菜单入栈,用于返回
menu_map = {} ##当前菜单与按键映射
menu_pos = menu_struct.firstchild
menu_hot = None
while True:
menu_map = displayMenu(menu_pos, menu_hot)
input = raw_input("\n 请输入选择(r返回上级,x退出):")
input = input.strip()
if input.lower() == 'r':
if menu_hot:
menu_hot = None
menu_map = displayMenu(menu_pos, menu_hot)
else:
if len(menu_saved) > 0:
menu_pos = menu_saved.pop(-1)
if input.lower() == 'x':
sys.exit()
if menu_map.has_key(input.lower()):
if menu_map[input].cmd:
k = raw_input("确认执行请按y,其他返回: ")
if k != 'y':
continue
print(menu_map[input].cmd.split())
ret = subprocess.Popen(menu_map[input].cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=menu_map[input].directory)
print("\n======>\n")
if ret.stdout:
for line in ret.stdout:
line = line.strip()
print(line)
wait = raw_input("\n任意键返回..")
else:
if input.isdigit():
menu_hot = menu_map[input]
if input.isalpha():
menu_saved.append(menu_pos) # 保存历史
menu_pos = menu_map['a']
menu_hot = menu_map[input]
menu_map = displayMenu(menu_pos, menu_hot)
菜单结构配置采用yaml格式书写,也可以用json格式,用json包导入处理:
title: 菜单中显示的名称
child:该菜单下包含的子菜单
cmd: 菜单对应的执行脚本,包含子菜单则为空
directory:菜单执行时切换的目录
title: 系统菜单
child:
- title: 应用发布
cmd:
child:
- title: 生产环境
child:
- title: 预演
cmd: /usr/bin/ansible-playbook yun1_prop3p.yml restart_yun1_prop3p.yml yun2_prop3p.yml restart_yun2_prop3p.yml
directory: /data/local/auto/deploys/product
- title: 生产pro1
child:
- title: 只更新不重启
cmd: /usr/bin/ansible-playbook yun1_prop.yml yun2_prop.yml
directory: /data/local/auto/deploys/product
- title: 更新、重启
cmd: /usr/bin/ansible-playbook yun1_prop.yml restart_yun1_prop.yml yun2_prop.yml restart_yun2_prop.yml
directory: /data/local/auto/deploys/product
- title: 应用重启
child:
- title: shop
cmd: /usr/bin/ansible-playbook restart_yun1_proshop.yml
directory: /data/local/auto/deploys/product
- title: pro1
cmd: /usr/bin/ansible-playbook restart_yun1_prop.yml
directory: /data/local/auto/deploys/product
- title: 服务管理
child:
- title: dns域名
cmd: show_dns.sh
- title: 内网proxy映射
cmd: show_proxy.sh
- title: 数据库同步
child:
- title: db1同步至本地
cmd: /yunwei/scripts/sync_prod.sh prod_db1
- title: db2同步至本地
cmd: /yunwei/scripts/sync_prod.sh prod_db2