1-06 348 views
一、简单介绍
上文我们使用了zabbix的自动发现的监控来监控服务的端口,重点写了zabbix的发现的一个原理和过程,但是实际上我们服务器的配置是比较复杂的,而且之前用的是简单的模拟方式实现的,脚本用的是shell构造成json的,这种不利于维护。下面我们通过线上配置文件来格式化成我们zabbix能够解读的json文件:
二、文件结构分析及思路
首先得先观察游戏服的配置文件结构tree命令,查看我们的配置文件位置
很明显我们的配置文件位于:/datadisk/jh-fw-server_xxxx/config/config.toml目录下
接下来观察配置文件格式:
是典型的key vlaue结构的配置文件类似于windows的ini文件,思路:我们可以用configparser去读取配置文件信息,然后构造输出json信息
三、开始构造
这次我们使用python脚本,非常之强大的胶水语言。
这次写2个脚本 分别是:配置信息脚本和执行脚本。这样方便扩展,结构灵活!
1.配置信息脚本monitor_settings.py
# encoding: utf-8 import socket server_path='/datadisk' server_path_file_re='^/datadisk/.*server_[0-9]{1,5}/config/config.toml$' server_path_re='^/datadisk/.*server_[0-9]{1,5}$' #下面server_config_section_option是你要捕捉的端口信息的key,通过这个key去捕捉value server_config_section_option={ 'game':['rpc_addr',], 'gate':['rpc_addr','addr'], 'login':['addr'], 'api':['addr'], '[redis':['addr',] } server_url = "http://10.0.32.22/zabbix/api_jsonrpc.php" header = {"Content-Type": "application/json"} username = "zabbix" password = "123456" def get_host_ip(): ''' 获取服务器的信息 :return: ''' try: host_info={} s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) host_info['host_ip'] = s.getsockname()[0] host_info['host_name']= socket.gethostname() except Exception as e: host_info={} finally: s.close() return host_info host_info=get_host_ip()
2.执行脚本get_monitor_server.py
# encoding: utf-8 import os,sys,json,re,time import monitor_settings #根据不同版本导入configparser if sys.version_info[0] == 2: import ConfigParser as configparser else: import configparser def get_server_list(func_argv_server_path,func_argv_server_path_file_re): #定义一个数组来存放配置文件地址信息 func_server_config_file_list=[] #使用os.walk模块,返回3个值分别是(1.当前正在遍历的这个文件夹的本身的地址,2.内容是一个list是该文件夹中所有的目录的名字(不包括子目录),3.内容同样是list是该文件夹中所有的文件(不包括子目录)) for path_abs,path_list,file_list in os.walk(func_argv_server_path): for file_name in file_list: #匹配配置文件的所在路径,若匹配到了,就将信息加入到数组 if re.findall(r'{}'.format(func_argv_server_path_file_re),os.path.join(path_abs,file_name)): func_server_config_file_list.append(os.path.join(path_abs,file_name)) #返回数组信息 return func_server_config_file_list def get_server_config_values(func_argv_server_config_file_list, func_argv_config_section_option): #实例化一个config对象,config是用于读取配置信息的一个模块 config = configparser.ConfigParser() #定义一个存放你要捕捉端口的数组 server_config_name_port_list=[] for server_config_file_abs in func_argv_server_config_file_list: #切出服务的id server_name_id=server_config_file_abs.split('/')[2] #print(server_config_file_abs) #print(server_name_id) #读取配置文件 config.read(server_config_file_abs) #读取你定义的key1 如(game,gate,redis等) for section in func_argv_config_section_option: # print(section,func_argv_config_section_option[section]) #读取你定义的key2 如(rpc_addr,addr等) for i in func_argv_config_section_option[section]: # print(config.get(section=section,option=i)) #将获取到的信息加入数组,其中一个知识点config.get(section=section,option=i),通过config模块section(key)获取option(value),具体了解<a href="https://www.jianshu.com/p/4f50ce352b2f">config</a>模块 server_config_name_port_list.append({"{#SERVER}":"{}_{}".format(server_name_id,section),"{#PORT}":config.get(section=section,option=i).split(':')[-1].split('"')[0]}) #定义一个字典 server_dict={} #将捕获信息的数组放入字典的data中 server_dict['data']=server_config_name_port_list #返回字典 return server_dict def running(): #获取配置文件的绝对地址(传入的两个参数是服务主目录和文件匹配规则) server_config_file_list = get_server_list(monitor_settings.server_path, monitor_settings.server_path_file_re) # print server_config_file_list #通过配置文件获取json信息(传入的两个参数是配置文件地址数组信息和你要捕捉的key的信息) server_dict=get_server_config_values(server_config_file_list, monitor_settings.server_config_section_option) #用json模式输出字典 print(json.dumps(server_dict, indent=4)) if __name__ == '__main__': running()
执行结果:
输出类似这种json,既可以让zabbix去发现你的监控项了。当前你要先设置好自动发现规则!
若你按之前上文一样配置好自动发现规则,结果就好如下显示:
既然能自动发现监控项,那比如游戏合服了,监控项不存在了,我们总不能手动去删除监控项吧,下面介绍自动删除不存在的监控项:
有3个py文件组成
get_monitor_server.py 就是上面get_server.py,只是换了个名称,它的作用就是获取现在真实有效的监控项(无用的监控项,再合服之后,游戏服目录肯定重命名了,所以不会再获取到)
monitor_settings.py zabbix的一些配置信息
delete_useless_server_monitor.py 自动删除不存在的监控项(主菜)
大致逻辑:通过比对get_monitor_server.py 获取的真实有效的监控项与zabbix上的监控项,将他们的差集删除掉就行了。
附上脚本内容:
脚本1 monitor_settings.py # encoding: utf-8 import socket server_path='/data' server_path_file_re='^/data/.*server_[0-9]{1,5}/config/config.toml$' server_path_re='^/data/.*server_[0-9]{1,5}$' #下面server_config_section_option是你要捕捉的端口信息的key,通过这个key去捕捉value server_config_section_option={ 'game':['rpc_addr',], 'gate':['rpc_addr','addr'], 'login':['addr'], 'api':['addr'], '[redis':['addr',] } server_url = "http://192.168.122.11/zabbix/api_jsonrpc.php" header = {"Content-Type": "application/json"} username = "Admin" password = "zabbix" def get_host_ip(): ''' 获取服务器的信息 :return: ''' try: host_info={} s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) host_info['host_ip'] = s.getsockname()[0] host_info['host_name']= socket.gethostname() except Exception as e: host_info={} finally: s.close() return host_info host_info=get_host_ip() 脚本2 get_monitor_server.py # encoding: utf-8 #用于自动发现监控项 import os,sys,json,re,time import monitor_settings #根据不同版本导入configparser if sys.version_info[0] == 2: import ConfigParser as configparser else: import configparser def get_server_list(func_argv_server_path,func_argv_server_path_file_re): #定义一个数组来存放配置文件地址信息 func_server_config_file_list=[] #使用os.walk模块,返回3个值分别是(1.当前正在遍历的这个文件夹的本身的地址,2.内容是一个list是该文件夹中所有的目录的名字(不包括子目录),3.内容同样是list是该文件夹中所有的文件(不包括子目录)) for path_abs,path_list,file_list in os.walk(func_argv_server_path): for file_name in file_list: #匹配配置文件的所在路径,若匹配到了,就将信息加入到数组 if re.findall(r'{}'.format(func_argv_server_path_file_re),os.path.join(path_abs,file_name)): func_server_config_file_list.append(os.path.join(path_abs,file_name)) #返回数组信息 return func_server_config_file_list def get_server_config_values(func_argv_server_config_file_list, func_argv_config_section_option): #实例化一个config对象,config是用于读取配置信息的一个模块 config = configparser.ConfigParser() #定义一个存放你要捕捉端口的数组 server_config_name_port_list=[] for server_config_file_abs in func_argv_server_config_file_list: #切出服务的id server_name_id=server_config_file_abs.split('/')[2] #print(server_config_file_abs) #print(server_name_id) #读取配置文件 config.read(server_config_file_abs) #读取你定义的key1 如(game,gate,redis等) for section in func_argv_config_section_option: # print(section,func_argv_config_section_option[section]) #读取你定义的key2 如(rpc_addr,addr等) for i in func_argv_config_section_option[section]: # print(config.get(section=section,option=i)) #将获取到的信息加入数组,其中一个知识点config.get(section=section,option=i),通过config模块section(key)获取option(value),具体了解<a href="https://www.jianshu.com/p/4f50ce352b2f">config</a>模块 server_config_name_port_list.append({"{#SERVER}":"{}_{}".format(server_name_id,section),"{#PORT}":config.get(section=section,option=i).split(':')[-1].split('"')[0]}) #定义一个字典 server_dict={} #将捕获信息的数组放入字典的data中 server_dict['data']=server_config_name_port_list #返回字典 return server_dict def running(): #获取配置文件的绝对地址(传入的两个参数是服务主目录和文件匹配规则) server_config_file_list = get_server_list(monitor_settings.server_path, monitor_settings.server_path_file_re) #print server_config_file_list #通过配置文件获取json信息(传入的两个参数是配置文件地址数组信息和你要捕捉的key的信息) server_dict=get_server_config_values(server_config_file_list, monitor_settings.server_config_section_option) #用json模式输出字典 print(json.dumps(server_dict, indent=4)) if __name__ == '__main__': running() 脚本3 delete_useless_server_monitor.py #!/usr/bin/env python36 # encoding: utf-8 #用于删除被合服后遗留的自动发现的监控项 import requests, json,re,os,sys,traceback import get_monitor_server,monitor_settings def send_weixin(func_argv_content): import requests url='https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=wwa28310f4ff14cd76&corpsecret=HZ2imHCjTLnNjWAD79U8K7vTHp6TmXbNiDUT5sxdSGU' r1 = requests.get(url) a=json.loads(r1.content) r2 = requests.post(url='https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={}'.format(a['access_token']), data=json.dumps({ "toparty": "2", "msgtype": "text", "agentid": 1000002, "text": { "content": "{}".format(json.dumps(func_argv_content)) }, "safe": "0" })) return r2 def get_host_ip(): ''' 获取服务器的ip :return: ''' import socket try: host_info={} s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 80)) host_info['host_ip'] = s.getsockname()[0] host_info['host_name']= socket.gethostname() except Exception as e: print(traceback.format_exc()) finally: s.close() return host_info def zabbix_login(func_argv_server_url,func_argv_header,func_argv_username,func_argv_password): ''' 获取zabbix的认证信息 :param func_argv_server_url: zabbix url的api :param func_argv_header: 头信息 :param func_argv_username: zabbix登录的用户名 :param func_argv_password: zabbix密码 :return: 返回认证信息 ''' # 登录zabbix并获取auth的token login = { "jsonrpc": "2.0", "method": "user.login", "params": { "user": func_argv_username, "password": func_argv_password }, "auth":None, "id": 1 } auth = requests.post(func_argv_server_url, data=json.dumps(login), headers=func_argv_header) auth_ret=json.loads(auth.text) return auth_ret def zabbix_get_hostid(func_argv_auth,func_argv_server_url,func_argv_header): ''' # 根据服务器名获取hostid :param func_argv_auth: zabbix认证信息 :return: 返回获取的主机信息 ''' host_get = { "jsonrpc": "2.0", "method": "host.get", "params": { "output": "extend", "filter": { "host": [ monitor_settings.host_info['host_name'] ] } }, "auth": func_argv_auth['result'], "id": 1 } hostid_get = requests.post(func_argv_server_url,data=json.dumps(host_get),headers=func_argv_header) hostid_get_ret=hostid_get.json() #hostid_get_ret['result']=[{u'available': u'1', u'tls_connect': u'1', u'maintenance_type': u'0', u'ipmi_errors_from': u'0', u'ipmi_username': u'', u'snmp_disable_until': u'0', u'ipmi_authtype': u'-1', u'ipmi_disable_until': u'0', u'lastaccess': u'0', u'snmp_error': u'', u'tls_psk': u'', u'ipmi_privilege': u'2', u'jmx_error': u'', u'jmx_available': u'0', u'maintenanceid': u'0', u'snmp_available': u'0', u'proxy_address': u'', u'tls_psk_identity': u'', u'status': u'0', u'description': u'', u'tls_accept': u'1', u'auto_compress': u'1', u'host': u'co5 server', u'disable_until': u'0', u'ipmi_password': u'', u'templateid': u'0', u'tls_issuer': u'', u'ipmi_available': u'0', u'maintenance_status': u'0', u'snmp_errors_from': u'0', u'ipmi_error': u'', u'proxy_hostid': u'0', u'hostid': u'10262', u'name': u'co5 server', u'jmx_errors_from': u'0', u'jmx_disable_until': u'0', u'flags': u'0', u'error': u'', u'maintenance_from': u'0', u'tls_subject': u'', u'errors_from': u'0'}] return hostid_get_ret def zabbix_get_items(func_argv_auth, func_argv_hostid,func_argv_server_url,func_argv_header): ''' 获取主机的监控项目 :param func_argv_auth: zabbix的认证信息 :param func_argv_hostid: 主机信息 :return: ''' items_get = { "jsonrpc": "2.0", "method": "item.get", "params": { "output": "extend", "hostids": "{}".format(func_argv_hostid['result'][0]['hostid']), "sortfield": "name" }, "auth": func_argv_auth['result'], "id": 1 } items_info_get = requests.post(func_argv_server_url,data=json.dumps(items_get),headers=func_argv_header) items_info_get_ret = items_info_get.json() items_list = items_info_get_ret['result'] func_server_items_dict={} for i in items_list: item_name=i['name'] if re.findall(r'^Listen SERVER \[',item_name): func_server_items_dict['-'.join([item_name.split()[2].strip('[').strip(']'),i['itemid']])]=i['itemid'] return func_server_items_dict def get_delete_server_monitor_info(func_argv_server_items_dict, func_argv_server_info_values_dict): ''' 返回要删除的监控项列表 :param func_argv_server_items_dict: 主机的监控项字典 :param func_argv_server_info_values_dict: 主机的所有游戏服的配置监控项字典 :return: 返回要删除的监控项列表 ''' func_server_config_monitor_list = [] func_delete_server_monitor_list = [] func_delete_server_monitor_dict = {} for i in func_argv_server_info_values_dict['data']: func_server_config_monitor_list.append(i['{#SERVER}']) for keys in func_argv_server_items_dict: #去除掉keys最后的id,例如keys='jh-wb-server_1001_gate-73664',最后构造成keys='jh-wb-server_1001_gate' if '-'.join(keys.split('-')[0:-1]) in func_server_config_monitor_list: pass else: # func_delete_server_monitor_dict={u'server_1002_api-28823': u'28823', u'server_1002_[redis-28825': u'28825',u'server_1002_login-28824': u'28824', u'server_1002_game-28822': u'28822',u'server_1002_gate-28820': u'28820',u'server_1002_gate-28821': u'28821'} func_delete_server_monitor_dict[keys] = func_argv_server_items_dict[keys] func_delete_server_monitor_list.append(func_argv_server_items_dict[keys]) print('#'*120) print('要删除的监控项:{}'.format(func_delete_server_monitor_dict)) return func_delete_server_monitor_list def delete_server_monitor_items(func_argv_auth,func_argv_server_url,func_argv_header,func_delete_server_monitor_list): ''' 删除监控项 :param func_argv_auth: 认证信息 :param func_argv_server_url: zabbix的api接口url :param func_argv_header: 头信息 :param func_delete_server_monitor_list:要删除的监控项列表 :return: ''' if func_delete_server_monitor_list: items_delete = { "jsonrpc": "2.0", "method": "item.delete", "params": func_delete_server_monitor_list, "auth": func_argv_auth['result'], "id": 1 } items_info_get = requests.post(func_argv_server_url, data=json.dumps(items_delete), headers=func_argv_header) items_info_get_ret = items_info_get.json() items_list = items_info_get_ret['result'] print('已经删除的监控项:{}'.format(items_list)) mes['delete_items'] = items_list send_weixin(mes) else: print('没有要删除的监控项:{}'.format(func_delete_server_monitor_list)) def running(): auth_dict = zabbix_login(monitor_settings.server_url,monitor_settings.header,monitor_settings.username,monitor_settings.password) hostid_get_dict = zabbix_get_hostid(auth_dict,monitor_settings.server_url,monitor_settings.header) server_items_dict=zabbix_get_items(auth_dict, hostid_get_dict,monitor_settings.server_url,monitor_settings.header) server_config_file_list = get_monitor_server.get_server_list(monitor_settings.server_path, monitor_settings.server_path_file_re) server_info_values_dict = get_monitor_server.get_server_config_values(server_config_file_list, monitor_settings.server_config_section_option) delete_server_monitor_list=get_delete_server_monitor_info(server_items_dict,server_info_values_dict) delete_server_monitor_items(auth_dict,monitor_settings.server_url,monitor_settings.header,delete_server_monitor_list) if __name__ == '__main__': host_info = get_host_ip() mes = {} mes['host_info'] = host_info mes['data'] = 'zabbix delete userless server monitor' try: running() except Exception: mes['error']=traceback.format_exc() send_weixin(mes)