一.作業需求:
1. 根據用戶輸入輸出對應的backend下的server信息
2. 可添加backend 和sever信息
3. 可修改backend 和sever信息
4. 可刪除backend 和sever信息
5. 操作配置文件前進行備份
6 添加server信息時,如果ip已經存在則修改;如果backend不存在則創建;若信息與已有信息重復則不操作
配置文件 參考 http://www.cnblogs.com/alex3714/articles/5717620.html
二.配置文件:

1 global 2 log 127.0.0.1 local2 3 daemon 4 maxconn 256 5 log 127.0.0.1 local2 info 6 defaults 7 log global 8 mode http 9 timeout connect 5000ms 10 timeout client 50000ms 11 timeout server 50000ms 12 option dontlognull 13 14 listen stats :8888 15 stats enable 16 stats uri /admin 17 stats auth admin:1234 18 19 frontend oldboy.org 20 bind 0.0.0.0:80 21 option httplog 22 option httpclose 23 option forwardfor 24 log global 25 acl www hdr_reg(host) -i www.oldboy.org 26 use_backend www.oldboy.org if www 27 28 backend www.oldboy.org 29 server 110.1.1.2 110.1.1.2 weight 20 maxconn 2000 30 server 110.1.1.1 110.1.1.1 weight 30 maxconn 3000 31 32 backend www.12345.com.cn 33 server 100.1.7.8 100.1.7.8 weight 10 maxconn 1000 34 35 backend www.baidu.com 36 server 100.0.0.1 100.0.0.1 weight 80 maxconn 1000
三.流程圖:
四.代碼:(python3.6 mac環境)

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author: Even 4 5 6 import os,sys 7 8 9 def numif(number_input): # 判斷輸入是否為數字 10 while not number_input.isdigit(): # 輸入不是數字就進入循環 11 number_input = input('\033[31m 輸入%s不是數字,請重新輸入!\033[0m' % number_input) # 提示重新輸入 12 number = number_input 13 return number 14 15 16 def show_list(file): # 查詢顯示並將文本生成程序需要的字典和列表 17 backend_list = [] 18 backend_all_dict = {} 19 backend_dict = {} 20 server_list = [] 21 with open(file,'r') as f: # 讀取haproxy文件 22 for line in f: 23 24 line = line.strip() 25 if line.startswith('backend') == True: # 判斷是否是backend開頭,讀取backend信息寫到backend_list中 26 backend_name = line.split()[1] 27 backend_list.append(backend_name) # 將文件中backend加到列表中 28 server_list = [] # 清空server_list里的記錄,遇到新backend可以輸入新的server_list 29 30 elif line.startswith('server') == True: # 判斷是否是server開頭,讀取server信息寫到backend_all_dict中 31 backend_dict['name'] = line.split()[1] # 讀取文件中server的name 32 backend_dict['IP'] = line.split()[2] # 讀取文件中server的IP 33 backend_dict['weight'] = line.split()[4] # 讀取文件中server的weight 34 backend_dict['maxconn'] = line.split()[6] # 讀取文件中server的maxconn 35 server_list.append(backend_dict.copy()) # 將backend中的信息加到server_list中,此處需要用copy 36 backend_all_dict[backend_name] = server_list # 將server信息對應backend存到字典中 37 38 return (backend_list,backend_all_dict) # 返回backend和server信息 39 40 41 def backend_show(backend_list): # 展示backend列表內容 42 backend_show_dict = {} 43 print("-------------------------------------------------") 44 print("\t\t\t歡迎來到HAproxy文件配置平台") 45 print("-------------------------------------------------") 46 print("backend列表信息如下:") 47 for k,v in enumerate(backend_list,1): # 逐行讀取backend信息並展示 48 print(k, v) 49 backend_show_dict[str(k)] = v 50 return backend_show_dict # 返回backend和對應編號 51 52 53 def server_show(backend_input,backend_all_dict): # 展示backend下server內容 54 server_show_dict = {} 55 server_list = backend_all_dict[backend_input] 56 for k,v in enumerate(server_list,1): # 編號展示server信息 57 print(k,"name:",v['name'],"\tIP:",v['IP'],"\tweight:",v['weight'],"\tmaxconn:",v['maxconn']) 58 server_show_dict[k] = v 59 return server_show_dict # 返回編號對應的server字典 60 61 62 def action_list(): # 顯示操作列表和編號,並返回操作編號 63 print("-------------------------------------------------") 64 print("操作清單如下:") 65 print(''' 66 1.查詢backend和server信息 67 2.添加backend和server信息 68 3.修改backend和server信息 69 4.刪除backend和server信息 70 5.退出 71 ''') 72 print("-------------------------------------------------") 73 action_num = numif(input("請輸入需要操作的編號:(請輸入數字)")) 74 return action_num 75 76 77 def inquiry(inquiry_input): # 定義查詢功能 78 while True: 79 if inquiry_input in backend_show_dict: # 編號輸入分支 80 backend_input = backend_show_dict[inquiry_input] # 輸入編號得到backend 81 print(backend_input, ":") 82 server_show(backend_input, backend_all_dict) # 調用server_show,展示backend下server 83 break 84 85 elif inquiry_input in backend_show_dict.values(): # backend名稱輸入分支 86 print(inquiry_input, ":") 87 server_show(inquiry_input, backend_all_dict) # 調用server_show,展示backend下server 88 break 89 90 else: # 校驗異常輸入 91 inquiry_input = input("輸入錯誤,請重新輸入:") 92 93 94 def add(add_input,file): # 定義添加功能 95 (backend_list, backend_all_dict) = show_list(file) 96 while True: 97 if add_input in backend_show_dict: #添加原有backend下server 98 add_dict = {} 99 add_dict['name'] = input("請輸入需增加server名稱:") 100 add_dict['IP'] = input("請輸入需增加IP地址:") 101 add_dict['weight'] = input("請輸入需增加weight值:") 102 add_dict['maxconn'] = input("請輸入需增加maxcoon值:") 103 backend_name_add = backend_list[int(add_input)-1] 104 105 for dict in backend_all_dict[backend_name_add]: # 實現IP已存在,更新weight信息和maxconn信息 106 if add_dict['IP'] in dict.values(): 107 dict['weight'] = add_dict['weight'] 108 dict['maxconn'] = add_dict['maxconn'] 109 break 110 111 else: # IP不存在,就將server增加到backend下 112 backend_all_dict[backend_name_add].append(add_dict) 113 114 backup(file,backend_name_add,backend_all_dict) # 調用backup函數,將新增內容讀寫到文件中 115 print('''name:%s IP:%s weight:%s maxconn:%s已添加成功'''%( 116 add_dict['name'],add_dict['IP'],add_dict['weight'],add_dict['maxconn'])) # 提示添加成功 117 break 118 119 else: # 添加新backend下的server 120 add_dict = {} 121 add_dict['name'] = input("請輸入%s下新增server名稱:"%add_input) 122 add_dict['IP'] = input("請輸入%s下新增IP地址:"%add_input) 123 add_dict['weight'] = input("請輸入%s下新增weight值:"%add_input) 124 add_dict['maxconn'] = input("請輸入%s下新增maxcoon值:"%add_input) 125 backend_name_add = add_input 126 backend_all_dict[backend_name_add] = add_dict # 將新增backend和對應server存到字典中 127 128 file_new = "%s_new" % file # 新建一個文件,用來新增數據 129 with open(file, 'r') as f_read, open(file_new, 'a+') as f_write: # 讀取file文件,追加backend信息 130 for line in f_read: 131 f_write.write(line) 132 f_write.write("\nbackend %s" % backend_name_add) # 追加backend信息 133 server_line_write = '\n\t\tserver {name} {IP} weight {weight} maxconn {maxconn}\n' # 追加server信息 134 f_write.write(server_line_write.format(**add_dict)) # 格式化輸出 135 136 os.system('mv %s %s_backup' % (file, file)) # 將file文件名改為file_backup 137 os.system('mv %s %s' % (file_new, file)) # 將file_new文件名改為file,實現備份 138 print("\nbackend %s" % backend_name_add) 139 print('''name:%s IP:%s weight:%s maxconn:%s已添加成功''' % ( 140 add_dict['name'], add_dict['IP'], add_dict['weight'], add_dict['maxconn'])) # 提示添加成功 141 break 142 143 144 def revise(revise_input): # 定義修改功能 145 revise_dict = {} 146 if revise_input in backend_show_dict: # 判斷輸入是否存在 147 backend_revise = backend_show_dict[revise_input] # 通過編號獲取backend 148 revise_choise = input("是否需要修改該backend名稱:%s;確認請按'y',按任意鍵繼續:"%backend_revise) # 確認是否修改backend名,輸入y修改,否則繼續修改 149 if revise_choise == 'y': 150 backend_revise_new = input("請輸入修改后的backend名:") # 修改backend名 151 backend_all_dict[backend_revise_new] = backend_all_dict.pop(backend_revise) # 將舊backend的server對應到修改后的backend上 152 revise_choise_server = input("是否需要繼續修改%s下的server:確認請按'y',按任意鍵繼續:"%backend_revise_new) # 詢問是否繼續修改 153 if revise_choise_server == 'y': # 繼續修改server 154 server_revise_dict = server_show(backend_revise_new, backend_all_dict) # 展示server信息 155 server_revise_num = numif(input("請輸入需要修改的server編號:")) # 獲取需要修改的server編號 156 revise_dict['name'] = input("請輸入修改后的name:") 157 revise_dict['IP'] = input("請輸入修改后的IP:") 158 revise_dict['weight'] = input("請輸入修改后的weight:") 159 revise_dict['maxconn'] = input("請輸入修改后的maxconn:") 160 server_revise_dict[int(server_revise_num)] = revise_dict # 通過編號修改server信息 161 server_revise_dict_backup = {} 162 server_revise_dict_backup[backend_revise_new] = server_revise_dict.values() # 將修改的server信息對應到修改后的backend存到字典中 163 backup(file, backend_revise, server_revise_dict_backup,backend_revise_new) # 調用backup函數,操作文件 164 165 else: # 不修改server,只修改了backend 166 backup(file, backend_revise, backend_all_dict,backend_revise_new) 167 else: # 未修改backend名情況時修改server信息 168 server_revise_dict = server_show(backend_revise, backend_all_dict) 169 server_revise_num = numif(input("請輸入需要修改的server編號:")) # 獲取需修改的server編號 170 revise_dict['name'] = input("請輸入修改后的name:") 171 revise_dict['IP'] = input("請輸入修改后的IP:") 172 revise_dict['weight'] = input("請輸入修改后的weight:") 173 revise_dict['maxconn'] = input("請輸入修改后的maxconn:") 174 server_revise_dict[int(server_revise_num)] = revise_dict # 修改的server信息對應到編號中存到字典中 175 server_revise_dict_backup = {} 176 server_revise_dict_backup[backend_revise] = server_revise_dict.values() # 將修改后的server信息對應backend存到字典中 177 backup(file,backend_revise,server_revise_dict_backup) # 調用backup函數,操作文件 178 else: # 輸入錯誤提示重新輸入 179 revise_input_return = input("需修改backend不存在,請重新輸入:") 180 revise(revise_input_return) 181 182 183 def delete(delete_input): # 定義刪除功能 184 if delete_input in backend_show_dict: 185 backend_delete = backend_show_dict[delete_input] 186 delete_choise = input("是否需要刪除該backend:%s;確認請按'y',按任意鍵繼續:"%backend_delete) 187 if delete_choise == 'y': # 判斷是否刪除backend信息 188 del backend_all_dict[backend_delete] # 在backend與server總字典中刪除backend 189 backup(file, backend_delete, backend_all_dict) # 調用backup函數,操作文件 190 191 else: # 刪除server 192 server_delete_dict = server_show(backend_delete, backend_all_dict) 193 server_delete_num = int(numif(input("請輸入需要刪除的server編號:"))) # 除判斷是否時數字外,還需轉換為整數型 194 while True: # 刪除backend下的server循環 195 if server_delete_num in server_delete_dict: # 判斷輸入編號是否存在 196 server_delete_dict.pop(server_delete_num) 197 server_delete_dict_backup = {} 198 server_delete_dict_backup[backend_delete] = server_delete_dict.values() 199 backup(file, backend_delete, server_delete_dict_backup) # 調用backup函數,操作文件 200 break 201 else: 202 server_delete_num = input("輸入編號不存在,請重新輸入:") # 提示輸入錯誤 203 204 205 def backup(file,backend_name_action,backend_backup_dict,*backend_name_revise): # 定義文檔備份與回寫功能 206 file_new = "%s_new"%file 207 add_flag = False # 為跳過原backend下server存在 208 with open(file,'r') as f_read , open(file_new,'w+') as f_write: # 同時打開讀文件和寫文件 209 for line in f_read: # 讀取每行信息 210 backend_name = "backend %s" % backend_name_action 211 backend_name_revise = "".join(tuple(backend_name_revise)) # 修改功能會傳參,將元組轉換為字符串 212 if line.strip() == backend_name: # 讀取某行中有參數中的backend 213 if backend_name_action not in backend_backup_dict and backend_name_revise not in backend_backup_dict: # 為了刪除backend而存在 214 add_flag = True 215 pass 216 217 elif backend_name_revise in backend_backup_dict: # 判斷修改功能中修改后backend存在與字典中 218 line_revise = "backend %s\n" % backend_name_revise 219 f_write.write(line_revise) 220 for add_dict in backend_backup_dict[backend_name_revise]: # 逐行讀取修改backend下的server信息 221 server_line_write = '\t\tserver {name} {IP} weight {weight} maxconn {maxconn}\n' 222 f_write.write(server_line_write.format(**add_dict)) # 格式化輸出 223 add_flag = True 224 225 else: 226 f_write.write(line) # 將此行寫在文件中 227 for add_dict in backend_backup_dict[backend_name_action]: # 讀取該backend下所有server信息 228 server_line_write = '\t\tserver {name} {IP} weight {weight} maxconn {maxconn}\n' 229 f_write.write(server_line_write.format(**add_dict)) 230 add_flag = True 231 232 elif line.strip().startswith("server") == True and add_flag == True: # 為了跳過原backend下的server 233 pass 234 235 else: # 寫無用行 236 f_write.write(line) 237 add_flag = False # 寫下無用行后可以繼續循環 238 239 os.system('mv %s %s_backup' % (file, file)) 240 os.system('mv %s %s' % (file_new, file)) 241 242 243 def backend_exit(): #定義退出功能 244 flag_exit = True 245 b_input = input("操作完畢退出請按'b':") 246 while flag_exit: 247 if b_input == 'b': 248 flag_exit = False 249 return flag_exit 250 251 else: 252 return backend_exit() #使用尾遞歸優化,加上return幫助直接退出,而不需要遞歸一層層退出 253 254 255 flag = True # 主函數開始 256 while flag: 257 flag_main = True 258 flag_action = True 259 file = 'haproxy' # 文件名賦值 260 (backend_list, backend_all_dict) = show_list(file) # 調用show_list函數獲取backend和server信息 261 backend_show_dict = backend_show(backend_list) # 展示backend信息 262 action_num = action_list() # 展示功能項,並輸入操作編號 263 while flag_main: 264 if action_num == '1': 265 inquiry(input("請輸入需要查詢的backend編號或名稱:")) 266 flag_main = backend_exit() 267 break 268 269 if action_num == '2': 270 add(input("請輸入需要添加的現有backend編號或新backend名稱:"), file) 271 flag_main = backend_exit() 272 break 273 274 if action_num == '3': 275 revise(input("請輸入需要修改的backend編號或名稱:")) 276 flag_main = backend_exit() 277 break 278 279 if action_num == '4': 280 delete(input("請輸入需要刪除的backend編號或名稱:")) 281 flag_main = backend_exit() 282 break 283 284 if action_num == '5': 285 sys.exit() 286 287 elif action_num not in range(5): # 當輸入不在編號中,提示並重新輸入 288 print("\033[31;1m輸入錯誤請重新輸入!\033[0m") 289 flag_main = False
五.效果圖:
(1)查詢:
in
(2)添加新backend:
(3)添加backend下server:
(4)修改backend:
(5)修改server:
(6)刪除server:
(7)刪除backend: