#!/usr/bin/env pythonpython
import os,sys,time,re,prettytable,jsongit
from collections import defaultdict,OrderedDictjson
conf='haproxy.cfg' ###指定haproxy配置文件###後端
jgf=''服務器
######################1.input輸入字符類型轉化函數#######################app
def input_handle(s):ide
if str.isdigit(s): ###對輸入是不是數字進行判斷###函數
s = int(s) ###若是輸出的是個數字,則轉化爲整數類型###spa
return s ###返回輸入字符###orm
###########################2.backend列表展現函數############################
def backend_read(conf):
backend_list = [] ###初始化backend的列表###
show_dict = {} ###初始化要返回的顯示字典###
backend_name_dict = defaultdict(list) ###定義一個value爲列表的字典,用來存放server###
server_flag = False ###初始化server判斷標誌位###
with open(conf,'r') as ha: ###打開haproxy配置文件###
for line in ha:
server_dict = OrderedDict() ###定義一個有序字典###
line = line.strip('\n')
#狀況1
if re.match('backend',line): ###匹配配置文件以backend開頭的行###
backend_name = re.split('\s+',line)[1]
backend_list.append(backend_name) ###將配置到的backend的名稱插入到列表###
server_flag = True ###賦值標誌位爲真,用來與server關聯###
#狀況2
elif server_flag and re.match('\s+server',line): ###匹配配置文件以server開頭的行###
server_info = re.split('\s+',line) ###對server進行分隔###
server_dict['name'] = server_info[2] ###對server的具體信息進行字典賦值###
server_dict['address'] = server_info[3]
server_dict['weight'] = server_info[5]
server_dict['maxconn'] = server_info[7]
backend_name_dict[backend_name].append(server_dict) ###將server字典與backend的名稱進行關聯###
else:
server_flag = False ###當server沒匹配到,賦值標誌位爲假,結束關聯###
for k,v in enumerate(backend_list,1):
show_dict[k] = v ###對backend名稱進行新字典賦值,方便查詢和展現###
print('%d . %s' % (k,v)) ###輸出backend列表###
return(show_dict,backend_name_dict) ###返回顯示的字典和backend-server字典###
########################3.顯示server服務器函數#############################
def backend_server_show(backend_show_value,server_show_dict):
############對backend名稱進行遍歷並加上數字編號###########################
print(jgf.center(70,'='))
print('\033[1m後端服務器(%s)信息以下:\033[0m'%backend_show_value)
print('%-20s %-20s %-20s %-20s'%('name','address','weight','maxconn'))
server_list = server_show_dict[backend_show_value]
for v in server_list: ###用enumerate進行server展現###
n=list(v.values())
print('\033[32;40m%-5s%20s%15s%25s\033[1m'%(n[0],n[1],n[2],n[3]))
print(jgf.center(60, '='))
#####################4.名稱輸入判斷函數#############################
def name_decide():
(name,name_flag) = ('',True) ###初始化返回的名稱和判斷標誌位###
while name_flag:
name_input = input('\033[32m請輸入新服務名(退出輸入q):\033[0m')
if len(name_input) == 0: ###若是輸入爲空則直接下一次循環###
continue
elif name_input == 'q': ###輸入q,退出本次輸入###
name_flag = False
sys.exit('\033[32;1m腳本已退出!\033[1m')
elif re.match('[0-9a-zA-Z\_]+',name_input): ###匹配輸入是否以字符、數字或下劃線開頭###
name = name_input
name_flag = False ###輸入成功後退出循環###
else:
print('\033[31m名稱輸入錯誤,請從新輸入!!!\033[0m')
break
return(name) ###返回輸入的結果###
#####################5.IP地址及端口輸入判斷函數#############################
def ipaddress_decide():
(address,address_flag) = ('',True) ###初始化返回的IP地址和判斷標誌位###
while address_flag:
address_input = input('\033[32m請輸入新地址(IP哦)(退出輸入q):\033[0m')
if len(address_input) == 0: ###若是輸入爲空則直接下一次循環###
continue
elif address_input == 'q': ###輸入q,退出本次輸入###
address_flag = False
sys.exit('\033[32;1m腳本已退出!\033[1m')
##################匹配輸入是不是ip:port的格式######################
elif re.match('(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}(\:\d{1,5})?$',address_input):
address = address_input
address_flag = False ###輸入成功後退出循環###
else:
print('\033[31m地址輸入錯誤,請從新輸入!!!\033[0m')
return(address) ###返回輸入的結果###
####################6.數字輸入判斷函數######################################
def number_decide(name):
(number,number_flag) = ('',True) ###初始化返回的數字和判斷標誌位###
while number_flag:
number_input =input('\033[32m請輸入%s(數字哦)(退出輸入q):\033[0m' % name)
if len(number_input) == 0: ###若是輸入爲空則直接下一次循環###
continue
elif number_input == 'q': ###輸入q,退出本次輸入###
number_flag = False
sys.exit('\033[32;1m腳本已退出!\033[32;1m')
else:
try:
int(number_input) ###匹配輸入是不是數字###
except:
print('\033[31;1m%s輸入類型錯誤,請從新輸入!!!\033[0m'%name)
else:
number = number_input
number_flag = False ###輸入成功後退出循環###
return(number) ###返回輸入的結果###
#############################7.節點輸入判斷函數##########################
def backend_input_if(input_index,input_dict):
(input_name,input_flag) = ('',True) ###初始化返回的名稱和判斷標誌位###
###############若是輸入非空,對輸入進行判斷並轉化類型#################
if len(input_index) != 0:
input_index = input_handle(input_index)
if input_index == 'b': ###若是輸入爲b,則退出程序###
input_flag = False
elif input_index in input_dict.keys(): ###若是輸入爲數字編號,則從字典中獲取具體backend名稱###
input_name = input_dict[input_index]
elif input_index in input_dict.values(): ###若是輸入爲backend名稱,則直接獲取###
input_name = input_index
else:
input_name = '' ###輸入其餘字符,賦值變量爲空###
return(input_name,input_flag) ###返回輸入的結果和循環標誌位###
########################8.配置文件操做函數#################
def backend_server_handle(conf,handle_dict):
newfile = '%s.new'%conf ###定義回寫的新文件###
server_flag = False
with open(conf,'r') as read_file,open(newfile,'w') as write_file: ###同時打開二文件,一個讀,一個寫###
for line in read_file:
if re.match('backend',line): ###匹配到backend行時進行server信息插入###
write_file.write(line)
backend_name = re.split('\s+',line)[1]
for server_dict in handle_dict[backend_name]: ###對backend-server字典進行遍歷###
server_line = '\tserver {name} {address} weight {weight} maxconn {maxconn}\n'
write_file.write(server_line.format(**server_dict)) ###將指定的backend下的server條目插入文件###
server_flag = True ###指定標誌位爲真,方便server判斷###
elif server_flag and re.match('\s+server',line): ###匹配server開頭的行,跳過不作任何操做###
pass
else:
write_file.write(line) ###其餘的行,直接插入新文件###
server_flag = False
print('\033[33;1m server更新成功\033[0m')
os.system('mv %s %s.bak'%(conf,conf)) ###對源配置文件進行備份###
os.system('mv %s %s'%(newfile,conf)) ###對新生成的配置文件進行更名###
##################################主程序開始##################################
if __name__ == '__main__':
flag = True
backend_name = ''
haproxy_name_show_dict = {} ###初始化backend顯示字典###
haproxy_server_show_dict = {} ###初始化server顯示字典###
while flag:
print(jgf.center(60,'='))
hy='\033[36m歡迎訪問haproxy配置文件管理腳本\033[0m'
print(hy.center(60,'*'))
print('\033[1mbackend列表信息以下:')
(haproxy_name_show_dict,haproxy_server_show_dict) = backend_read(conf)
print(jgf.center(50,'='))
time.sleep(1)
print('''
\033[35;1m1.查詢後端服務\033[0m
\033[35;1m 2.添加後端服務\033[0m
\033[35;1m 3.修改後端服務\033[0m
\033[31;1m 4.刪除後端服務\033[0m
\033[32;1m 5.退出\033[0m ''')
print(jgf.center(60,'='))
select_num = input('\033[35;1m請選擇操做條目:\033[0m')
#######################1. 查詢後端服務################################
if select_num == '1':
query_flag = True ###初始化查詢循環標誌###
while query_flag:
backend_index =input('\033[31;1m請輸入須要查詢的backend編號或名稱(返回上級菜單輸入b,退出輸入q):\033[0m')
##############################對輸入值進行判斷################
(backend_name,query_flag) = backend_input_if(backend_index,haproxy_name_show_dict)
if backend_name: ###顯示對應backend下的server列表###
backend_server_show(backend_name,haproxy_server_show_dict)
elif backend_index=='b':
break
elif backend_index=='q':
sys.exit('\033[35;1m腳本退出!\033[0m')
else:
query_flag=False
print('\033[31;1m您輸入的節點不存在!請從新輸入!')
time.sleep(1)
#######################2. 添加後端服務################################
if select_num == '2':
add_flag = True ###初始化添加循環標誌###
while add_flag:
backend_index =input('\033[32;1m請輸入添加的backend的編號或名稱(返回上級菜單,請輸入b):\033[0m')
##############################對輸入值進行判斷################
(backend_name,add_flag) = backend_input_if(backend_index,haproxy_name_show_dict)
if backend_name: ###顯示對應backend下的server列表###
backend_server_show(backend_name,haproxy_server_show_dict)
add_server_dict = OrderedDict() ###設置實例默認爲有序字典
print('\033[34;1m請依次輸入後端服務信息(name,address,weight,maxconn):\033[0m')
add_server_dict['name'] = name_decide() ###對輸入的name有效性進行判斷###
add_server_dict['address'] = ipaddress_decide() ###對輸入的IP有效性進行判斷###
add_server_dict['weight'] = number_decide('權重值') ###對輸入的權重有效性進行判斷###
add_server_dict['maxconn'] = number_decide('最大鏈接數') ###對輸入的鏈接數有效性進行判斷###
print(add_server_dict['name'],add_server_dict['address'],add_server_dict['weight'],add_server_dict['maxconn'])
#############對輸入的四個服務信息是否成功判斷#############
if add_server_dict['name'] and add_server_dict['address'] and add_server_dict['weight'] and add_server_dict['maxconn']:
add_commit = input('\033[31;1m請確認是否添加此條目(y | n):\033[0m')
if add_commit == 'y': ###確認添加服務條目,並回寫配置文件###
haproxy_server_show_dict[backend_name].append(add_server_dict)
backend_server_handle(conf,haproxy_server_show_dict)
else:
add_flag = False ###不然退出本次循環###
else:
print('\033[1;31m server信息輸入有誤,請從新輸入!!!\033[0m')
time.sleep(2)
#######################3. 修改後端服務#################################
if select_num == '3':
backend_modify_flag = True ###初始化修改循環標誌###
while backend_modify_flag:
backend_index =input('\033[32;1m請輸入修改的backend的編號或名稱(返回上級菜單,請輸入b):\033[0m')
##############################對輸入值進行判斷################
(backend_name,backend_modify_flag) = backend_input_if(backend_index,haproxy_name_show_dict)
if backend_name: ###顯示對應backend下的server列表###
backend_server_show(backend_name,haproxy_server_show_dict)
server_modify_flag = True ###初始化server條目修改標誌位###
while server_modify_flag:
server_index =input('\033[32;1m請輸入修改的server的編號(返回上級菜單,請輸入b):\033[0m')
if len(server_index) != 0:
server_index = input_handle(server_index)
if server_index == 'b': ###輸入b,返還上一層###
server_modify_flag = False
#####################指定具體的server編號進行判斷#####
elif server_index >= 1 and server_index <= len(haproxy_server_show_dict[backend_name]):
modify_server_dict = OrderedDict()
print('\033[34;1m請依次輸入後端服務信息(name,address,weight,maxconn):\033[0m')
modify_server_dict['name'] = name_decide() ###對輸入的四個信息有效性進行判斷###
modify_server_dict['address'] = ipaddress_decide()
modify_server_dict['weight'] = number_decide('權重值')
modify_server_dict['maxconn'] = number_decide('最大鏈接數')
print(modify_server_dict['name'],modify_server_dict['address'],modify_server_dict['weight'],modify_server_dict['maxconn'])
######對輸入的四個服務信息是否成功判斷#############
if modify_server_dict['name'] and modify_server_dict['address'] and modify_server_dict['weight'] and modify_server_dict['maxconn']:
modify_commit =input('\033[32;1m請確認是否修改此條目(y|n):\033[1m')
if modify_commit == 'y': ###確認修改服務條目,並回寫配置文件###
haproxy_server_show_dict[backend_name][server_index - 1] = modify_server_dict
backend_server_handle(conf,haproxy_server_show_dict)
modify_server_flag = False
else: ###不然退出本次循環###
modify_server_flag = False
else:
print('\033[31m server輸入信息有誤,請從新輸入!!!\033[0m')
else:
print('\033[31m server編號輸入錯誤,請從新輸入!!!\033[0m')
#######################4. 刪除後端服務################################
if select_num == '4':
backend_delete_flag = True ###初始化刪除循環標誌###
while backend_delete_flag:
backend_index =input('\033[32;1m請輸入刪除的backend下條目編號或名稱(返回上層菜單,請輸入b):\033[0m')
##############################對輸入值進行判斷################
(backend_name,backend_delete_flag) = backend_input_if(backend_index,haproxy_name_show_dict)
if backend_name: ###顯示對應backend下的server列表###
backend_server_show(backend_name,haproxy_server_show_dict)
server_delete_flag = True ###初始化server條目刪除標誌位###
while server_delete_flag:
server_index =input('\033[32;1m請輸入要刪除的server編號(返回上層菜單,請輸入b):\033[0m')
if len(server_index) != 0:
server_index = input_handle(server_index)
if server_index == 'b': ###輸入b,返還上一層###
server_delete_flag = False
#####################指定具體的server編號進行判斷#####
elif server_index >= 1 and server_index <= len(haproxy_server_show_dict[backend_name]):
print(haproxy_server_show_dict[backend_name][server_index - 1])
delete_commit =input('請確認是否刪除此條目(y|n):')
if delete_commit == 'y': ###確認刪除服務條目,並回寫配置文件###
del haproxy_server_show_dict[backend_name][server_index - 1]
backend_server_handle(conf,haproxy_server_show_dict)
delete_server_flag = False
else: ###不然退出本次循環###
delete_server_flag = False
else:
print('\033[31m server編號輸入錯誤,請從新輸入!!!\033[0m')
#######################5. 退出程序######################
if select_num == '5':
print('\033[31;1m程序將在兩秒後退出,歡迎再次使用,謝謝!\033[0m')
time.sleep(1)
print('\033[32;1m1s\033[0m')
time.sleep(1)
print('\033[32;1m2s\033[0m')
print('\033[31;1m程序退出')
sys.exit()