一、简单介绍

上文我们使用了zabbix的自动发现的监控来监控服务的端口,重点写了zabbix的发现的一个原理和过程,但是实际上我们服务器的配置是比较复杂的,而且之前用的是简单的模拟方式实现的,脚本用的是shell构造成json的,这种不利于维护。下面我们通过线上配置文件来格式化成我们zabbix能够解读的json文件:

二、文件结构分析及思路

首先得先观察游戏服的配置文件结构tree命令,查看我们的配置文件位置

很明显我们的配置文件位于:/datadisk/jh-fw-server_xxxx/config/config.toml目录下

接下来观察配置文件格式:

是典型的key  vlaue结构的配置文件类似于windows的ini文件,思路:我们可以用configparser去读取配置文件信息,然后构造输出json信息

三、开始构造

这次我们使用python脚本,非常之强大的胶水语言。

这次写2个脚本 分别是:配置信息脚本和执行脚本。这样方便扩展,结构灵活!

1.配置信息脚本

# 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.执行脚本


# 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上的监控项,将他们的差集删除掉就行了。

附上脚本内容:

 

<pre>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()</pre>
&nbsp;

&nbsp;

&nbsp;
<pre>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()</pre>
&nbsp;

&nbsp;

&nbsp;

&nbsp;
<pre>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)

</pre>
&nbsp;

 

v2ray

搭建v2ray的步骤大体如下: 购买一个VPS,购买后你会获得VPS的IP、root用户及密码、SSH端口等信息; 登录VPS,可以借助Xshell这个工具; 安装v2ray,使用xsh...

阅读全文

redis的数据库持久化机制

一、redis的 rdb 和 aof 持久化的区别 aof,rdb是两种 redis持久化的机制。用于crash后,redis的恢复。 rdb的特性如下: fork一个进程,遍历hash table,利用...

阅读全文

zabbix–api接口

Zabbix_api4.4官方文档 Zabbix_api3.4中文文档 一、初识api(zabbix4.4.4版本) API(Application Programming Interface,应用程序编程接口)是一些预先定义的...

阅读全文

欢迎留言