1 #!/usr/bin/env python 2 import os,sys,time,re,prettytable,json 3 from collections import defaultdict,OrderedDict 4 conf='haproxy.cfg' ###指定haproxy配置文件### 5 jgf='' 6 ######################1.input輸入字符類型轉化函數####################### 7 def input_handle(s): 8 if str.isdigit(s): ###對輸入是不是數字進行判斷### 9 s = int(s) ###若是輸出的是個數字,則轉化爲整數類型### 10 return s ###返回輸入字符### 11 12 ###########################2.backend列表展現函數############################ 13 def backend_read(conf): 14 backend_list = [] ###初始化backend的列表### 15 show_dict = {} ###初始化要返回的顯示字典### 16 backend_name_dict = defaultdict(list) ###定義一個value爲列表的字典,用來存放server### 17 server_flag = False ###初始化server判斷標誌位### 18 with open(conf,'r') as ha: ###打開haproxy配置文件### 19 for line in ha: 20 server_dict = OrderedDict() ###定義一個有序字典### 21 line = line.strip('\n') 22 #狀況1 23 if re.match('backend',line): ###匹配配置文件以backend開頭的行### 24 backend_name = re.split('\s+',line)[1] 25 backend_list.append(backend_name) ###將配置到的backend的名稱插入到列表### 26 server_flag = True ###賦值標誌位爲真,用來與server關聯### 27 #狀況2 28 elif server_flag and re.match('\s+server',line): ###匹配配置文件以server開頭的行### 29 server_info = re.split('\s+',line) ###對server進行分隔### 30 server_dict['name'] = server_info[2] ###對server的具體信息進行字典賦值### 31 server_dict['address'] = server_info[3] 32 server_dict['weight'] = server_info[5] 33 server_dict['maxconn'] = server_info[7] 34 backend_name_dict[backend_name].append(server_dict) ###將server字典與backend的名稱進行關聯### 35 else: 36 server_flag = False ###當server沒匹配到,賦值標誌位爲假,結束關聯### 37 for k,v in enumerate(backend_list,1): 38 show_dict[k] = v ###對backend名稱進行新字典賦值,方便查詢和展現### 39 print('%d . %s' % (k,v)) ###輸出backend列表### 40 return(show_dict,backend_name_dict) ###返回顯示的字典和backend-server字典### 41 42 ########################3.顯示server服務器函數############################# 43 def backend_server_show(backend_show_value,server_show_dict): 44 ############對backend名稱進行遍歷並加上數字編號########################### 45 print(jgf.center(70,'=')) 46 print('\033[1m後端服務器(%s)信息以下:\033[0m'%backend_show_value) 47 print('%-20s %-20s %-20s %-20s'%('name','address','weight','maxconn')) 48 server_list = server_show_dict[backend_show_value] 49 for v in server_list: ###用enumerate進行server展現### 50 n=list(v.values()) 51 print('\033[32;40m%-5s%20s%15s%25s\033[1m'%(n[0],n[1],n[2],n[3])) 52 print(jgf.center(60, '=')) 53 54 #####################4.名稱輸入判斷函數############################# 55 def name_decide(): 56 (name,name_flag) = ('',True) ###初始化返回的名稱和判斷標誌位### 57 while name_flag: 58 name_input = input('\033[32m請輸入新服務名(退出輸入q):\033[0m') 59 if len(name_input) == 0: ###若是輸入爲空則直接下一次循環### 60 continue 61 elif name_input == 'q': ###輸入q,退出本次輸入### 62 name_flag = False 63 sys.exit('\033[32;1m腳本已退出!\033[1m') 64 elif re.match('[0-9a-zA-Z\_]+',name_input): ###匹配輸入是否以字符、數字或下劃線開頭### 65 name = name_input 66 name_flag = False ###輸入成功後退出循環### 67 else: 68 print('\033[31m名稱輸入錯誤,請從新輸入!!!\033[0m') 69 break 70 return(name) ###返回輸入的結果### 71 #####################5.IP地址及端口輸入判斷函數############################# 72 def ipaddress_decide(): 73 (address,address_flag) = ('',True) ###初始化返回的IP地址和判斷標誌位### 74 while address_flag: 75 address_input = input('\033[32m請輸入新地址(IP哦)(退出輸入q):\033[0m') 76 if len(address_input) == 0: ###若是輸入爲空則直接下一次循環### 77 continue 78 elif address_input == 'q': ###輸入q,退出本次輸入### 79 address_flag = False 80 sys.exit('\033[32;1m腳本已退出!\033[1m') 81 ##################匹配輸入是不是ip:port的格式###################### 82 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): 83 address = address_input 84 address_flag = False ###輸入成功後退出循環### 85 else: 86 print('\033[31m地址輸入錯誤,請從新輸入!!!\033[0m') 87 return(address) ###返回輸入的結果### 88 89 ####################6.數字輸入判斷函數###################################### 90 def number_decide(name): 91 (number,number_flag) = ('',True) ###初始化返回的數字和判斷標誌位### 92 while number_flag: 93 number_input =input('\033[32m請輸入%s(數字哦)(退出輸入q):\033[0m' % name) 94 if len(number_input) == 0: ###若是輸入爲空則直接下一次循環### 95 continue 96 elif number_input == 'q': ###輸入q,退出本次輸入### 97 number_flag = False 98 sys.exit('\033[32;1m腳本已退出!\033[32;1m') 99 else: 100 try: 101 int(number_input) ###匹配輸入是不是數字### 102 except: 103 print('\033[31;1m%s輸入類型錯誤,請從新輸入!!!\033[0m'%name) 104 else: 105 number = number_input 106 number_flag = False ###輸入成功後退出循環### 107 return(number) ###返回輸入的結果### 108 109 #############################7.節點輸入判斷函數########################## 110 def backend_input_if(input_index,input_dict): 111 (input_name,input_flag) = ('',True) ###初始化返回的名稱和判斷標誌位### 112 ###############若是輸入非空,對輸入進行判斷並轉化類型################# 113 if len(input_index) != 0: 114 input_index = input_handle(input_index) 115 if input_index == 'b': ###若是輸入爲b,則退出程序### 116 input_flag = False 117 elif input_index in input_dict.keys(): ###若是輸入爲數字編號,則從字典中獲取具體backend名稱### 118 input_name = input_dict[input_index] 119 elif input_index in input_dict.values(): ###若是輸入爲backend名稱,則直接獲取### 120 input_name = input_index 121 else: 122 input_name = '' ###輸入其餘字符,賦值變量爲空### 123 return(input_name,input_flag) ###返回輸入的結果和循環標誌位### 124 125 ########################8.配置文件操做函數################# 126 def backend_server_handle(conf,handle_dict): 127 newfile = '%s.new'%conf ###定義回寫的新文件### 128 server_flag = False 129 with open(conf,'r') as read_file,open(newfile,'w') as write_file: ###同時打開二文件,一個讀,一個寫### 130 for line in read_file: 131 if re.match('backend',line): ###匹配到backend行時進行server信息插入### 132 write_file.write(line) 133 backend_name = re.split('\s+',line)[1] 134 for server_dict in handle_dict[backend_name]: ###對backend-server字典進行遍歷### 135 server_line = '\tserver {name} {address} weight {weight} maxconn {maxconn}\n' 136 write_file.write(server_line.format(**server_dict)) ###將指定的backend下的server條目插入文件### 137 138 server_flag = True ###指定標誌位爲真,方便server判斷### 139 elif server_flag and re.match('\s+server',line): ###匹配server開頭的行,跳過不作任何操做### 140 pass 141 else: 142 write_file.write(line) ###其餘的行,直接插入新文件### 143 server_flag = False 144 print('\033[33;1m server更新成功\033[0m') 145 os.system('mv %s %s.bak'%(conf,conf)) ###對源配置文件進行備份### 146 os.system('mv %s %s'%(newfile,conf)) ###對新生成的配置文件進行更名### 147 148 ##################################主程序開始################################## 149 if __name__ == '__main__': 150 flag = True 151 backend_name = '' 152 haproxy_name_show_dict = {} ###初始化backend顯示字典### 153 haproxy_server_show_dict = {} ###初始化server顯示字典### 154 while flag: 155 print(jgf.center(60,'=')) 156 hy='\033[36m歡迎訪問haproxy配置文件管理腳本\033[0m' 157 print(hy.center(60,'*')) 158 print('\033[1mbackend列表信息以下:') 159 (haproxy_name_show_dict,haproxy_server_show_dict) = backend_read(conf) 160 print(jgf.center(50,'=')) 161 time.sleep(1) 162 print(''' 163 \033[35;1m1.查詢後端服務\033[0m 164 \033[35;1m 2.添加後端服務\033[0m 165 \033[35;1m 3.修改後端服務\033[0m 166 \033[31;1m 4.刪除後端服務\033[0m 167 \033[32;1m 5.退出\033[0m ''') 168 print(jgf.center(60,'=')) 169 select_num = input('\033[35;1m請選擇操做條目:\033[0m') 170 171 #######################1. 查詢後端服務################################ 172 if select_num == '1': 173 query_flag = True ###初始化查詢循環標誌### 174 while query_flag: 175 backend_index =input('\033[31;1m請輸入須要查詢的backend編號或名稱(返回上級菜單輸入b,退出輸入q):\033[0m') 176 177 ##############################對輸入值進行判斷################ 178 (backend_name,query_flag) = backend_input_if(backend_index,haproxy_name_show_dict) 179 if backend_name: ###顯示對應backend下的server列表### 180 backend_server_show(backend_name,haproxy_server_show_dict) 181 elif backend_index=='b': 182 break 183 elif backend_index=='q': 184 sys.exit('\033[35;1m腳本退出!\033[0m') 185 else: 186 query_flag=False 187 print('\033[31;1m您輸入的節點不存在!請從新輸入!') 188 time.sleep(1) 189 190 #######################2. 添加後端服務################################ 191 if select_num == '2': 192 add_flag = True ###初始化添加循環標誌### 193 while add_flag: 194 backend_index =input('\033[32;1m請輸入添加的backend的編號或名稱(返回上級菜單,請輸入b):\033[0m') 195 ##############################對輸入值進行判斷################ 196 (backend_name,add_flag) = backend_input_if(backend_index,haproxy_name_show_dict) 197 if backend_name: ###顯示對應backend下的server列表### 198 backend_server_show(backend_name,haproxy_server_show_dict) 199 add_server_dict = OrderedDict() ###設置實例默認爲有序字典 200 print('\033[34;1m請依次輸入後端服務信息(name,address,weight,maxconn):\033[0m') 201 add_server_dict['name'] = name_decide() ###對輸入的name有效性進行判斷### 202 add_server_dict['address'] = ipaddress_decide() ###對輸入的IP有效性進行判斷### 203 add_server_dict['weight'] = number_decide('權重值') ###對輸入的權重有效性進行判斷### 204 add_server_dict['maxconn'] = number_decide('最大鏈接數') ###對輸入的鏈接數有效性進行判斷### 205 206 print(add_server_dict['name'],add_server_dict['address'],add_server_dict['weight'],add_server_dict['maxconn']) 207 208 #############對輸入的四個服務信息是否成功判斷############# 209 if add_server_dict['name'] and add_server_dict['address'] and add_server_dict['weight'] and add_server_dict['maxconn']: 210 add_commit = input('\033[31;1m請確認是否添加此條目(y | n):\033[0m') 211 if add_commit == 'y': ###確認添加服務條目,並回寫配置文件### 212 haproxy_server_show_dict[backend_name].append(add_server_dict) 213 backend_server_handle(conf,haproxy_server_show_dict) 214 else: 215 add_flag = False ###不然退出本次循環### 216 else: 217 print('\033[1;31m server信息輸入有誤,請從新輸入!!!\033[0m') 218 time.sleep(2) 219 220 #######################3. 修改後端服務################################# 221 if select_num == '3': 222 backend_modify_flag = True ###初始化修改循環標誌### 223 while backend_modify_flag: 224 backend_index =input('\033[32;1m請輸入修改的backend的編號或名稱(返回上級菜單,請輸入b):\033[0m') 225 ##############################對輸入值進行判斷################ 226 (backend_name,backend_modify_flag) = backend_input_if(backend_index,haproxy_name_show_dict) 227 228 if backend_name: ###顯示對應backend下的server列表### 229 backend_server_show(backend_name,haproxy_server_show_dict) 230 231 server_modify_flag = True ###初始化server條目修改標誌位### 232 while server_modify_flag: 233 234 server_index =input('\033[32;1m請輸入修改的server的編號(返回上級菜單,請輸入b):\033[0m') 235 if len(server_index) != 0: 236 server_index = input_handle(server_index) 237 if server_index == 'b': ###輸入b,返還上一層### 238 server_modify_flag = False 239 #####################指定具體的server編號進行判斷##### 240 elif server_index >= 1 and server_index <= len(haproxy_server_show_dict[backend_name]): 241 modify_server_dict = OrderedDict() 242 print('\033[34;1m請依次輸入後端服務信息(name,address,weight,maxconn):\033[0m') 243 modify_server_dict['name'] = name_decide() ###對輸入的四個信息有效性進行判斷### 244 modify_server_dict['address'] = ipaddress_decide() 245 modify_server_dict['weight'] = number_decide('權重值') 246 modify_server_dict['maxconn'] = number_decide('最大鏈接數') 247 248 print(modify_server_dict['name'],modify_server_dict['address'],modify_server_dict['weight'],modify_server_dict['maxconn']) 249 250 ######對輸入的四個服務信息是否成功判斷############# 251 if modify_server_dict['name'] and modify_server_dict['address'] and modify_server_dict['weight'] and modify_server_dict['maxconn']: 252 modify_commit =input('\033[32;1m請確認是否修改此條目(y|n):\033[1m') 253 if modify_commit == 'y': ###確認修改服務條目,並回寫配置文件### 254 haproxy_server_show_dict[backend_name][server_index - 1] = modify_server_dict 255 backend_server_handle(conf,haproxy_server_show_dict) 256 modify_server_flag = False 257 258 else: ###不然退出本次循環### 259 modify_server_flag = False 260 else: 261 print('\033[31m server輸入信息有誤,請從新輸入!!!\033[0m') 262 else: 263 print('\033[31m server編號輸入錯誤,請從新輸入!!!\033[0m') 264 265 #######################4. 刪除後端服務################################ 266 if select_num == '4': 267 backend_delete_flag = True ###初始化刪除循環標誌### 268 while backend_delete_flag: 269 backend_index =input('\033[32;1m請輸入刪除的backend下條目編號或名稱(返回上層菜單,請輸入b):\033[0m') 270 ##############################對輸入值進行判斷################ 271 (backend_name,backend_delete_flag) = backend_input_if(backend_index,haproxy_name_show_dict) 272 273 if backend_name: ###顯示對應backend下的server列表### 274 backend_server_show(backend_name,haproxy_server_show_dict) 275 276 server_delete_flag = True ###初始化server條目刪除標誌位### 277 while server_delete_flag: 278 279 server_index =input('\033[32;1m請輸入要刪除的server編號(返回上層菜單,請輸入b):\033[0m') 280 if len(server_index) != 0: 281 server_index = input_handle(server_index) 282 if server_index == 'b': ###輸入b,返還上一層### 283 server_delete_flag = False 284 #####################指定具體的server編號進行判斷##### 285 elif server_index >= 1 and server_index <= len(haproxy_server_show_dict[backend_name]): 286 287 print(haproxy_server_show_dict[backend_name][server_index - 1]) 288 delete_commit =input('請確認是否刪除此條目(y|n):') 289 if delete_commit == 'y': ###確認刪除服務條目,並回寫配置文件### 290 del haproxy_server_show_dict[backend_name][server_index - 1] 291 backend_server_handle(conf,haproxy_server_show_dict) 292 delete_server_flag = False 293 294 else: ###不然退出本次循環### 295 delete_server_flag = False 296 else: 297 print('\033[31m server編號輸入錯誤,請從新輸入!!!\033[0m') 298 299 #######################5. 退出程序###################### 300 if select_num == '5': 301 print('\033[31;1m程序將在兩秒後退出,歡迎再次使用,謝謝!\033[0m') 302 time.sleep(1) 303 print('\033[32;1m1s\033[0m') 304 time.sleep(1) 305 print('\033[32;1m2s\033[0m') 306 print('\033[31;1m程序退出') 307 sys.exit()