环境

  • CentOS7
  • Yum 安装的 zabbix4.2.5
  • 企业微信信息:
    • 企业 ID: aabbccdd0011223344
    • 自建应用的 ID: 100002
    • 自建应用的密钥: AAAABBBB11112222ccccddddd_eeeeffff000011111
    • 设置该自建应用对人员”刘涛(帐号: LiuTao)“和部门”运维部(ID: 2)“可见

部署脚本

  • 创建 /usr/lib/zabbix/alertscripts/wechat.py,内容如下

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    
    #!/usr/bin/python3
    # _*_ coding:utf-8 _*_
    
    
    import requests
    import time
    import json
    import sys
    
    
    class Wechat(object):
        def __init__(self,overdue, tkpath, tktime, touser, toparty, corpid, corpsecret, agentid, content):
            # 消息接收者
            self.touser = touser
            # 部门ID列表
            self.toparty = toparty
            # token路径(首先从文件读取token,如果没有就get_token)
            self.tkpath = tkpath
            # 上次请求Token的时间存放的路径(时间戳)
            self.tktime = tktime
            # Token过期时间,期间内获取的Token是一样的
            self.overdue = overdue
            # 当前时间戳
            self.nowtime = int(time.time())
            # 企业ID
            self.corpid  = corpid
            # 管理组凭证
            self.corpsecret = corpsecret
            # 自建的程序管理ID
            self.agentid = agentid
            # 发送的内容
            self.content = content
            # 请求的AccessToken
            self.token = self.read_token()
    
        def read_token(self):
            try:
                self.token = str(open(self.tkpath,'r+').read())            # 读取token
                self.times = int(float(open(self.tktime,"r+").read()))     # 读取时间戳(需转换为整型)
                self.times = self.nowtime - self.times                     # 时间差(当前时间-上次时间)
                if self.times >= self.overdue:                             # 如果过期就重新请求Token(超过7200)
                    self.token = self.get_token()                          # 调用get_token方法重新获取
                    return self.token
                else:
                    return self.token       # 否则直接返回读取到token
            except IOError:
                self.token = self.get_token()                       # 如果读取失败证明没请求过(第一次请求)
                return self.token
        """
            该read_token方法的逻辑是:
            (1)读取token文件和times文件。如果出错代表是第一次运行此脚本(或被误删)
                1. 发起新的请求,获取token
                2. 最后返回请求到的token
            (2)读取token文件和time文件。没有错误就进行时间的相减
                1. 企业微信API在7200内请求的token是相同的。
                2. 企业微信API在1分钟内限制请求1000次。
                3. 将上次发起时间与现在时间相减,如果没有超过7200s就将之前存入的token返回
                4. 如果超过7200s则会发起新的请求,重新获取token
                5. 最后返回请求到的token
            注:在正常情况下,每次发送消息都会发起两次请求,获取token和发送消息到微信,所以此函数减少了获取token的频率。
        """
    
    
        def get_token(self):
            # 获取token的url
            url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={}&corpsecret={}".format(self.corpid,self.corpsecret)
            # 发送get请求,并获取返回的内容
            token = requests.get(url).text
            # 将返回的内容(json)转为python字典格式,并获取token
            self.token = json.loads(token)['access_token']
            # 将获取到的token写入到本地文件
            with open(self.tkpath,'w+') as f:
                f.write(str(self.token))
            # 将当前时间的时间戳写入文件,以便下次计算过期时间
            with open(self.tktime,'w+') as f:
                f.write(str(time.time()))
            # 最后返回获取到的token
            return self.token
    
        def msg_send(self,content):
            # 发送消息的url
            url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={}".format(self.token)
            # 要发送的表单(需转换成json格式)
            data = {
                "touser": "|".join(self.touser),
                "toparty": self.toparty,
                "msgtype": "text",
                "agentid": self.agentid,
                "text": {
                    "content": content
                },
                "safe": 0
            }
    
            # 将python字典转化为json并指定编码utf-8(默认使用ascii编码)python3会出现编码问题,将#.encode('utf-8')的#注释删除掉即可。
            data_json = json.dumps(data, ensure_ascii=False)#.encode('utf-8')
            # 发送post请求,并发送表单,
            response = requests.post(url, data=data_json).text
            # 将返回的内容(json)转为python字典格式
            ss = json.loads(response)
            # 如果返回值不正确就打印发送失败,否则返回请求到的内容
            if ss['errcode'] != 0 and ss['errmsg'] != "ok":
                return "出现错误..."
            else:
                return response # 返回请求到的结果
    
    
    if __name__ == '__main__':
        # ======================用户配置信息区域==================================
        # token过期时间(过期后发起新的token请求)
        overdue = 7200
        # token保存的路径(详见read_token方法描述)
        tkpath = '/tmp/token'
        # 记录token过期时间的路径(详见read_token方法描述)
        tktime = '/tmp/tokentime'
        # 消息的接收者,"@all"表示向关注该企业应用的全部成员发送,多个用户逗号分隔
        # 注意:接收者必须在企业微信自建应用的可见范围内。否则消息接收不到!!!
        touser = ("LiuTao",)
        # 部门ID列表,"@all"表示所有部门,多个部门|分隔,例如:1|2|3|4
        toparty = 2
        # 企业自建应用的ID(在zabbix中配置并传递过来)
        agentid = sys.argv[1]
        # 企业ID
        corpid = "aabbccdd0011223344"
        # 自建应用的密钥
        corpsecret = "AAAABBBB11112222ccccddddd_eeeeffff000011111"
        # 要发送的内容
        # sys.argv[1]是zabbix传来的应用ID
        # sys.argv[2]是zabbix传来的标题
        # sys.argv[3]是zabbix传来的内容
        # 若想修改为指定内容,修改content变量值即可
        content = sys.argv[2] + '\n' + sys.argv[3]
        #======================================================================
    
        # 实例化微信类
        w = Wechat(
            overdue=overdue,
            tkpath=tkpath,
            tktime=tktime,
            touser=touser,
            toparty=toparty,
            corpid=corpid,
            corpsecret=corpsecret,
            agentid=agentid,
            content=content
        )
        # 调用微信实例中的发送消息方法
        #print(w.msg_send(content)) #调试,查看响应信息
        w.msg_send(content)
  • 测试脚本,如果企业微信能收到信息则表示脚本正常

    1
    
    /usr/lib/zabbix/alertscripts/wechat.py 100002 test_subject test_content

配置 zabbix

  • 浏览器登陆 zabbix
  • 单击”管理”-“报警媒介类型”-“创建媒体类型”,输入如下信息
    • 名称: 企业微信
    • 类型: 脚本
    • 脚本名称: wechat.py
    • 脚本参数:
      • {ALERT.SENDTO}
      • {ALERT.SUBJECT}
      • {ALERT.MESSAGE}
    • 其它默认,单击”添加”
  • 单击”管理”-“用户”-“Admin”-“报警媒介”-“添加”,输入如下信息
    • 类型: 企业微信
    • 收件人: 1000002
    • 其它默认,单击”添加”
  • 单击”配置”-“动作”-“Report problems to Zabbix administrators”
    • 在”动作”标签页下,选中”已启用”
    • 在”操作”标签页下,输入如下信息
      • 默认标题:

        1
        
        XXXX系统 {HOST.NAME} 故障: {TRIGGER.NAME}
      • 消息内容:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        
        服务器: {HOST.NAME}
        故障时间: {EVENT.DATE} {EVENT.TIME}
        故障名称: {TRIGGER.NAME}
        故障状态: {TRIGGER.STATUS}
        故障等级: {TRIGGER.SEVERITY}
        故障编号: ID: {EVENT.ID}
        监控项: {ITEM.NAME1} ({HOST.NAME1}:{ITEM.KEY1})
        监控值:
        {ITEM.VALUE1}
      • 单击”操作”框中的”编辑”,打开”操作细节”框,输入如下信息

        • 操作类型: 发送消息
        • 发送到用户: “添加” Admin 用户
        • 仅送到: 企业微信
        • 其他默认,单击”更新”
    • 在”恢复操作”标签页下,输入如下信息
      • 默认标题:

        1
        
        XXXX系统 {HOST.NAME} 恢复: {TRIGGER.NAME}
      • 消息内容:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        
        服务器: {HOST.NAME}
        恢复时间: {EVENT.DATE} {EVENT.TIME}
        故障名称: {TRIGGER.NAME}
        故障状态: {TRIGGER.STATUS}
        故障等级: {TRIGGER.SEVERITY}
        故障编号: ID: {EVENT.ID}
        监控项: {ITEM.NAME1} ({HOST.NAME1}:{ITEM.KEY1})
        监控值:
        {ITEM.VALUE1}
      • 单击”操作”框中的步骤1的”编辑”,打开”操作细节”框,输入如下信息

        • 操作类型: 发送消息
        • 发送到用户: “添加” Admin 用户
        • 仅送到: 企业微信
        • 其他默认,单击”更新”
    • 忽略”更新操作”
    • 其他默认,单击”更新”

测试

  • 触发器被触发后,刘涛和运维部成员的企业微信收到告警信息

参考