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()