0x01 前言

我的zabbix一直使用邮件进行告警,可是邮件告警有将近5分钟的延迟,主要是我的邮箱不支持推送。因此我编写一个简单的python脚本处理zabbix告警信息并转发到其他脚本。

其他脚本可以是调用微信API的脚本,可以是短信平台的API等。但在调用之前需要先处理zabbix发送过来的内容,因为原始内容中很大的一部分是固定的,可以将其替换为中文等。

0x02 准备

首先需要准备zabbix环境,如果你没有做任何修改,那么告警信息是这样的:

Trigger: ngx.hk \u975e200\u54cd\u5e94
Trigger status: OK
Trigger severity: High
Trigger URL: https://ngx.hk

Item values:

1. Response code for step "ngx.hk" of scenario "ngx.hk". (Zabbix server:web.test.rspcode[ngx.hk,ngx.hk]): 200
2. *UNKNOWN* (*UNKNOWN*:*UNKNOWN*): *UNKNOWN*
3. *UNKNOWN* (*UNKNOWN*:*UNKNOWN*): *UNKNOWN*

Original event ID: 3793899

然后需要准备python 3环境。

0x03 脚本

0x03.1 内容替换

根据上面的日志,我们可以将一些内容替换为中文,以下是相关的字典:

# 需要替换的内容
msg_description_mapping_dict = {'Trigger': '触发器',
                                'status': '状态',
                                'severity': '告警等级',
                                'URL': 'URL',
                                'Item values': '触发项目',
                                'Original event ID': '事件ID',
                                'Not classified': '未归类',
                                'Information': '通知',
                                'Warning': '警告',
                                'Average': '中等',
                                'High': '严重',
                                'Disaster': '灾难',
                                'PROBLEM': '异常',
                                'OK': '正常'
                                }

有了字典,我选择用遍历字典的方式替换原始内容:

# 遍历字典,替换内容
for key, values in msg_description_mapping_dict.items():
    msg = msg.replace(key, values)

运行后的内容如下:

MacBook-Air-wifi:~ terence$ python3 /Users/terence/Documents/git_home/zabbix_msg/t1.py '
> Trigger: ngx.hk \u975e200\u54cd\u5e94
> Trigger status: OK
> Trigger severity: High
> Trigger URL: https://ngx.hk
> 
> Item values:
> 
> 1. Response code for step "ngx.hk" of scenario "ngx.hk". (Zabbix server:web.test.rspcode[ngx.hk,ngx.hk]): 200
> 2. *UNKNOWN* (*UNKNOWN*:*UNKNOWN*): *UNKNOWN*
> 3. *UNKNOWN* (*UNKNOWN*:*UNKNOWN*): *UNKNOWN*
> 
> Original event ID: 3793899'



触发器: ngx.hk \u975e200\u54cd\u5e94
触发器 状态: 正常
触发器 告警等级: 严重
触发器 URL: https://ngx.hk

触发项目:

1. Response code for step "ngx.hk" of scenario "ngx.hk". (Zabbix server:web.test.rspcode[ngx.hk,ngx.hk]): 200
2. *UNKNOWN* (*UNKNOWN*:*UNKNOWN*): *UNKNOWN*
3. *UNKNOWN* (*UNKNOWN*:*UNKNOWN*): *UNKNOWN*

事件ID: 3793899

0x03.2 unicode

我在建立自定义zabbix告警Trigger时使用了中文,例如上面日志中的:

Trigger: ngx.hk \u975e200\u54cd\u5e94

将其中unicode编码文字解码后的意思是:

非200响应

这个Trigger是监控我的网站是在线,同时为了方便理解,所以我用中文作为Trigger名。

所以我使用正则将所有unicode编码的字符匹配并编组:

# 匹配unicode的正则
re_pattern = re.compile(r'\\u\w*')
# 找到所有unicode字符并编组
unicode_msg = re_pattern.findall(msg)

这里有个问题,zabbix在将内容发送到自定义脚本前会将字符编码为unicode,这时候python接收到的内容全为字符串,如上面日志所示。需要先将字符串编码再解码,因为字符串不能直接解码:

# 匹配unicode的正则
re_pattern = re.compile(r'\\u\w*')
# 找到所有unicode字符并编组
unicode_msg = re_pattern.findall(msg)

# 将unicode编码为中文并替换掉msg里的unicode
for i in unicode_msg:
    j = i[0:]
    j = j.encode('latin-1').decode('unicode_escape')
    msg = msg.replace(i, j)

运行后的结果如下:

触发器: ngx.hk 非200响应

0x03.3 shell

像这种小脚本,而且参数格式比较单一的脚本,我喜欢用字典传递参数。同时我调用了企业微信的API,所以相关的字典内容如下:

# dict
script_parameter = dict()
script_parameter['corpid'] = corpid
script_parameter['corpsecret'] = corpsecret
script_parameter['msg'] = msg
script_parameter['app_id'] = app_id
script_parameter['group_id'] = group_id

调用微信API时会有回调内容,在这里我使用subprocess进行shell调用,首先要定义命令:

# 定义shell命令
cmd = ['python3', script_path, str(script_parameter)]

然后定义调用subprocess的方法:

# 定义调用shell命令的方法
send_msg = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)

最后是实施:

# 调用shell命令
send_msg_callback, send_msg_err = send_msg.communicate()

因为时间关系,在这里我并没有写回调内容,但在日后会更新。

完整的脚本如下:

#!/usr/bin/python3
# -*- coding=utf-8 -*-

import re
import subprocess
import sys

# 接收传入内容
msg = sys.argv[1]

# 企业ID
corpid = 'your corpid'

# 应用的凭证密钥
corpsecret = 'your corpsecret here'

# 企业应用的id
app_id = 1

# 部门ID
group_id = 1

# 脚本的相对路径
script_path = '/usr/local/shell/wechat_msg/main.py'

# 需要替换的内容
msg_description_mapping_dict = {'Trigger': '触发器',
                                'status': '状态',
                                'severity': '告警等级',
                                'URL': 'URL',
                                'Item values': '触发项目',
                                'Original event ID': '事件ID',
                                'Not classified': '未归类',
                                'Information': '通知',
                                'Warning': '警告',
                                'Average': '中等',
                                'High': '严重',
                                'Disaster': '灾难',
                                'PROBLEM': '异常',
                                'OK': '正常'
                                }

# 遍历字典,替换内容
for key, values in msg_description_mapping_dict.items():
    msg = msg.replace(key, values)

# 匹配unicode的正则
re_pattern = re.compile(r'\\u\w*')
# 找到所有unicode字符并编组
unicode_msg = re_pattern.findall(msg)

# 将unicode编码为中文并替换掉msg里的unicode
for i in unicode_msg:
    j = i[0:]
    j = j.encode('latin-1').decode('unicode_escape')
    msg = msg.replace(i, j)

# dict
script_parameter = dict()
script_parameter['corpid'] = corpid
script_parameter['corpsecret'] = corpsecret
script_parameter['msg'] = msg
script_parameter['app_id'] = app_id
script_parameter['group_id'] = group_id

# 定义shell命令
cmd = ['python3', script_path, str(script_parameter)]

# 定义调用shell命令的方法
send_msg = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)

# 调用shell命令
send_msg_callback, send_msg_err = send_msg.communicate()

0x04 zabbix

完成脚本后需要将脚本上传到zabbix的服务器中,我的路径如下:

[[email protected] ~]# ll /usr/local/shell/zabbix/
总用量 4
-rwx--x--x 1 zabbix zabbix 2142 9月  30 18:04 main.py

需要将脚本赋予可执行权限并将用户修改为zabbix,然后在zabbix控制面板中添加一个Media types:

主要内容如下:

完成Media types的添加后还需要添加用户的告警media:

在控制面板中修改完成后还需要修改zabbix server的配置文件,指定脚本的路径:

#打开文件并编辑
[[email protected] ~]# vim /usr/local/zabbix/etc/zabbix_server.conf

#找到以下内容
AlertScriptsPath=${datadir}/zabbix/alertscripts

#去掉注释符号并修改为
AlertScriptsPath=/usr/local/shell/zabbix

然后重新启动zabbix server即可,因为我的zabbix server是自行编译且没配置管理器,所以只能killall了:

#kill掉所有的服务
[[email protected] ~]# killall zabbix_server

#启动服务
[[email protected] ~]# zabbix_server

0x05 结语

因为可能会有网络故障等意外情况发生,如果需要用在生产环境,建议编写回调与记录相关日志的语句。

如果需要测试也很简单,只需要自定义一个告警项即可。