对haproxy配置文件进行操作
要求:
对haproxy配置文件中backend下的server实现增删改查的功能
一、这个程序有二个版本
1、 python2.7版本见haproxy_python27.py
2、 python3.4版本见haproxy_python34.py
二、具体实现了如下功能:
1、输入1,进入backend菜单,查询server信息
2、输入2,进入backend菜单,添加server条目
3、输入3,进入backend菜单,选择server条目,进入修改环节
4、输入4,进入backend菜单,选择server条目,进入删除环节
5、输入5,退出程序
三、haproxy配置文件如下:
global
log 127.0.0.1 local2 daemon maxconn 256 log 127.0.0.1 local2 info defaults log global mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms option dontlognull listen stats :8888 stats enable stats uri /admin stats auth admin:1234 frontend oldboy bind 0.0.0.0:80 option httplog option httpclose option forwardfor log global acl www hdr_reg(host) -i www.oldboy.org use_backend www.oldboy.org if www backend www.oldboy.org server 100.1.7.9 100.1.7.9 weight 20 maxconn 3000 server 100.1.7.10 100.1.7.10 weight 10 maxconn 2000 frontend mysql bind *:3306 mode tcp log global default_backend mysqlserver backend mysqlserver server mysql1 10.1.1.110:3306 weight 20 maxconn 300 server mysql2 10.1.1.120:3306 weight 10 maxconn 200 haproxy配置文件
四、流程图如下:
五、python2.7代码:
#!/usr/bin/python27
#_*_ coding=utf-8 _*_ import os,sys,re,time from collections import defaultdict,OrderedDict ######################raw_input输入字符类型转化函数####################### def input_handle(s): if str.isdigit(s): ###对输入是否是数字进行判断### s = int(s) ###如果输出的是个数字,则转化为整数类型### return s ###返回输入字符### #####################名称或变量名输入判断函数############################# def name_decide(): (name,name_flag) = ('',True) ###初始化返回的名称和判断标志位### while name_flag: name_input = raw_input('\033[32m请输入新服务名:(退出输入q)\033[0m') if len(name_input) == 0: ###如果输入为空则直接下一次循环### continue elif name_input == 'q': ###输入q,退出本次输入### name_flag = False elif re.match('[0-9a-zA-Z\_]+',name_input): ###匹配输入是否以字符、数字或下划线开头### name = name_input name_flag = False ###输入成功后退出循环### else: print('\033[31m名称输入错误,请重新输入!!!\033[0m') return(name) ###返回输入的结果### #####################IP地址及端口输入判断函数############################# def ipaddress_decide(): (address,address_flag) = ('',True) ###初始化返回的IP地址和判断标志位### while address_flag: address_input = raw_input('\033[32m请输入新地址(IP哦):(退出输入q)\033[0m') if len(address_input) == 0: ###如果输入为空则直接下一次循环### continue elif address_input == 'q': ###输入q,退出本次输入### address_flag = False ##################匹配输入是否是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) ###返回输入的结果### ####################数字输入判断函数###################################### def number_decide(name): (number,number_flag) = ('',True) ###初始化返回的数字和判断标志位### while number_flag: number_input = raw_input('\033[32m请输入 %s (数字哦):(退出输入q)\033[0m' % name) if len(number_input) == 0: ###如果输入为空则直接下一次循环### continue elif number_input == 'q': ###输入q,退出本次输入### number_flag = False else: try: int(number_input) ###匹配输入是否是数字### except: print('\033[31m %s 输入错误,请重新输入!!!\033[0m' % name) else: number = number_input number_flag = False ###输入成功后退出循环### return(number) ###返回输入的结果### #############################backend输入判断函数########################## 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) ###返回输入的结果和循环标志位### ###########################backend列表展示函数############################ def backend_read(file): backend_list = [] ###初始化backend的列表### show_dict = {} ###初始化要返回的显示字典### backend_name_dict = defaultdict(list) ###定义一个value为列表的字典,用来存放server### server_flag = False ###初始化server判断标志位### with open(file,'r') as ha: ###打开haproxy配置文件### for line in ha: server_dict = OrderedDict() ###定义一个有序字典### line = line.strip('\n') if re.match('backend',line): ###匹配配置文件以backend开头的行### backend_name = re.split('\s+',line)[1] backend_list.append(backend_name) ###将配置到的backend的名称插入到列表### server_flag = True ###赋值标志位为真,用来与server关联### 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字典### ########################显示backend后端服务器函数############################# def backend_server_show(backend_show_value,server_show_dict): ############对backend名称进行遍历并加上数字编号########################### print('\n================================================================') print('后端服务器(%s)信息如下 : ' % backend_show_value) print('%-5s %-20s %-20s %-20s %-20s' % ('id','name','address','weight','maxconn')) server_list = server_show_dict[backend_show_value] for k,v in enumerate(server_list,1): ###用enumerate进行server展示### print '%-5s' % k + ' ', for kk,vv in v.items(): print '%-20s' % vv + ' ', print print('\n================================================================') ########################backend后端服务操作并回写配置文件函数################# def backend_server_handle(file,handle_dict): newfile = '%s.new' % file ###定义回写的新文件### server_flag = False with open(file,'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[33m server更新成功\033[0m') os.system('mv %s %s.bak' % (file,file)) ###对源配置文件进行备份### os.system('mv %s %s' % (newfile,file)) ###对新生成的配置文件进行改名###